新型小型工程
机械intelrealsense系列中D435深度相机获取较为优质的场景数据,其中涉及内容:数。。。
接触D435深度相机将近两个⽉了,这⾥总结⼀下这段时间的使⽤过程中,碰到的问题以及相关的解决⽅法。
所使⽤的配置环境如下:
win10+VS2017+PCL1.9.0+OpenCV4.1.0
在使⽤相机之前,⾸先要下载相机⼚商提供的官⽅SDK⽂件,进⾏学习和使⽤以及查阅⼀些基本的环境配置问题。这⾥可以参考之前写过的⽂章。
链接如下:
⾥⾯有相关内容的介绍这⾥就不多赘述。
对于使⽤的相机,尤其是深度相机,会很看重各种数据流的融合以及数据精度。深度图像获取过程很容
易收到外部环境已经相机⾃⾝因素的影响。⽐如
设备精度、操作者经验、环境因素等带来的影响,以及电磁波衍射特性、被测物体表⾯性质变化和数据拼接配准操作过程的影响,点云数据中将不可避免地出现⼀些噪声点,属于随机误差。
其实官⽅提供了以下滤波的API供⽤户使⽤,⽐如:时间滤波、空间滤波、孔洞填充等。可以参考之前写过的⽂章。 链接如下:
这⾥提供了⼀份⽂档,主要介绍相关滤波⽅法的原理及使⽤⽅法。
相关代码:
然后,通过获取相机的场景数据,会发现相机的默认坐标系的坐标轴是反着的(相对⽽⾔),但遵循
右⼿定则,为了看着更舒服些,可以对其点数据进⾏处理,使其坐标系与视野更能接近实际(说⽩了就是把点的坐标转换⼀下,看着舒服些)。坐标默认之所以是反着,⽹上有说观点说是为了适应cloudcompare软件初始界⾯使⽤的。
PS:其实上⾯这段的解释并不准确,现做说明和补充,其实相机采集的数据与初始安装状态的场景数据是倒着的,这其实真实的原因是便于相机与机械臂(⼀般这款相机常与机械臂搭配使⽤)进⾏联系,这样能够保证相机获取的数据的坐标系能够与机械臂末端执⾏器默认坐标⼀致,便于进⾏相机与机械臂之间的左边变换(由于旋转分量上坐标⽅向是⼀致的,只变换平移分量的位移量即可),也就是说此处不需要下图所⽰的代码(由于机械臂种类和型号众多,具体还需参考实际机械臂的坐标信息)。
各种数据处理操作结束后,需要⽣成点云数据了,直接上整体的操作代码,按照代码中的注释和单步执⾏,有些代码就容易看懂了,代码量较⼤。
#include<iostream>
#include<algorithm>
#include<boost/date_time/posix_time/posix_time.hpp>
数字家庭影院
#include<boost/thread/thread.hpp>
#include<string>
#include<stdio.h>
#include<tchar.h>
#include<map>
#include<mutex>// std::mutex, std::lock_guard
#include<cmath>// std::ceil
#include<conio.h>
// Intel Realsense Headers 相机头⽂件
#include<librealsense2/rs.hpp>// Include RealSense Cross Platform API
#include"example.hpp"
// PCL Headers PCL头⽂件
#include<pcl/io/pcd_io.h>
#include<pcl/point_types.h>
#include<pcl/filters/passthrough.h>
#include<pcl/common/common_headers.h>
#include<pcl/features/normal_3d.h>
#include<pcl/visualization/pcl_visualizer.h>
#include<pcl/console/parse.h>
#include<boost/thread/thread.hpp>
#include<pcl/io/io.h>
#include<pcl/visualization/cloud_viewer.h>
#include<iostream>
#include<pcl/io/pcd_io.h>
#include<pcl/io/ply_io.h>
#include<pcl/point_types.h>
#include<pcl/common/io.h>
#include<pcl/impl/point_types.hpp>
#include<pcl/point_cloud.h>
// Include OpenCV API OpenCV头⽂件
#include<opencv2/opencv.hpp>
#include"cv-helpers.hpp"
using namespace std;//定义命名空间
using namespace cv;
//获取深度像素对应长度单位转换
float get_depth_scale(rs2::device dev);
//检查摄像头数据管道设置是否改变
bool profile_changed(const std::vector<rs2::stream_profile>& current,const std::vector<rs2::stream_profile>& prev);
typedef pcl::PointXYZRGB RGB_Cloud;//定义点云类型
typedef pcl::PointCloud<RGB_Cloud> point_cloud;
typedef point_cloud::Ptr cloud_pointer;
typedef point_cloud::Ptr prevCloud;
// Prototypes 原型
void Load_PCDFile(void);
bool userInput(void);
void cloudViewer(void);
// Global Variables 全局变量
string cloudFile;// .pcd file name
string prevCloudFile;// .pcd file name (Old cloud)
int i =1;// Index for incremental file name 增量⽂件名的索引
//boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer1(new pcl::visualization::PCLVisualizer("3D Viewer"));全局共享指针//boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer2(new pcl::visualization::PCLVisualizer("3D Viewer2"));
//boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer3(new pcl::visualization::PCLVisualizer("Captured Frame"));
声明
//std::tuple<int, int, int> RGB_Texture(rs2::video_frame texture, rs2::texture_coordinate Texture_XY);
//cloud_pointer PCL_Conversion(const rs2::points& points, const rs2::video_frame& color);
//boost::shared_ptr<pcl::visualization::PCLVisualizer> rgbVis(pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr cloud);
const std::string no_camera_message ="No camera connected, please connect 1 or more";
const std::string platform_camera_name ="Platform Camera";
//设备容器
class device_container
{
// Helper struct per pipeline
struct view_port
{
std::map<int, rs2::frame> frames_per_stream;
rs2::colorizer colorize_frame;
texture tex;
rs2::pipeline pipe;
rs2::pipeline_profile profile;
};
光纤切割刀片public:
void enable_device(rs2::device dev)
{
std::string serial__info(RS2_CAMERA_INFO_SERIAL_NUMBER)); std::lock_guard<std::mutex>lock(_mutex);
if(_devices.find(serial_number)!= _d())
{
return;//already in
}
// Ignoring platform cameras (webcams, etc..)
if(platform_camera_name == _info(RS2_CAMERA_INFO_NAME))
{
return;
}
// Create a pipeline from the given device
rs2::pipeline p;
rs2::config cfg;
//able_stream(RS2_STREAM_COLOR, 1280, 720, RS2_FORMAT_BGR8, 30); //able_stream(RS2_STREAM_INFRARED, 1280, 720, RS2_FORMAT_Y8, 30); //able_stream(RS2_STREAM_DEPTH, 1280, 720, RS2_FORMAT_Z16, 30);
// Start the pipeline with the configuration
rs2::pipeline_profile profile = p.start(cfg);
// Hold it internally
_place(serial_number, view_port{{},{},{}, p, profile });
}
void remove_devices(const rs2::event_information& info)
{
小区自动售水机
std::lock_guard<std::mutex>lock(_mutex);
// Go over the list of devices and check if it was disconnected
auto itr = _devices.begin();
while(itr != _d())
{
if(info.was_removed(itr->_device()))
{
法兰锻造
itr = _ase(itr);
}
else
{
++itr;
}
}
}
size_t device_count()
{
std::lock_guard<std::mutex>lock(_mutex);
return _devices.size();
}
int stream_count()
{
std::lock_guard<std::mutex>lock(_mutex);tpe薄膜
int count =0;
for(auto&& sn_to_dev : _devices)
{
for(auto&& stream : sn_to_dev.second.frames_per_stream)
{
if(stream.second)
{
count++;
}
}
}
return count;
}
void poll_frames()
{
std::lock_guard<std::mutex>lock(_mutex);
// Go over all device
for(auto&& view : _devices)
{
/
/ Ask each pipeline if there are new frames available
rs2::frameset frameset;
if(view.second.pipe.poll_for_frames(&frameset))
{
for(int i =0; i < frameset.size(); i++)
{
rs2::frame new_frame = frameset[i];
int stream_id = _profile().unique_id();
//view.second.frames_per_stream[stream_id] = lorize_frame.process(new_frame); //update view port with the new stream view.second.frames_per_stream[stream_id]= new_frame;不将深度图彩⾊化
}
}
}
}
void render_textures()
{
std::lock_guard<std::mutex>lock(_mutex);
int stream_num =0;
rs2::colorizer color_map;
for(auto&& view : _devices)
{
// For each device get its frames
for(auto&& id_to_frame : view.second.frames_per_stream)
{
if(rs2::video_frame vid_frame = id_to_frame.second.as<rs2::video_frame>())
{
auto format = _profile().format();
auto w = _width();
auto h = _height();
if(format == RS2_FORMAT_BGR8)彩⾊图
{
auto colorMat =Mat(Size(w, h), CV_8UC3,(void*)_data(), Mat::AUTO_STEP);
imshow("color1_"+to_string(stream_num), colorMat);
}
else if(format == RS2_FORMAT_RGB8)
{
auto colorMat =Mat(Size(w, h), CV_8UC3,(void*)_data(), Mat::AUTO_STEP);
cvtColor(colorMat, colorMat, COLOR_RGB2BGR);
imshow("color2_"+to_string(stream_num), colorMat);
}
else if(format == RS2_FORMAT_Z16)
{
auto depth = vid_frame.apply_filter(color_map);
auto colorMat =Mat(Size(w, h), CV_8UC3,(void*)_data(), Mat::AUTO_STEP);
imshow("color_depth_"+to_string(stream_num), colorMat);
//auto depthMat = Mat(Size(w, h), CV_16UC1, (void*)_data(), Mat::AUTO_STEP);
}
waitKey(1);
}
stream_num++;
}
}
}
void pointcloud_process(){
std::lock_guard<std::mutex>lock(_mutex);
int stream_num =0;
rs2::frame color_frame_1, depth_frame_1;
rs2::frame color_frame_1, color_frame_2, depth_frame_1, depth_frame_2;
cloud_pointer cloud1;
cloud_pointer cloud1, cloud2;
for(auto&& view : _devices)遍历每个设备
{
// For each device get its frames
for(auto&& id_to_frame : view.second.frames_per_stream)每个设备⼀个stream⾥有3 帧数据:深度帧,红外帧,彩⾊帧{
if(rs2::video_frame vid_frame = id_to_frame.second.as<rs2::video_frame>())
{
auto format = _profile().format();
auto w = _width();
auto h = _height();
int cur_num = stream_num /3;
只获取深度帧和彩⾊帧
if(format == RS2_FORMAT_BGR8)彩⾊帧
{
if(cur_num ==0)
color_frame_1 = vid_frame;
/*
else
color_frame_2 = vid_frame;
*/
}
else if(format == RS2_FORMAT_Z16)深度帧
{
if(cur_num ==0)
depth_frame_1 = vid_frame;