一、应用背景
工业场景下,往往会有两相机重叠区域很小,但需要拼接两张图后再做图像处理的操作(或对相机下的物体进行测量操作),这时需要借助标定板建立世界坐标系,得出两相机之间的转换关系,做拼接。
二、操作步骤如下
1.硬件准备
拿一块标定板放置在两相机视野之中,成像如下
2.选取世界坐标系的点
以标定板建立世界坐标系,比如左下角圆心为(0,0),第二个圆心为(3,0),分别选取左右相机中的8个圆点(应该是均匀选取越多越好),得到他们的世界坐标和像素坐标(可以通过拟合圆的方式获取)如下:
//预输入参数
vector<cv::Point2f> point_left_pixel, point_left_physics;
point_left_pixel.push_back(Point2f(2286.198, 2577.778));
point_left_pixel.push_back(Point2f(2426.574, 2554));
point_left_pixel.push_back(Point2f(2261.526, 2437.938));
point_left_pixel.push_back(Point2f(2403.213, 2414.513));
point_left_pixel.push_back(Point2f(1959.695, 680.4792));
point_left_pixel.push_back(Point2f(2099.814, 655.9193));
point_left_pixel.push_back(Point2f(1983.792, 819.6689));
point_left_pixel.push_back(Point2f(2124.299, 795.1664));
point_left_physics.push_back(Point2f(0, 9));
point_left_physics.push_back(Point2f(6, 9));
point_left_physics.push_back(Point2f(0, 15));
point_left_physics.push_back(Point2f(6, 15));
point_left_physics.push_back(Point2f(0, 90));
point_left_physics.push_back(Point2f(6, 90));
point_left_physics.push_back(Point2f(0, 84));
point_left_physics.push_back(Point2f(6, 84));
vector<cv::Point2f> point_right_pixel, point_right_physics;
point_right_pixel.push_back(Point2f(2545.076, 1950.228));
point_right_pixel.push_back(Point2f(2686.234, 1926.355));
point_right_pixel.push_back(Point2f(2521.015, 1809.616));
point_right_pixel.push_back(Point2f(2662.064, 1785.171));
point_right_pixel.push_back(Point2f(2214.018, 60.818));
point_right_pixel.push_back(Point2f(2353.586, 36.41));
point_right_pixel.push_back(Point2f(2238.701, 198.28));
point_right_pixel.push_back(Point2f(2378.156, 173.92));
point_right_physics.push_back(Point2f(153, 9));
point_right_physics.push_back(Point2f(159, 9));
point_right_physics.push_back(Point2f(153, 15));
point_right_physics.push_back(Point2f(159, 15));
point_right_physics.push_back(Point2f(153, 90));
point_right_physics.push_back(Point2f(159, 90));
point_right_physics.push_back(Point2f(153, 84));
point_right_physics.push_back(Point2f(159, 84));
3.获得相机与世界坐标的单应性矩阵M
其实只需要获得右相机的放射矩阵就可
//Mat m1 = findHomography(point_left_pixel, point_left_physics, RANSAC); //不需要求
Mat m2 = findHomography(point_right_physics, point_right_pixel, RANSAC);
4.计算左相机的标定板点在右相机中的像素点
将左相机下的8个世界坐标点转换到右相机中的图像坐标点
vector<cv::Point2f> point_left_physics_right_pixel;
perspectiveTransform(point_left_physics, point_left_physics_right_pixel, m2);
5.图像拼接
这时候有了左相机原本的8个像素点,也有了这8个像素点在右相机中的对应点,那么可以按照套路进行拼接
Mat WarpImg, DstImg;
if (!Image_Stitching(image_left, image_right, point_left_pixel, point_left_physics_right_pixel,WarpImg, DstImg))
{
cout << "can not stitching the image!" << endl;
system("pause");
return false;
}
waitKey(0);
destroyAllWindows();
system("pause");
return 0;
6.最终效果图如下
三、图像拼接代码如下
bool Image_Stitching(Mat image_left, Mat image_right, vector<cv::Point2f> Point_left, vector<cv::Point2f> Point_right, Mat& WarpImg, Mat& DstImg)
{
//findHomography计算单应性矩阵至少需要4个点
/*
计算多个二维点对之间的最优单映射变换矩阵H(3x3),使用MSE或RANSAC方法,找到两平面之间的变换矩阵
*/
if (Point_left.size() < 4 || Point_right.size() < 4) return false;
//获取图像right到图像left的投影映射矩阵,尺寸为3*3
//注意顺序,srcPoints对应goodkeypoint_right,dstPoints对应goodkeypoint_left
Mat H = findHomography(Point_right, Point_left, RANSAC);
//对image_right进行透视变换
warpPerspective(image_right, WarpImg, H, Size(image_right.cols + image_left.cols, image_right.rows));
DstImg = WarpImg.clone();
//将image_left拷贝到透视变换后的图片上,完成图像拼接
image_left.copyTo(DstImg(Rect(0, 0, image_left.cols, image_left.rows)));
//透视变换左上角(0,0,1)
Mat V2 = (Mat_<double>(3, 1) << 0.0, 0.0, 1.0);
Mat V1 = H * V2;
Point left_top;
left_top.x = V1.at<double>(0, 0) / V1.at<double>(2, 0);
left_top.y = V1.at<double>(1, 0) / V1.at<double>(2, 0);
if (left_top.x < 0)left_top.x = 0;
//透视变换左下角(0,src.rows,1)
V2 = (Mat_<double>(3, 1) << 0.0, image_left.rows, 1.0);
V1 = H * V2;
Point left_bottom;
left_bottom.x = V1.at<double>(0, 0) / V1.at<double>(2, 0);
left_bottom.y = V1.at<double>(1, 0) / V1.at<double>(2, 0);
if (left_bottom.x < 0)left_bottom.x = 0;
int start_x = min(left_top.x, left_bottom.x);//重合区域起点
int end_x = image_left.cols;//重合区域终点
OptimizeSeam(start_x, end_x, WarpImg, DstImg); //图像融合
imwrite("merge3.bmp", DstImg);
return true;
}
四、总结
相机应该需要先做畸变矫正
选取点应该均匀分布
图像融合部分应该可以再优化