千家信息网

C++ OpenCV如何进行图像全景拼接

发表于:2024-11-25 作者:千家信息网编辑
千家信息网最后更新 2024年11月25日,C++ OpenCV如何进行图像全景拼接,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。前言下面将使用OpenCV C++ 进行图像全景拼
千家信息网最后更新 2024年11月25日C++ OpenCV如何进行图像全景拼接

C++ OpenCV如何进行图像全景拼接,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

    前言

    下面将使用OpenCV C++ 进行图像全景拼接。目前使用OpenCV对两幅图像进行拼接大致可以分为两类。

    一、使用OpenCV内置API Stitcher 进行拼接。

    二、使用特征检测算法匹配两幅图中相似的点、计算变换矩阵、最后对其进行透视变换就可以了。

    一、OpenCV Stitcher

    imageA

    imageB

    原图如图所示。本案例的需求是将上述两幅图片拼接成一幅图像。首先使用OpenCV提供的Stitcher进行拼接。关于Stitcher的具体原理请大家自行查找相关资料。

    1.功能源码

    bool OpenCV_Stitching(Mat imageA, Mat imageB){        vectorimages;        images.push_back(imageA);        images.push_back(imageB);        Ptrstitcher = Stitcher::create();        Mat result;        Stitcher::Status status = stitcher->stitch(images, result);// 使用stitch函数进行拼接        if (status != Stitcher::OK) return false;        imshow("OpenCV图像全景拼接", result);        return true;}

    2.效果

    这就是使用OpenCV 内置Stitcher拼接出来的效果。

    二、图像全景拼接

    1.特征检测

    使用方法二进行图像全景拼接。目前网上教程大致流程归为:

    1、使用特征检测算子提取两幅图像的关键点,然后进行特征描述子匹配。我这里使用的是SURF算子。当然SIFT等其他特征检测算子也可以。

         //创建SURF特征检测器        int Hessian = 800;        Ptrdetector = SURF::create(Hessian);        //进行图像特征检测、特征描述        vectorkeypointA, keypointB;        Mat descriptorA, descriptorB;        detector->detectAndCompute(imageA, Mat(), keypointA, descriptorA);        detector->detectAndCompute(imageB, Mat(), keypointB, descriptorB);        //使用FLANN算法进行特征描述子的匹配        FlannBasedMatcher matcher;        vectormatches;        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;                }        }        //筛选出匹配程度高的关键点        vectorgoodmatches;        vectorgoodkeypointA, 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.计算单应性矩阵

    计算单应性变换矩阵

        //获取图像A到图像B的投影映射矩阵,尺寸为3*3    Mat H = findHomography(goodkeypointA, goodkeypointB, RANSAC);    Mat M = (Mat_(3, 3) << 1.0, 0, imageA.cols, 0, 1.0, 0, 0, 0, 1.0);    Mat Homo = M * H;

    3.透视变换

    根据计算出来的单应性矩阵对imageA进行透视变换

        //进行透视变换    Mat DstImg;    warpPerspective(imageA, DstImg, Homo, Size(imageB.cols + imageA.cols, imageB.rows));    imshow("透视变换", DstImg);

    如图所示为imageA进行透视变换得到的结果。

    4.图像拼接

    根据上述操作,我们已经得到了经透视变换的imageA,接下来只需将imageA与imageB拼接起来就可以了。

        imageB.copyTo(DstImg(Rect(imageA.cols, 0, imageB.cols, imageB.rows)));    imshow("图像全景拼接", DstImg);

    5.功能源码

    bool Image_Stitching(Mat imageA, Mat imageB, bool draw){        //创建SURF特征检测器        int Hessian = 800;        Ptrdetector = SURF::create(Hessian);        //进行图像特征检测、特征描述        vectorkeypointA, keypointB;        Mat descriptorA, descriptorB;        detector->detectAndCompute(imageA, Mat(), keypointA, descriptorA);        detector->detectAndCompute(imageB, Mat(), keypointB, descriptorB);        //使用FLANN算法进行特征描述子的匹配        FlannBasedMatcher matcher;        vectormatches;        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;                }        }        //筛选出匹配程度高的关键点        vectorgoodmatches;        vectorgoodkeypointA, 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]);                }        }        if (draw)        {                Mat result;                drawMatches(imageA, keypointA, imageB, keypointB, goodmatches, result);                imshow("特征匹配", result);                Mat temp_A = imageA.clone();                for (int i = 0; i < goodkeypointA.size(); i++)                {                        circle(temp_A, goodkeypointA[i], 3, Scalar(0, 255, 0), -1);                }                imshow("goodkeypointA", temp_A);                Mat temp_B = imageB.clone();                for (int i = 0; i < goodkeypointB.size(); i++)                {                        circle(temp_B, goodkeypointB[i], 3, Scalar(0, 255, 0), -1);                }                imshow("goodkeypointB", temp_B);        }        //findHomography计算单应性矩阵至少需要4个点        /*        计算多个二维点对之间的最优单映射变换矩阵H(3x3),使用MSE或RANSAC方法,找到两平面之间的变换矩阵        */        if (goodkeypointA.size() < 4 || goodkeypointB.size() < 4) return false;        //获取图像A到图像B的投影映射矩阵,尺寸为3*3        Mat H = findHomography(goodkeypointA, goodkeypointB, RANSAC);        Mat M = (Mat_(3, 3) << 1.0, 0, imageA.cols, 0, 1.0, 0, 0, 0, 1.0);        Mat Homo = M * H;        //进行透视变换        Mat DstImg;        warpPerspective(imageA, DstImg, Homo, Size(imageB.cols + imageA.cols, imageB.rows));        imshow("透视变换", DstImg);        imageB.copyTo(DstImg(Rect(imageA.cols, 0, imageB.cols, imageB.rows)));        imshow("图像全景拼接", DstImg);        return true;}

    6.效果

    最终拼接效果如图所示。

    三、源码

    #include#include#include#includeusing namespace std;using namespace cv;using namespace cv::xfeatures2d;//1、使用特征检测算法找到两张图像中相似的点,计算变换矩阵//2、将A透视变换后得到的图片与B拼接bool Image_Stitching(Mat imageA, Mat imageB, bool draw){        //创建SURF特征检测器        int Hessian = 800;        Ptrdetector = SURF::create(Hessian);        //进行图像特征检测、特征描述        vectorkeypointA, keypointB;        Mat descriptorA, descriptorB;        detector->detectAndCompute(imageA, Mat(), keypointA, descriptorA);        detector->detectAndCompute(imageB, Mat(), keypointB, descriptorB);        //使用FLANN算法进行特征描述子的匹配        FlannBasedMatcher matcher;        vectormatches;        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;                }        }        //筛选出匹配程度高的关键点        vectorgoodmatches;        vectorgoodkeypointA, 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]);                }        }        if (draw)        {                Mat result;                drawMatches(imageA, keypointA, imageB, keypointB, goodmatches, result);                imshow("特征匹配", result);                Mat temp_A = imageA.clone();                for (int i = 0; i < goodkeypointA.size(); i++)                {                        circle(temp_A, goodkeypointA[i], 3, Scalar(0, 255, 0), -1);                }                imshow("goodkeypointA", temp_A);                Mat temp_B = imageB.clone();                for (int i = 0; i < goodkeypointB.size(); i++)                {                        circle(temp_B, goodkeypointB[i], 3, Scalar(0, 255, 0), -1);                }                imshow("goodkeypointB", temp_B);        }        //findHomography计算单应性矩阵至少需要4个点        /*        计算多个二维点对之间的最优单映射变换矩阵H(3x3),使用MSE或RANSAC方法,找到两平面之间的变换矩阵        */        if (goodkeypointA.size() < 4 || goodkeypointB.size() < 4) return false;        //获取图像A到图像B的投影映射矩阵,尺寸为3*3        Mat H = findHomography(goodkeypointA, goodkeypointB, RANSAC);        Mat M = (Mat_(3, 3) << 1.0, 0, imageA.cols, 0, 1.0, 0, 0, 0, 1.0);        Mat Homo = M * H;        //进行透视变换        Mat DstImg;        warpPerspective(imageA, DstImg, Homo, Size(imageB.cols + imageA.cols, imageB.rows));        imshow("透视变换", DstImg);        imageB.copyTo(DstImg(Rect(imageA.cols, 0, imageB.cols, imageB.rows)));        imshow("图像全景拼接", DstImg);        return true;}bool OpenCV_Stitching(Mat imageA, Mat imageB){        vectorimages;        images.push_back(imageA);        images.push_back(imageB);        Ptrstitcher = Stitcher::create();        Mat result;        Stitcher::Status status = stitcher->stitch(images, result);// 使用stitch函数进行拼接        if (status != Stitcher::OK) return false;        imshow("OpenCV图像全景拼接", result);        return true;}int main(){        Mat imageA = imread("image1.jpg");        Mat imageB = imread("image2.jpg");        if (imageA.empty() || imageB.empty())        {                cout << "No Image!" << endl;                system("pause");                return -1;        }        if (!Image_Stitching(imageA, imageB, true))        {                cout << "can not stitching the image!" << endl;        }        if (!OpenCV_Stitching(imageA, imageB))        {                cout << "can not stitching the image!" << endl;        }        waitKey(0);        system("pause");        return 0;}

    小编使用OpenCV C++进行图像全景拼接,关键步骤有以下几点。

    1、使用特征检测算子提取两幅图像的关键点,然后进行特征描述子匹配。

    2、筛选出匹配程度高的关键点计算两幅图的单应性矩阵。

    3、利用计算出来的单应性矩阵对其中一张图片进行透视变换。

    4、将透视变换的图片与另一张图片进行拼接。

    看完上述内容,你们掌握C++ OpenCV如何进行图像全景拼接的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注行业资讯频道,感谢各位的阅读!

    特征 图像 变换 矩阵 下标 关键 检测 全景 关键点 程度 算法 选出 如图 图片 方法 C++ 两个 之间 效果 算子 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 电脑软件开发什么配置的 关于加强节假日网络安全工作 云南人口详细数据库 广州互联网科技学校怎么样 怎样把表复制进sql数据库 修改数据库表中数据值 数据库给表起别名sql语句 广德多功能软件开发服务价钱 网络技术偏向软件还是硬件 天元网络技术有限公司是浪潮吗 大话魔游记服务器关闭了吗 网络安全大赛玩的什么游戏 幻塔不同服务器的好可以买吗 小学生网络安全知识教育8条 国都互联网科技有限公司 鹤壁网络安全培训视频 生态环境部中小学网络安全 计算机网络技术英文名称 珠海erp软件开发联系方式 在数据库中说法不正确 梦幻西游端游数据库 新宁县天气预报软件开发 服务器ups电源主机 电工与网络技术哪个容易学 梦香服务器 玖二柒互联网科技公司 数据库管理存储技术 打开服务器文件夹 网络安全党日活动 中兴展示的服务器浸没式液冷技术
    0