OpenCV在未知相机内参数情况下的立体图像矫正方法及注意事项

很多时候我们不知道摄像机的内参数矩阵,并且我们也不太关注内参数到底是多少,因为我们仅仅关心如何得到两幅图像的稠密匹配,或者两幅图像的差别——例如我们只想计算两幅图像的视差图,或者说得到两幅立体图像对的深度图就足够了。既然不知道摄像机的内参数,那么就只能借助对极约束来达到目的了。通过计算两幅图像的基础矩阵F,然后利用对极约束矫正极线为平行线的方法,可以很好的实现这个目标,该方法也被称为Hartly方法,在OpenCV中由cv::stereoRectifyUncalibrated函数实现。

    立体图像的极线矫正需要三个步骤:

(1)提取特征点并匹配,参考http://blog.sina.com.cn/s/blog_4298002e01013w4z.html

(2)计算基本矩阵F,参考http://blog.sina.com.cn/s/blog_4298002e01013w9a.html

(3)极线矫正。

    Hartly方法的函数原型如下:

//! computes the rectification transformation for an uncalibrated stereo camera (zero distortion is assumed)
CV_EXPORTS_W bool stereoRectifyUncalibrated( const Mat& points1, const Mat& points2,
                                             const Mat& F, Size imgSize,
                                             CV_OUT Mat& H1, CV_OUT Mat& H2,
                                             double threshold=5 );

该函数输入参数为两幅图像的匹配特征点,基本矩阵F以及图像的尺寸,返回的参数是两幅图像各自对应的单应变换矩阵H1和H2。只需要对两幅图像按照H1和H2做单应变换,即可得到矫正后图像。假设I为图像,变换如下:

I_recty = H*I

 

    需要说明一点,该函数的前两个参数Mat& points1, Mat& points2与cv::findFundamentalMat的前两个参数并不是相同的数据结构。它们虽然可以是同一个匹配点集,但是他们的数据结构是完全不同的!cv::findFundamentalMat中传入的匹配点集要求是2xN或者Nx2的矩阵,但是cv::stereoRectifyUncalibrated中要求传入的匹配点集必须是1x2N或者2Nx1的矩阵!在很多文档中都说他们的参数是一样的,这其实是一个天大的错误,如果用计算F的匹配点集直接传给图像矫正函数,程序将直接崩溃。正确的做法是利用cv::Mat的构造函数,直接从vector<Point2f>构造一个cv::Mat传入。

    cv::stereoRectifyUncalibrated函数默认原始图像是没有径向畸变的,因此在矫正图像之前,最好先对原始图像做径向矫正。

    另外需要注意的一点,函数返回的单应变换矩阵H1和H2都是double类型,也即CV_64F类型,若不是该类型的矩阵,与之相乘会报错。下面是示例代码:

 

// 假设前面我们已经得到两幅图像的匹配特征点,并计算出了基本矩阵F,同时得到了匹配特征点的inlier

// Mat m_matLeftImage;
// Mat m_matRightImage;

// vector<Point2f> m_LeftInlier;
// vector<Point2f> m_RightInlier;

// Mat m_Fundamental;

 

// 计算图像矫正的单应变换矩阵

Mat m_LeftH;
Mat m_RightH;

stereoRectifyUncalibrated(Mat(m_LeftInlier), Mat(m_RightInlier), m_Fundamental,
                          Size(m_matLeftImage.cols, m_matLeftImage.rows),
                          m_LeftH, m_RightH);

 

// 任意指定一个内参数矩阵K,不会影响计算结果,此处设为单位阵。

Mat K = Mat::eye(3, 3, CV_64F); // 注意一定是double类型
Mat invK = K.inv(DECOMP_SVD);
Mat LeftR = invK*m_LeftH*K;     // 根据单应变换矩阵计算左图摄像机在空间中的变换矩阵R1
Mat RightR = invK*m_RightH*K;   // 计算右图摄像机在空间中的变换矩阵R2
Mat LeftMap1, LeftMap2;
Mat RightMap1, RightMap2;

Mat Distort;                    // 径向畸变为0,设为空矩阵
Size UndistSize(m_matLeftImage.cols, m_matLeftImage.rows);

 

// 计算左右两幅图像的映射矩阵

initUndistortRectifyMap(K, Distort, LeftR, K, UndistSize, CV_32FC1, LeftMap1, LeftMap2);
initUndistortRectifyMap(K, Distort, RightR, K, UndistSize, CV_32FC1, RightMap1, RightMap2);

 

// 把原始图像投影到新图像上,得到矫正图像

Mat m_LeftRectyImage;
Mat m_RightRectyImage;

remap(m_matLeftImage, m_LeftRectyImage, LeftMap1, LeftMap2, INTER_LINEAR);
remap(m_matRightImage, m_RightRectyImage, RightMap1, RightMap2, INTER_LINEAR);

 

// 显示结果

cvNamedWindow( "left image", 1);
cvShowImage("left image", &(IplImage(m_LeftRectyImage)));
cvNamedWindow( "right image", 1);
cvShowImage("right image", &(IplImage(m_RightRectyImage)));
cvWaitKey( 0 );
cvDestroyWindow( "left image" );
cvDestroyWindow( "right image" );

 

程序计算的结果如下图所示:

原始图像对:

OpenCV在未知相机内参数情况下的立体图像矫正方法及注意事项

极线矫正后的图像:
OpenCV在未知相机内参数情况下的立体图像矫正方法及注意事项

    得到上面的矫正图像之后,就可以计算视差或者进行稠密匹配了。下面以视差计算的应用为例,分别用GC和SGBM算法计算视差,结果如下图:

 

SGBM算法:

OpenCV在未知相机内参数情况下的立体图像矫正方法及注意事项

GC算法:
OpenCV在未知相机内参数情况下的立体图像矫正方法及注意事项

from: http://blog.sina.com.cn/s/blog_4298002e01013yb8.html


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
OpenCV中,可以使用双目立体视觉技术对图像进行深度估计,但是在进行深度估计之前,需要对双目相机进行矫正,以确保左右相机图像具有相同的几何形状和位置关系。以下是基本的双目相机矫正步骤: 1. 执行相机标定,获取相机的内部参数和外部参数。 2. 使用标定结果计算左右相机之间的基础矩阵极线约束。 3. 计算视差图,以获取深度信息。 4. 可选的步骤,进行后处理,例如图像去噪、插值、滤波等。 下面是基本的OpenCV代码示例,用于执行双目相机矫正: ```python # 标定相机,获取相机参数和外参数(略) # 计算左右相机之间的基础矩阵极线约束 F, mask = cv2.findFundamentalMat(pts_left, pts_right, cv2.FM_RANSAC) # 计算左右相机的校正映射 R_left, R_right, P_left, P_right, Q, _, _ = cv2.stereoRectify(cameraMatrix1=mtx_left, distCoeffs1=dist_left, cameraMatrix2=mtx_right, distCoeffs2=dist_right, imageSize=image_size, R=R, T=T) # 计算左右相机的映射矩阵 map_left_x, map_left_y = cv2.initUndistortRectifyMap(mtx_left, dist_left, R_left, P_left, image_size, cv2.CV_32FC1) map_right_x, map_right_y = cv2.initUndistortRectifyMap(mtx_right, dist_right, R_right, P_right, image_size, cv2.CV_32FC1) # 校正左右相机图像 rectified_left = cv2.remap(img_left, map_left_x, map_left_y, cv2.INTER_LINEAR) rectified_right = cv2.remap(img_right, map_right_x, map_right_y, cv2.INTER_LINEAR) # 计算视差图 stereo = cv2.StereoSGBM_create(minDisparity=0, numDisparities=16*5, blockSize=5, P1=8*3*5**2, P2=32*3*5**2, disp12MaxDiff=1, uniquenessRatio=10, speckleWindowSize=100, speckleRange=32) disparity = stereo.compute(rectified_left, rectified_right) # 可选的后处理步骤,例如视差图滤波、插值、去噪等 ``` 其中,`mtx_left`、`dist_left`、`mtx_right`、`dist_right`分别是左右相机的内部参数和畸变系数,`img_left`、`img_right`分别是左右相机图像,`pts_left`、`pts_right`是左右相机中提取的匹配点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值