工业领域-双相机图像拼接opencv

一、应用背景

工业场景下,往往会有两相机重叠区域很小,但需要拼接两张图后再做图像处理的操作(或对相机下的物体进行测量操作),这时需要借助标定板建立世界坐标系,得出两相机之间的转换关系,做拼接。

二、操作步骤如下

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;
}

四、总结

相机应该需要先做畸变矫正
选取点应该均匀分布
图像融合部分应该可以再优化

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值