项目实战四 图像拼接

一、简介

图像拼接是我们常用到的一种技术,我个人曾经天真的以为项目中最长用的是用halcon 案例中的那种来拼图,但是真正做项目的时候并不是这样的,这是项目中的一个一个真实案例。

二、项目背景

1、有 上、中、下三张图片,且每张图片的右边是一排标定圆

2、上面图的标定圆能拍到9个圆孔,中间的图片拍到上图的全部和下图的部分保证有重叠的,下图和中图肯定也要有重叠,如下图:

 

 

三、拼图原理

如前面两步所示:

第一步:我们需要找到图片右边的标定圆,找圆的时候,a、先通过blob 分析找出想要的圆孔的轮廓,然后拟合圆,还有一种方法就是计算出圆孔的area_center,然后用二维测量卡尺来拟合圆

* 通过面积来计算半径
Radius:=pow(mean(Area)/rad(180),0.5)

* 创建卡尺的
create_metrology_model (MetrologyHandle)
get_image_size (ImageReduced, Width, Height)
set_metrology_model_image_size (MetrologyHandle, Width, Height)

tuple_gen_const (|Row|, Radius, Radiuses)
add_metrology_object_circle_measure (MetrologyHandle, Row, Column, Radiuses, 5, 10, 1, 30, ['num_measures','measure_transition','measure_select','min_score'], [16,'positive','all',0.1], Index_circle)

apply_metrology_model (ImageReduced, MetrologyHandle)


get_metrology_object_result (MetrologyHandle, Index_circle, 'all', 'result_type', 'all_param', Parameter_circle)

第二步:第一步中我们得到的各个图片的圆孔行列坐标,这一步只要是计算重叠位置的差,分布是上图和中图 的offsetx1 offsety1,以及中图和下图的offsetx2,offsety2 。计算的方式有很多,这里就不说了。

第三步:通过tile_images_offset 算子来拼图

四、显示效果

核心代码:

找圆

    * 得到9个圆的半径和  行列坐标
    Albert_Carib_Circle (ImageResult, ContCircleT, 'TOP', tilParams[6], [tilParams[7],tilParams[9],tilParams[10]], [tilParams[8],1,tilParams[11]], [], ProcessObjOut, ProcessObjOut, RowT, ColumnT)
    SetDictObject (ContCircleT, ProcessObjOut, '上图找圆结果')
    
     * 计算相邻两个圆之间的距离 
    distance_pp (RowT[0:|RowT|-2], ColumnT[0:|RowT|-2], RowT[1:|RowT|-1], ColumnT[1:|RowT|-1], Distance)
    a := max(Distance)-min(Distance)

 拼图:

 OffsetYX := [0,0,OffsetY11,OffsetX11,OffsetY11+OffsetY22,OffsetX11+OffsetX22]
   * set_dict_tuple (DictHandle_tile, '标定圆提取', ProcessObjOut)
    *拼图
    gen_empty_obj (TiledImageLight)
    gen_empty_obj (TiledImageDark)
    get_image_size (ObjectSelected, Width, Height)
    tile_images_offset (ImageLights, TiledImageLight, [OffsetYX[0],OffsetYX[2],OffsetYX[4]], [OffsetYX[1],OffsetYX[3],OffsetYX[5]], [0,0,0], [0,0,0], [Height,Height,Height], [Width,Width,Width], Width, Height*3-2000)

最终效果:

五、opencv

//  
int MyTileImages(Mat& src1, Mat& src2, Mat& src3, Mat& dst)
{

	vector<Point2f>  pointsLift;
	vector<Point2f>  pointsMiddle;
	vector<Point2f> pointsRight;

	Mat LeftGray, MidGray, RightGray;
	Mat LeftGrayScale, MidGrayScale, RightGrayScale;
	// 图像放缩
	Size size  (src1.cols, src1.rows*6);
	Tiff2Gray(src1, -10, LeftGray);
	resize(LeftGray, LeftGrayScale, size,3);


	Size size2(src2.cols, src2.rows * 6);
	Tiff2Gray(src2, -10, MidGray);
	resize(MidGray, MidGrayScale, size2, 3);


	Size size3(src3.cols, src3.rows * 6);
	Tiff2Gray(src3, -10, RightGray);
	resize(RightGray, RightGrayScale, size3, 3);

	vector<float> left, middle, right;
	FileStorage fs2("./my.yaml", FileStorage::READ);
	string leftstr, middlestr, rightstr;
	fs2["Left"] >> leftstr;
	fs2["Middle"] >> middlestr;
	fs2["Right"] >> rightstr;
	fs2.release();
	left = Mysplit(leftstr, ",");
	middle = Mysplit(middlestr, ",");
	right = Mysplit(rightstr, ",");

	//============左图===================
	GetCalibrateCircles(LeftGrayScale, left, pointsLift);
	vector<vector<Point2f>> sortCentLeft,ssss, sortCentMiddle, sortCentRight;
	// 开始排序   计算出标定板的点 
	SortByRowOrCol(pointsLift, "row", 2, sortCentLeft);

	// 
	Point2f left_right_up(sortCentLeft.at(0).at(1));
	Point2f left_right_down(sortCentLeft.at(1).at(1));
	Point2f  pointleft((left_right_up.x+ left_right_down.x)/2, (left_right_up.y + left_right_down.y) / 2);

	//cout << pointleft << endl;
	circle(LeftGrayScale, left_right_up, 20, Scalar(255), 2, 8, 0);//在原图画出圆心
	circle(LeftGrayScale, left_right_down, 32, Scalar(255), 2, 8, 0);//在原图画出圆心

	circle(LeftGrayScale, pointleft, 20, Scalar(55), 2, 8, 0);//在原图画出圆心
   // 中间的图像需要将其镜像一下=============================================
	Mat Midgraymirror;
	flip(MidGrayScale, Midgraymirror, 0);
	//string flieNameR = "D:\\work\\pcl_workplaces\\Algorithm2D_opencv\\splice_images\\Midgraymirror.png";
	//imwrite(flieNameR, Midgraymirror);
	GetCalibrateCircles(Midgraymirror, middle,pointsMiddle);

	// 
	SortByRowOrCol(pointsMiddle, "row", 2, sortCentMiddle);
	Point2f left_middle_up(sortCentMiddle.at(0).at(0));
	Point2f left_middle_down(sortCentMiddle.at(1).at(0));
	Point2f  pointmiddle_1((left_middle_up.x + left_middle_down.x) / 2, (left_middle_up.y + left_middle_down.y) / 2);


	Point2f right_middle_up(sortCentMiddle.at(0).at(7));
	Point2f right_middle_down(sortCentMiddle.at(1).at(7));
	Point2f  pointmiddle_2((right_middle_up.x + right_middle_down.x) / 2, (right_middle_up.y + right_middle_down.y) / 2);

	circle(Midgraymirror, pointmiddle_1, 20, Scalar(25), 2, 8, 0);//在原图画出圆心
	circle(Midgraymirror, pointmiddle_2, 12, Scalar(25), 2, 8, 0);//在原图画出圆心
	//circle(Midgraymirror, right_middle_up, 20, Scalar(255), 2, 8, 0);//在原图画出圆心
	//circle(Midgraymirror, right_middle_down, 12, Scalar(255), 2, 8, 0);//在原图画出圆心

	//cout << pointmiddle_1 << endl;
	//cout << pointmiddle_2 << endl;

    GetCalibrateCircles(RightGrayScale,right, pointsRight);
	SortByRowOrCol(pointsRight, "row", 2, sortCentRight);
	Point2f right_left_up(sortCentRight.at(0).at(0));
	Point2f right_left_down(sortCentRight.at(1).at(0));
	Point2f  pointright((right_left_up.x + right_left_down.x) / 2, (right_left_up.y + right_left_down.y) / 2);
	circle(RightGrayScale, pointright, 20, Scalar(25), 2, 8, 0);//在原图画出圆心
	//circle(RightGrayScale, left_right_down, 12, Scalar(255), 2, 8, 0);//在原图画出圆心
	//cout << pointright << endl;
	// 将上面的选出的圆的坐标排列出来
	  // 现将第一张图贴上去
	Size size_t = src2.size();
	dst = Mat::zeros(Size(size_t.width * 3, size_t.height * 6), CV_8UC1);
	TileImageBy2Images(LeftGrayScale, pointleft, Midgraymirror,pointmiddle_1, 0.5,dst);
	Point2f lesmd(pointleft.x+(pointmiddle_2.x- pointmiddle_1.x), pointmiddle_2.y);
	TileImageBy2Images(dst, lesmd, RightGrayScale, pointright, 0.5, dst);
	// 计算
	cout << "拼接完成" << endl;

	return 0;
}

 误差是2个像素左右,还可以。。。

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值