一、双目立体标定
使用stereoCalibrate()进行标定,生成第一个相机点转换为第二个相机点的旋转矩阵R和平移向量T。(这里和Halcon的相反,halcon是第二相机点转换到第一相机点)
二、双目极线校正
1.使用stereoRectify()计算两个相机的极线校正矩阵(Bouguet法)。
void cv::stereoRectify (
InputArray cameraMatrix1, //输入第一个相机的内参矩阵
InputArray distCoeffs1, //输入第一个相机的畸变系数
InputArray cameraMatrix2, //输入第二个相机的内参矩阵
InputArray distCoeffs2, //输入第二个相机的畸变系数
Size imageSize, //输入图像的尺寸大小
InputArray R, //输入stereoCalibrate()生成的双目标定旋转矩阵
InputArray T, //输入stereoCalibrate()生成的双目标定平移向量
OutputArray R1, //输出第一个相机的坐标系校正旋转矩阵
OutputArray R2, //输出第二个相机的坐标系校正旋转矩阵
OutputArray P1, //输出第一个相机校正后的新投影矩阵(相机坐标系点投影到图像坐标系点)
OutputArray P2, //输出第二个相机校正后的新投影矩阵(相机坐标系点投影到图像坐标系点)
OutputArray Q, //输出通过视差图计算三维点的转换矩阵
int flags = CALIB_ZERO_DISPARITY,
double alpha = -1,
Size newImageSize = Size(),
Rect * validPixROI1 = 0,
Rect * validPixROI2 = 0 )
2.使用initUndistortRectifyMap()计算畸变矫正和校正变换映射。
在OpenCV中可以通过initUndistortRectifyMap()函数获得原始图像和矫正+校正图像之间的映射表。
3.使用remap()函数根据映射表对整个图像进行映射处理实现去畸变及极线校正。
注:stereoRectify()是需要标定参数,stereoRectifyUncalibrated()(Hartley法)不用标定内参参数需要基础矩阵F,stereoRectify()的精度会高一些。
可通过initInverseRectificationMap() 计算极线校正后图像转换为极线校正前图像,用于投影仪的逆相机变换。
Computes the projection and inverse-rectification transformation map. In essense, this is the inverse of initUndistortRectifyMap to accomodate stereo-rectification of projectors (‘inverse-cameras’) in projector-camera pairs.
三、寻找同名点
opencv有对应的函数这里不展开描述。
1、局部匹配
2、半全局匹配
3、全局匹配
四、计算三维点
使用reprojectImageTo3D()通过视差图计算三维点,计算的三维点的坐标系是校正后的第一个相机坐标系的。
void cv::reprojectImageTo3D(
InputArray disparity, //输入视差图
OutputArray _3dImage, //输出三维点图,生成的点是在第一个相机校正后的坐标系下的点
InputArray Q, //输入极线校正生成的Q矩阵
bool handleMissingValues = false,
int ddepth = -1 )
注意实际计算并非像官方给出的直接左乘Q这么简单,实际代码是左乘Q后,还要除以左乘Q结果的第四项。
//opencv源码计算三维点部分核心代码
for( x = 0; x < cols; x++)
{
double d = sptr[x];
Vec4d homg_pt = _Q*Vec4d(x, y, d, 1.0);
dptr[x] = Vec3d(homg_pt.val);
dptr[x] /= homg_pt[3];
if( fabs(d-minDisparity) <= FLT_EPSILON )
dptr[x][2] = bigZ;
}
三维空间点 P 在相机的成像图如下图所示。由图可以看出,根据相似三角形原理, 有以下关系:
这里x和y是像素坐标,x0和y0是图像坐标系转像素坐标系的原点差(是图像x和y的一半,也就是Cx和Cy)。
(x-x0)和(y-y0)就是将像素坐标转换为图像坐标的过程。
因此,当已知三维空间上任意一点的在不同图像上的视差,再根据相机的参数,就可以知道该点在相机坐标系的三维坐标。
五、转换为原主相机坐标系(可选,用于手眼标定等)
使用极线校正生成第一个相机坐标系校正矩阵R的逆矩阵转换为原第一个相机坐标系。
机械手基坐标系下的点 = 手眼标定转换矩阵 * R的逆矩阵 * 三维点,这里将R的逆矩阵转换为齐次坐标后左乘手眼标定转换矩阵,得到最终转换矩阵。
或者
使用极线校正后的图像进行手眼标定。
整体代码后续择机补充!
参考:
https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html#ga1bc1152bd57d63bc524204f21fde6e02
https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html#ga617b1685d4059c6040827800e72ad2b6
双目相机标定以及立体测距原理及OpenCV实现(上)https://zhuanlan.zhihu.com/p/561399264
双目视觉:reprojectImageTo3D函数https://blog.youkuaiyun.com/qq_49110168/article/details/144836805