CV进阶应用【10】——图像拼接全景图与平面跟踪的AR

编程环境:

VS + OpenCV + C++
完整代码已经更新至GitHub,欢迎fork~GitHub链接


声明:创作不易,未经授权不得复制转载
statement:No reprinting without authorization


内容概述:

  • 基于OpenCV实现图像拼接,可以对两张或更多的输入图像,将图像对齐后拼接成一张全景图。( 相关函数: findHomography, warpPerspective )
  • 对包含一个平面目标的视频,跟踪由用户指定的平面上的一个四边形区域,并替换区域内的视频内容。
    — 被跟踪的四边形区域由用户在第1帧指定,或者基于给 定的模板进行识别;
    — 优化跟踪的稳定性和速度;

一、全景图拼接

实验步骤过程

1、对每幅图进行特征点提取
2、对特征点进行匹配,并进行筛选
3、进行图像配准
4、把图像拷贝到另一幅图像的特定位置,裁剪尺寸处理
5、对重叠边界处理优化,图像融合(去裂缝处理)

测试拼接所用的原图片:

image.png

image.png

image.png

image.png

image.png

(1)特征点提取

• 提取特征点有sift、surf、harris角点、ORB等常用方法
• 考虑到精确度、稳定性和速度,本实验中采用了SIFT和SURF的方法
• SURF精确度和稳定性不及SIFT,但是其综合能力还是优越一些,在速度方面有了明显的提高(速度是SIFT的3倍)
• 注:opencv stitch选择的特征检测方式第一选择是SURF,第二选择才是ORB

(2)获取匹配点与筛选

1、获取:

       使用opencv的 FlannBasedMatcher(更快找到最近邻近似匹 配,不尝试所有可能的匹配,不一定最佳,保证相对好的匹配和速度,BFMatcher)
        然后调用 KNNMatch ,可设置K = 2 ,即对每个匹配返回两个最近邻描述符,仅当第一个匹配与第二个匹配之间的距离足够小时,才认为这是一个匹配。得到所有匹配点。

2、筛选:(自定义goodMatch+二次匹配)

(1)只保留匹配点中的两点距离较小的:
matchePoints[i][0].distance<0.4*matchePoints[i][1].distance
(2)进行二次匹配:img1->img2  goodmatch  img2->img1
得到更多好的匹配点(参考opencv自带的拼接算法stitch)

• 进行特征点的检测和匹配点筛选后的结果:
        左图为将Pic02.jpg和Pic03.jpg合并得到dst01.jpg时打印的信息,有图将Pic01.jpg和dst01.jpg合并拼接的信息


image.png
image.png

• 进行特征点的检测和匹配点筛选后的结果


image.png

image.png

(3)进行图像配准与拷贝

• 先利用 findHomography 函数得到投影映射矩阵
(也可以使用getPerspectiveTransform方法获得透视变换矩阵,不过要求只能有4个点,效果稍差)
• 计算配准图的四个顶点坐标

• 调用 warpPerspective 变换另一幅图像,最后设置好尺寸,使用copyTo完成拼接

1、转换后tran.jpg
image.png

image.png

image.png
2、初步拼接后图片
image.png

image.png

image.png

(4)边界处理优化

• 优化两图的连接处,使得拼接自然:
• 策略:(修改alpha通道值)
如果遇到图像trans中无像素的黑点,则完全拷贝img1中的数据
否则将img1中像素的权重,设置为与当前处理点距重叠区域左边界的距离成正比的大小

//优化两图的连接处,使得拼接自然
void OptimizeSeam(Mat& img1, Mat& trans, Mat& dst)
{
    int start = MIN(corners.left_top.x, corners.left_bottom.x);//开始位置,即重叠区域的左边界  

    double processWidth = img1.cols - start;//重叠区域的宽度  
    int rows = dst.rows;
    int cols = img1.cols; //注意,是列数*通道数
    double alpha = 1;//img1中像素的权重  
    for (int i = 0; i < rows; i++)
    {
        uchar* p = img1.ptr<uchar>(i);  //获取第i行的首地址
        uchar* t = trans.ptr<uchar>(i);
        uchar* d = dst.ptr<uchar>(i);
        for (int j = start; j < cols; j++)
        {
            //如果遇到图像trans中无像素的黑点,则完全拷贝img1中的数据
            if (t[j * 3] == 0 && t[j * 3 + 1] == 0 && t[j * 3 + 2] == 0)
            {
                alpha = 1;
            }
            else
            {
                //img1中像素的权重,与当前处理点距重叠区域左边界的距离成正比,实验证明,这种方法确实好  
                alpha = (processWidth - (j - start)) / processWidth;
            }

            d[j * 3] = p[j * 3] * alpha + t[j * 3] * (1 - alpha);
            d[j * 3 + 1] = p[j * 3 + 1] * alpha + t[j * 3 + 1] * (1 - alpha);
            d[j * 3 + 2] = p[j * 3 + 2] * alpha + t[j * 3 + 2] * (1 - alpha);

        }
    }

}
1、最终效果图一:
image.png

opencv stitch效果图:
image.png
2、最终效果图二:
image.png

opencv stitch效果图:
image.png

二、基于平面跟踪的AR

(1)实验内容步骤

• 打开视频对第一帧进行处理,交互确定四边形的初始点
• 框定进行特征检测与匹配的局部区域,加速匹配计算变换矩阵
• 对视频流每帧进行处理计算出矩阵后得到新的四个顶点坐标(perspectiveTransform)再次利用findHomography和warpPerspective将视频进行嵌入

(2)优化及一些问题

1、框定局部区域可以加速计算并派出一些干扰,来求解homograph,区域太小会导致计算出的匹配点太少,误差较大,造成晃动
• 优化策略:框定具有明显

特征的区域,进一步优化
筛选匹配点,自定义
的good match可以调高阈值,
适当增加匹配点的数量


image.png

2、计算变换矩阵时,并不将当前帧与前一帧作为输入,而是将之前存储的base帧与当前帧输入,并且每隔一定帧数(10帧左右),更新base帧,同时更新基准顶点坐标

1、优点:可以提高稳定性,加速计算,提前保存base帧的特征点,不用重复计算。
2、用前后帧或更新过快的话可能会导致意外的错误大量累积,每次更新的顶点都在上一次误差上加大,同时更新过慢的话,会由于图片场景变化过大,得到的匹配点数目越来越少,导致计算出的误差较大,不精准。
3、解决策略:调参!实验发现- 每隔10-12帧更新一次,- 结果较好,比较稳定


image.png

3、优化匹配点问题:

knnMatch + goodmatch + RANSAC(封装在findHomography中)

• 核心代码示例:

while (true) {
        video >> curImg; myvideo >> inImg;      
        if (!inImg.data||!curImg.data || waitKey(pauseTime) == 27)  //图像为空或Esc键按下退出播放
        {
            break;
        }
        im_temp = curImg.clone();
        vimg = curImg.clone();      
        //Mat curPart = curImg(Rect(originalPoint, processPoint));
        //h = getmyHomographMat(lastPart, curPart);
        h = getmyHomographMat(FstImg, curImg);
        //cout << "变换矩阵为:\n" << h << endl << endl; //输出映射矩阵     
        perspectiveTransform(data.points,CURponits, h);
        //cout << "size data point :" << data.points.size() << endl;
        Mat HH = findHomography(pts_src, CURponits);
        warpPerspective(inImg, inImg, HH, curImg.size());
        for (int i = 0; i < 4; i++)
        {
            pts_dst[i] = CURponits[i];
        }       
        fillConvexPoly(vimg, pts_dst, 4, Scalar(0), CV_AA);
        shImg = vimg + inImg;
        //不去更新对比图片,如果每次在上一次的点基础上变换,会导致误差不断累积
        //imshow("result", shImg);
        count_frame++;
        if (count_frame % 10 == 0) {
            FstImg = im_temp;
            //lastPart = im_temp(Rect(originalPoint, processPoint));//提升速度
            data.points = CURponits;
        }
        writerr.write(shImg);
        //shImg.release();      
    }

(3)视频成果:

        视频链接


声明:创作不易,未经授权不得复制转载
statement:No reprinting without authorization


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容