700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 利用C++中的opencv进行图像拼接

利用C++中的opencv进行图像拼接

时间:2023-11-11 01:30:40

相关推荐

利用C++中的opencv进行图像拼接

这篇文章依旧是记录采用C++复现图像拼接过程解决遇到的问题。因为自己没有学过C++,大学学的C考完试立马还给老师了,Python也是现学的,只会一点点MATLAB,所以遇到的问题和解决都很基础,目的是自己做一些记录,并分享给与我相同的图像入门小白,若有错误还希望大佬们指正。

一、拼接方法介绍

拼接的主要参考文献:

OpenCV常用图像拼接方法(二):基于模板匹配拼接_Color Space的博客-CSDN博客_图像拼接素材

图像拼接的程序的目的是将imgL(1)与imgR(2)拼接起来,方法是通过截取imgL中的一小部分特征区域与imgR的图像进行比对,找到最相似的区域坐标,以此作为拼接的联系坐标,将两幅图拼接起来(大白话就是将两图最相似的区域对齐叠起来达到拼接效果。)

Mat imgL = imread("A.jpg");Mat imgR = imread("B.jpg");double start = getTickCount();Mat grayL, grayR;cvtColor(imgL, grayL, COLOR_BGR2GRAY);cvtColor(imgR, grayR, COLOR_BGR2GRAY);Rect rectCut = Rect(372, 122, 128, 360);Rect rectMatched = Rect(0, 0, imgR.cols / 2, imgR.rows);Mat imgTemp = grayL(Rect(rectCut));Mat imgMatched = grayR(Rect(rectMatched));int width = imgMatched.cols - imgTemp.cols + 1;int height = imgMatched.rows - imgTemp.rows + 1;Mat matchResult(height, width, CV_32FC1);matchTemplate(imgMatched, imgTemp, matchResult, TM_CCORR_NORMED);normalize(matchResult, matchResult, 0, 1, NORM_MINMAX, -1); //归一化到0--1范围double minValue, maxValue;Point minLoc, maxLoc;minMaxLoc(matchResult, &minValue, &maxValue, &minLoc, &maxLoc);Mat dstImg(imgL.rows, imgR.cols + rectCut.x - maxLoc.x, CV_8UC3, Scalar::all(0));Mat roiLeft = dstImg(Rect(0, 0, imgL.cols, imgL.rows));imgL.copyTo(roiLeft);Mat debugImg = imgR.clone();rectangle(debugImg, Rect(maxLoc.x, maxLoc.y, imgTemp.cols, imgTemp.rows), Scalar(0, 255, 0), 2, 8);imwrite("match.jpg", debugImg);Mat roiMatched = imgR(Rect(maxLoc.x, maxLoc.y - rectCut.y, imgR.cols - maxLoc.x, imgR.rows - 1 - (maxLoc.y - rectCut.y)));Mat roiRight = dstImg(Rect(rectCut.x, 0, roiMatched.cols, roiMatched.rows));roiMatched.copyTo(roiRight);double end = getTickCount();double useTime = (end - start) / getTickFrequency();cout << "use-time : " << useTime << "s" << endl;imwrite("dst.jpg", dstImg);cout << "Done!" << endl;

基础背景说明

1、首先这个程序是C++程序,不是Python程序,我在Python中跑半天是不是很令人震惊。

我在Visualstudio中创建一个C++的空项目进行复现(VS如何配置opencv环境以及创建空项目我后面估计会再分享一个博客记录说明,因为我自己也老忘,好麻烦呀,反观MATLAB好香)

写好啦:Visual Studio中设置opencv环境_日拱一卒不慌忙的博客-CSDN博客

2、其次上面这个函数是一个子函数的内容,直接复制到VS中是不能运行的,需要加入一些头文件,并把函数放进主函数中才能运行。

#include <windows.h>#include <opencv2\opencv.hpp>#include <iostream>using namespace std;using namespace cv;int main(){//1、读取图像,并将RGB图像转换为灰度图Mat imgL = imread("C:\\Users\\AC\\Desktop\\A.jpg");Mat imgR = imread("C:\\Users\\AC\\Desktop\\B.jpg");double start = getTickCount(); //计时开始Mat grayL, grayR;cvtColor(imgL, grayL, COLOR_BGR2GRAY);cvtColor(imgR, grayR, COLOR_BGR2GRAY);//2、在左图中截取一小块特征区域作为匹配模板imgtempRect Rectcut = Rect(150, 150, 50, 50);int widthR = Rectcut.x;int heightR = Rectcut.y;Rect Rectmatched = Rect(0, 0, imgR.cols / 2, imgR.rows); Mat imgtemp = grayL(Rect(Rectcut));Mat imgmatched = grayR(Rect(Rectmatched));//3、采用特征模板在右图中进行相似比对,找到最相似的区域位置坐标maxLocint width = imgmatched.cols - imgtemp.cols + 1;int height = imgmatched.rows - imgtemp.rows + 1;Mat matchResult(height, width, CV_32FC1); //CV_32 32比特,F代表单精度浮点型,C1单通道图像,2三通道,3四通道 matchTemplate(imgmatched, imgtemp, matchResult, TM_CCORR_NORMED); normalize(matchResult, matchResult, 0, 1, NORM_MINMAX, -1); //归一化到0--1范围 double minValue, maxValue; Point minLoc, maxLoc;minMaxLoc(matchResult, &minValue, &maxValue, &minLoc, &maxLoc); //4、创建一个大的空图,先将左图复制上去,再将右图根据重叠区域位置坐标截切后复制到大图中,形成最终的拼接图像dstImgMat dstImg(imgL.rows, imgR.cols + Rectcut.x - maxLoc.x, CV_8UC3, Scalar::all(0)); Mat roiLeft = dstImg(Rect(0, 0, imgL.cols, imgL.rows));Mat debugImg = imgR.clone(); rectangle(debugImg, Rect(maxLoc.x, maxLoc.y, imgtemp.cols, imgtemp.rows), Scalar(0, 255, 0), 2, 8); imwrite("match.jpg", debugImg);Mat roiMatched = imgR(Rect(maxLoc.x, maxLoc.y - Rectcut.y, imgR.cols - maxLoc.x, imgR.rows - 1 - (maxLoc.y - Rectcut.y))); Mat roiRight = dstImg(Rect(Rectcut.x, 0, roiMatched.cols, roiMatched.rows));roiMatched.copyTo(roiRight);//5、存图,还有仪式感double end = getTickCount(); //计时结束double useTime = (end - start) / getTickFrequency();cout << "use-time : " << useTime << "s" << endl;imshow("图像", dstImg);waitKey(0);cout << "Done!" << endl;return 0;}

二、拼接程序分析

程序基础准备

首先我们拿到一个程序需要清楚程序的目的(在做什么),程序的流程(怎么做的),对应到程序各部分的功能(每一个part到底在做啥,我附注在上面每段的程序上了),有背景基础才能有助于对新的语言所表达的内容进行理解,要不然就陷入到一堆字母中啊?啊?啊?放弃X,我就是放弃了好多遍又捡回来的(讲道理的时候说得可好听啦...)。

各部分基础说明

1、Mat imgL=imread("路径(双斜杠)")

M要大写,路径间隔要是双斜杠或反斜杠,每句后要有小写的;

否则你会喜提一个感叹号,杠杠的!

创建一个名称为imgL的空的mat数据矩阵存放读取进的图像,图像的每个像素的灰度值会被记录在矩阵的每个对应位置上,同理Mat grayL, grayR,也是创建了两个名称为grayL, grayR的空的数据矩阵存放一会RGB转换为灰度图的图像,cvtcolor是一个转换函数,具体细节百度一下。

Mat imgL = imread("C:\\Users\\AC\\Desktop\\A.jpg");Mat imgR = imread("C:\\Users\\AC\\Desktop\\B.jpg");Mat grayL, grayR;cvtColor(imgL, grayL, COLOR_BGR2GRAY);cvtColor(imgR, grayR, COLOR_BGR2GRAY);

2、Rect类

Rect Rectcut = Rect(150, 150, 50, 50);// 定义一个名称为Rectcut的矩形,Rect括号里面分别表示这个矩形的左上角坐标,宽和高,同理下面的Rectmatched,不要试图翻译矩矩切,矩矩匹配,爱它没结果,要注重函数的构成形式,名称不重要,意义也不重要,重要的是理解函数实现了一个什么样功能的操作

3、int类,double类

哈哈哈,终于碰到我眼熟的了,这是定义一个名称为widthR的整型,将Rectcut.x的值或是计算的结果存储到widthR中。

int widthR = Rectcut.x

1. OpenCV 数据结构与基本绘图_zcx_xxx的博客-CSDN博客

Rect Rectcut = Rect(150, 150, 50, 50);int widthR = Rectcut.x;int heightR = Rectcut.y;Rect Rectmatched = Rect(0, 0, imgR.cols / 2, imgR.rows); Mat imgtemp = grayL(Rect(Rectcut));Mat imgmatched = grayR(Rect(Rectmatched));

4、匹配函数matchTemplate

matchTemplate是函数的名称,()里面是其需要输入的参数变量。

首先需要理解,函数的功能,其次需要知道自己想要正确使用这个函数需要输入的正确对应参数。

譬如MatchTemplate函数,是在一幅图像中寻找与另一幅模板图像最匹配(相似)部分。

参数详解

MatchTemplate(InputArray image, InputArray templ, OutputArray result, int method);

image:输入一个待匹配的图像,支持8U或者32F。

templ:输入一个模板图像,与image相同类型。

result:输出保存结果的矩阵,32F类型。

method:要使用的数据比较方法。

MatchTemplate函数参考下面这个博文

【 OpenCV 】MatchTemplate函数参数详解及原理分析_Nick大帅仔的博客-CSDN博客_matchtemplate

同理normalize这个函数是用来归一化的,minMaxloc是用来寻找最大值和最小值的坐标位置(&a代表取到a的地址)。

归一化函数normalize详解 - 百度文库

OpenCV 找出图像中最小值最大值函数minMaxLoc的使用 - 灰信网(软件开发博客聚合)

//3、采用特征模板在右图中进行相似比对,找到最相似的区域位置坐标maxLocint width = imgmatched.cols - imgtemp.cols + 1;int height = imgmatched.rows - imgtemp.rows + 1;Mat matchResult(height, width, CV_32FC1); //CV_32 32比特,F代表单精度浮点型,C1单通道图像,2三通道,3四通道 matchTemplate(imgmatched, imgtemp, matchResult, TM_CCORR_NORMED); normalize(matchResult, matchResult, 0, 1, NORM_MINMAX, -1); //归一化到0--1范围 double minValue, maxValue; Point minLoc, maxLoc;minMaxLoc(matchResult, &minValue, &maxValue, &minLoc, &maxLoc);

5、拼图(浅拷贝和深拷贝)

//4、创建一个大的空图,先将左图复制上去,再将右图根据重叠区域位置坐标截切后复制到大图中,形成最终的拼接图像dstImgMat dstImg(imgL.rows, imgR.cols + Rectcut.x - maxLoc.x, CV_8UC3, Scalar::all(0)); Mat roiLeft = dstImg(Rect(0, 0, imgL.cols, imgL.rows));Mat debugImg = imgR.clone(); rectangle(debugImg, Rect(maxLoc.x, maxLoc.y, imgtemp.cols, imgtemp.rows), Scalar(0, 255, 0), 2, 8); imwrite("match.jpg", debugImg);Mat roiMatched = imgR(Rect(maxLoc.x, maxLoc.y - Rectcut.y, imgR.cols - maxLoc.x, imgR.rows - 1 - (maxLoc.y - Rectcut.y))); Mat roiRight = dstImg(Rect(Rectcut.x, 0, roiMatched.cols, roiMatched.rows));roiMatched.copyTo(roiRight);

这里会涉及到拷贝的问题,就是我们要形成最后的拼接图像,必然要先从原来的两幅图中的信息提取出来,然后进行一些修剪,再将其组合起来。

首先数据传递和处理不能影响到原图imgL(深拷贝),其次分图roiLeft的数据的处理要体现在最后的大的拼接图dstImg中(浅拷贝)。

深拷贝:分配新内存的同时拷贝数据!当被赋值的容器被修改时,原始容器数据不会改变。

浅拷贝:仅拷贝数据!当被赋值容器修改时,原始容器数据也会做同样改变。(感觉和C++中引用同理)

深拷贝是 b = a.clone(); 和 a.copyTo(b);浅拷贝是 b = a;和 b(a);

OpenCV中cv::Mat的深拷贝 浅拷贝问题_verystory的博客-CSDN博客_cv::mat拷贝

三、个人心得

个人总结一点程序调试的心得,这部分还是希望有大佬们多多指点我。

我自己的方法是,首先清楚程序的目的,流程和各部分的功能后,调试程序用的是笨办法,就是从上到下逐步取消注释运行部分程序看有没有报错,前面的没有报错,代表的前面没有问题,后面新的问题一定是出在了新的取消注释的部分中,然后先根据错误列表中首先看格式有没有问题,格式没问题了,看函数是否使用合适,参数是否符合函数的输入参数要求,譬如最后拼接出问题就是由于坐标值计算结果为负导致报错。

暂时就这么多啦,感谢在解决问题过程中各位大佬的帮助,如果我的回答帮助到你,还麻烦给我点赞加油呀~~

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。