双目摄像头基于SGBM算法的3d重建+立体标定+相机内外参获取

这是在下用的摄像头,还算便宜,如果是无畸变的摄像头可以直接跳过立体标定。也可以直接用两个相同的USB单目摄像头,不过进行立体标定的过程可能有点麻烦。

下面在下介绍在下实现3d重建的整个步骤。

1.先获取摄像头内参,外参

2.进行双目摄像头立体标定

3.进行立体匹配获得视差图(SGBM)

4.根据Z=b*f/d得到深度图

5.根据深度图绘制点云图

下面,在下按照各个步骤给大家进行讲解:

1.先获取摄像头内参,外参

 https://blog.csdn.net/u012319493/article/details/77622053

获得以下矩阵

Mat M1 = Mat::zeros(3,3,CV_64F);//左相机内参矩阵
Mat M2 = Mat::zeros(3,3,CV_64F);//右相机内参矩阵
Mat D1 = Mat::zeros(1,14,CV_64F);//左相机畸变系数向量
Mat D2 = Mat::zeros(1,14,CV_64F);//右相机畸变系数向量
Mat R = Mat::zeros(3,3,CV_64F);//两相机相对旋转矩阵
Mat T = Mat::zeros(3,1,CV_64F);//相对平移矩阵
Mat R1 = Mat::zeros(3,3,CV_64F);//第一个摄像机的校正变换矩阵(旋转变换)
Mat R2 = Mat::zeros(3,3,CV_64F);//第二个摄像机的校正变换矩阵(旋转变换)
Mat P1 = Mat::zeros(3,4,CV_64F);//第一个摄像机在新坐标系下的投影矩阵
Mat P2 = Mat::zeros(3,4,CV_64F);//第二个摄像机在新坐标系下的投影矩阵
Mat Q = Mat::zeros(4,4,CV_64F);//深度差异映射矩阵

2.进行双目摄像头立体标定

https://blog.csdn.net/qq_36537774/article/details/85005552

https://blog.csdn.net/qq_22424571/article/details/80836342

https://blog.csdn.net/u014652390/article/details/71169927

获得映射rmap 
initUndistortRectifyMap(M1, D1, R1, P1, imageSize, CV_16SC2, rmap[0][0], rmap[0][1]);
initUndistortRectifyMap(M2, D2, R2, P2, imageSize, CV_16SC2, rmap[1][0], rmap[1][1]);

进行畸变校正

remap(Img_left, Img_left_out, rmap[0][0], rmap[0][1], CV_INTER_LINEAR);
remap(Img_right, Img_right_out, rmap[1][0], rmap[1][1], CV_INTER_LINEAR);

查看校正的结果

看绿线处的特征是否对齐

获得校正之后的图

3.进行立体匹配获得视差图(SGBM)

4.根据Z=b*f/d得到深度图

https://www.cnblogs.com/riddick/p/8486223.html   //这篇博客很有参考价值,在下大致按照里面的步骤做的

https://www.cnblogs.com/riddick/p/8318997.html

https://blog.csdn.net/wwp2016/article/details/86080722

获得视差图,深度图,进行空洞填充。(第一篇博客里面有代码)

在下在实践的过程中获得一个经验,最好用右图减左图来获取视差图,这样效果更好一些。(不知为何)

sgbm->compute(imgR, imgL, disp);

不过通过以上设定生成的视差图与sgbm->compute(imgL, imgR, disp);生成的视差图是互补的,也就是说视差越大像素值越小,

所以要进行一个求补的运算,如果你disp是u8类型,像素值=255-像素值,u16类型,像素值=65535-像素值,你可以用pic.type()查看图像像素点数据类型。

建一个Trackbar用来调节SGBM的各个参数,以让视差图获得最好的效果。什么是最好的效果,图像平滑,杂点少黑洞小。

用来生成视差图的图像纹理要多。

 

深度=基线×焦距/视差(至于SGBM生成的视差图单位是什么,在下心中有一个大大的问号)

在下生成的视差图和深度图效果

 上面的视差图是求补运算前的图,所以越远的地方越亮,生成的深度图黑压压一片,啥都看不到,在下专门进行了normalize()归一化让特征显示的明显一点

5.根据深度图绘制点云图

 下面是最精彩的表演,生成点云图

在下用的是pcl库

​

void draw_pcl()
{
  Eigen::Isometry3d pose = Eigen::Isometry3d::Identity();
  pose.pretranslate( Eigen::Vector3d( 0, 0, 0 ) );
    
  double cx = M1.at<double>(0,2);
  double cy = M1.at<double>(1,2);
  double fx = M1.at<double>(0,0);
  double fy = M1.at<double>(1,1);
  double depthScale = 1.0;//不确定
  
  cout<<"将图像装换为点云"<<endl;
  typedef pcl::PointXYZRGB PointT;
  typedef pcl::PointCloud<PointT> PointCloud;
  
  PointCloud::Ptr pointCloud( new PointCloud );

    cout<<"转换图像中:"<<endl;
    cv::Mat color = img_right;
    cv::Mat depth = img_right_depth;
    Eigen::Isometry3d T = pose;
    for( int v=0; v<color.rows; v++ )
      for( int u=0; u<color.cols; u++ )
      {
	unsigned int d = depth.ptr<unsigned short> ( v )[u];//<unsigned short>
	if( d==0 ) continue;
        if(d>=500) continue; //把远处的噪点截掉
	Eigen::Vector3d point;
	point[2] = double(d)/depthScale;
	point[0] = (u-cx)*point[2]/fx;
	point[1] = (v-cy)*point[2]/fy;
	Eigen::Vector3d pointWorld = T*point;
	
	PointT p;
	p.x = pointWorld[0];
	p.y = pointWorld[1];
	p.z = pointWorld[2];
	p.b = color.data[ v*color.step+u*color.channels() ];
	p.g = color.data[ v*color.step+u*color.channels()+1 ];
	p.r = color.data[ v*color.step+u*color.channels()+2 ];
	pointCloud->points.push_back( p );
      }
  
  
  pointCloud->is_dense = false;
  cout<<"点云共有"<<pointCloud->size()<<"个点。"<<endl;
  pcl::io::savePCDFileBinary( "map.pcd", *pointCloud );  


  system("pcl_viewer map.pcd");
  
/*
  pcl::visualization::CloudViewer viewer("Cloud_Viewer");
  viewer.showCloud(pointCloud);
  while (!viewer.wasStopped()) 
   { ; }
*/
}

[Click and drag to move]
​

把rgb图的像素和深度图的像素转换为世界坐标系的一个点

 

天花板投影仪隐约可见

 

 

效果还不是很好,用更高分辨率的摄像头和更优秀的立体匹配算法应该可以获得更准确的深度图,再加上滤波算法。先告一段落,在下日后再尝试。大家有什么更好的双目实现办法可以告诉在下,多谢。

  • 6
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 双目相机是利用两个摄像头分别拍摄同一场景,从而获取不同视角下的图像信息,以实现深度信息的获取。三维重建是指通过图像处理技术将拍摄得到的二维图像转化为三维模型的过程。 在实现双目相机三维重建的过程中,可以使用OpenCV和PCL这两个开源库。OpenCV是一款计算机视觉库,提供了许多图像处理和计算机视觉相关的函数和工具,比如图像读取和处理、特征提取和匹配等。PCL是一款点云处理库,能够处理三维点云数据,提供了点云滤波、分割、配准和特征提取等功能。 具体步骤如下: 1. 获取双目相机的图像,进行标定标定可以校准摄像头对应的内矩阵和外矩阵,以保证匹配时的准确度。 2. 通过绝对/相对模板匹配获取左右匹配的特征点。之后可以使用立体匹配算法(例如SGBM算法)计算出匹配点的视差(即左右视图在深度方向上的偏差),根据视差反向计算出点的深度。 3. 将获取的深度点云数据使用PCL进行处理,如点云滤波、重采样、分割等。之后可以使用PCL提供的立体配准算法对左右图像进行配准,基于此获取的点云数据中的关键点,进行特征点匹配,从而实现三维重建。 总之,双目相机三维重建opencv-pcl结合使用能够高效地完成三维重建任务,这是一个较为复杂的过程,需要仔细设计,注意数设置和优化算法。 ### 回答2: 双目相机三维重建是利用双目相机获取的两幅图像,通过计算机视觉算法相机观察到的场景进行三维重建的技术。OpenCV是一种开源的计算机视觉库,提供了许多图像处理和计算机视觉算法,PCL(PointCloud Library)则是一种开源的点云处理库,提供了各种点云相关的处理算法。 通过结合OpenCV和PCL,我们可以实现双目相机的三维重建。首先,需要利用OpenCV对双目相机获取的两幅图像进行立体匹配,得到两幅图像中对应像素点的视差。然后,通过视差计算相机与场景物体之间的距离信息,并将其转化为点云数据。最后,利用PCL对点云数据进行处理,实现三维重建。 具体的步骤包括: 1.读取左右相机的图像并进行预处理,包括图像去畸变和校正,以及调整图像的大小和尺度等。 2.使用OpenCV的立体匹配算法对左右相机图像进行匹配,得到像素点的视差图像。 3.通过三角化算法将视差信息转化为深度信息,并将深度信息转换为点云数据。 4.利用PCL对点云数据进行后续处理,包括点云滤波、点云重建和点云配准等。 5.最终得到的结果是场景的三维模型,可以对其进行渲染和可视化等操作。 总之,双目相机的三维重建是一项复杂的技术,在实践过程中需要综合运用计算机视觉、图像处理和点云处理等多个领域的知识和算法,但是对于建模、制造等领域来说,这是一项非常重要的技术。 ### 回答3: 双目相机三维重建是一种利用双目相机获取的视差数据来进行三维物体建模的技术。这种技术可以被应用到多个领域,如机器人导航、自动驾驶、医疗影像等。OpenCV是一个强大的计算机视觉库,支持多种计算机视觉算法和工具,能够方便地进行图像处理、特征提取和目标跟踪。而PCL是点云库,提供了处理点云数据的算法、工具和可视化功能。 实现双目相机三维重建,需要使用OpenCV和PCL。首先,利用双目相机捕获的两幅图像计算出视差图。然后,使用OpenCV提供的函数或者自定义算法,将视差图转换为深度图。接着,利用PCL提供的点云算法,将深度图转换为点云数据。最后,利用PCL的可视化工具,对点云数据进行可视化展示或二次处理。 在使用OpenCV和PCL进行双目相机三维重建时,需要注意几个关键点。首先,在捕获图像前需要进行相机标定获取相机和外数。这是很重要的,因为只有相机准确校准后,才能保证三维建模的精度和稳定性。其次,在计算视差图和深度图时,需要选择适合的计算方法和数。这些数可能会受到图像分辨率、灰度分布和光照等因素的影响。最后,在进行点云处理和可视化时,需要选择合适的算法和工具,以免因数据量过大或算法不精确而影响计算效率和准确性。 总之,双目相机三维重建结合OpenCV和PCL,是一种强大的三维重建技术。它可以应用到多个领域,包括机器人导航、自动驾驶、医疗影像等。在实现过程中,需要根据具体实际情况进行合理选择和优化,以保证算法的精度、效率和稳定性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值