传声筒
王不超OpenCVC++案例实战⼗⼆《图像全景拼接》
OpenCV C++案例实战⼗⼆《图像全景拼接》
前⾔
本⽂将使⽤OpenCV C++ 进⾏图像全景拼接。⽬前使⽤OpenCV对两幅图像进⾏拼接⼤致可以分为两类。
⼀、使⽤OpenCV内置API Stitcher 进⾏拼接。
⼆、使⽤特征检测算法匹配两幅图中相似的点、计算变换矩阵、最后对其进⾏透视变换就可以了。
⼀、OpenCV Stitcher
imageA
imageB
原图如图所⽰。本案例的需求是将上述两幅图⽚拼接成⼀幅图像。⾸先使⽤OpenCV提供的Stitcher进⾏拼接。关于Stitcher的具体原理请⼤家⾃⾏查找相关资料。
1.功能源码
bool OpenCV_Stitching(Mat imageA, Mat imageB)
{
vector<Mat>images;
images.push_back(imageA);
images.push_back(imageB);
Ptr<Stitcher>stitcher = Stitcher::create();
Mat result;
Stitcher::Status status = stitcher->stitch(images, result);// 使⽤stitch函数进⾏拼接
if(status != Stitcher::OK)return fal;
imshow("OpenCV图像全景拼接", result);
return true;
}
2.效果
西游记主旨
这就是使⽤OpenCV 内置Stitcher拼接出来的效果。
⼆、图像全景拼接
1.特征检测
使⽤⽅法⼆进⾏图像全景拼接。⽬前⽹上教程⼤致流程归为:
1、使⽤特征检测算⼦提取两幅图像的关键点,然后进⾏特征描述⼦匹配。我这⾥使⽤的是SURF算⼦。当然SIFT等其他特征检测算⼦也可以。
//创建SURF特征检测器
int Hessian =800;
Ptr<SURF>detector = SURF::create(Hessian);
//进⾏图像特征检测、特征描述
vector<KeyPoint>keypointA, keypointB;
Mat descriptorA, descriptorB;
detector->detectAndCompute(imageA,Mat(), keypointA, descriptorA);
detector->detectAndCompute(imageB,Mat(), keypointB, descriptorB);
//使⽤FLANN算法进⾏特征描述⼦的匹配
FlannBadMatcher matcher;
vector<DMatch>matches;
matcher.match(descriptorA, descriptorB, matches);
如图为使⽤FLANN算法进⾏特征描述⼦匹配的结果。我们需要把那些匹配程度⾼的关键点筛选出来⽤以下⾯计算两幅图像的单应性矩阵。
2、筛选出匹配程度⾼的关键点
double Max =0.0;
for(int i =0; i < matches.size(); i++)
{
//float distance –>代表这⼀对匹配的特征点描述符(本质是向量)的欧⽒距离,数值越⼩也就说明两个特征点越相像。
double dis = matches[i].distance;
if(dis > Max)
{
Max = dis;
}
}
//筛选出匹配程度⾼的关键点
vector<DMatch>goodmatches;
vector<Point2f>goodkeypointA, goodkeypointB;
for(int i =0; i < matches.size(); i++)
{
double dis = matches[i].distance;
if(dis <0.15*Max)
{
//int queryIdx –>是测试图像的特征点描述符(descriptor)的下标,同时也是描述符对应特征点(keypoint)的下标。
goodkeypointA.push_back(keypointA[matches[i].queryIdx].pt);
//int trainIdx –> 是样本图像的特征点描述符的下标,同样也是相应的特征点的下标。
goodkeypointB.push_back(keypointB[matches[i].trainIdx].pt);
goodmatches.push_back(matches[i]);
}
天秤座与天蝎座
}
如图为imageA筛选出来的关键点。
如图为imageB筛选出来的关键点。
从上图可以看出,我们已经筛选出imageA,imageB共有的关键点部分。接下来,我们需要使⽤这两个点集计算两幅图的单应性矩阵。
2.计算单应性矩阵
3、计算单应性变换矩阵
//获取图像A到图像B的投影映射矩阵,尺⼨为3*3
Mat H =findHomography(goodkeypointA, goodkeypointB, RANSAC);
Mat M =(Mat_<double>(3,3)<<1.0,0, ls,0,1.0,0,0,0,1.0);
Mat Homo = M * H;
3.透视变换
4、根据计算出来的单应性矩阵对imageA进⾏透视变换
//进⾏透视变换
Mat DstImg;
warpPerspective(imageA, DstImg, Homo,ls + ls, ws));
铁打的营盘imshow("透视变换", DstImg);
如图所⽰为imageA进⾏透视变换得到的结果。
4.图像拼接
5、根据上述操作,我们已经得到了经透视变换的imageA,接下来只需将imageA与imageB拼接起来就可以了。
imshow("图像全景拼接", DstImg);
5.功能源码
bool Image_Stitching(Mat imageA, Mat imageB,bool draw)
{
//创建SURF特征检测器
int Hessian =800;彩色插图
为了幸福
Ptr<SURF>detector = SURF::create(Hessian);
//进⾏图像特征检测、特征描述
vector<KeyPoint>keypointA, keypointB;
Mat descriptorA, descriptorB;
detector->detectAndCompute(imageA,Mat(), keypointA, descriptorA);
detector->detectAndCompute(imageB,Mat(), keypointB, descriptorB);
//使⽤FLANN算法进⾏特征描述⼦的匹配
FlannBadMatcher matcher;
vector<DMatch>matches;
matcher.match(descriptorA, descriptorB, matches);
double Max =0.0;
for(int i =0; i < matches.size(); i++)
{
//float distance –>代表这⼀对匹配的特征点描述符(本质是向量)的欧⽒距离,数值越⼩也就说明两个特征点越相像。double dis = matches[i].distance;
if(dis > Max)
{
Max = dis;
}
}
//筛选出匹配程度⾼的关键点
vector<DMatch>goodmatches;
vector<Point2f>goodkeypointA, goodkeypointB;
for(int i =0; i < matches.size(); i++)
{
double dis = matches[i].distance;
游园不值叶绍翁
if(dis <0.15*Max)
{
//int queryIdx –>是测试图像的特征点描述符(descriptor)的下标,同时也是描述符对应特征点(keypoint)的下标。