在Stitching模块中以及原始论文《Automatic Panoramic Image Stitching using Invariant Features》3.2中,都有“根据已经匹配好的特征对,判断哪些图片是属于序列,那些图片是不属于序列”的这一步操作。
论文解释为:
 


对应的函数为:
std::vector<int> leaveBiggestComponent(std::vector<ImageFeatures> &features,  std::vector<MatchesInfo> &pairwise_matches,float conf_threshold)
{
    const int num_images = static_cast<int>(features.size());
    DisjointSets comps(num_images);
    for (int i = 0; i < num_images; ++i)
    {
        for (int j = 0; j < num_images; ++j)
        {
            if (pairwise_matches[i*num_images + j].confidence < conf_threshold)
                continue;
            int comp1 = comps.findSetByElem(i);
            int comp2 = comps.findSetByElem(j);
            if (comp1 != comp2)
                comps.mergeSets(comp1, comp2);
        }
    }
    int max_comp = static_cast<int>(std::max_element(comps.size.begin(),comps.size.end()) - comps.size.begin());
    std::vector<int> indices;
    std::vector<int> indices_removed;
    for (int i = 0; i < num_images; ++i)
        if (comps.findSetByElem(i) == max_comp)
            indices.push_back(i);
        else
            indices_removed.push_back(i);
    std::vector<ImageFeatures> features_subset;
    std::vector<MatchesInfo> pairwise_matches_subset;
    for (size_t i = 0; i < indices.size(); ++i)
    {
        features_subset.push_back(features[indices[i]]);
        for (size_t j = 0; j < indices.size(); ++j)
        {
            pairwise_matches_subset.push_back(pairwise_matches[indices[i]*num_images + indices[j]]);
            pairwise_matches_subset.back().src_img_idx = static_cast<int>(i);
            pairwise_matches_subset.back().dst_img_idx = static_cast<int>(j);
        }
    }
    if (static_cast<int>(features_subset.size()) == num_images)
        return indices;
    LOG("Removed some images, because can't match them or there are too similar images: (");
    LOG(indices_removed[0] + 1);
    for (size_t i = 1; i < indices_removed.size(); ++i)
        LOG(", " << indices_removed[i]+1);
    LOGLN(").");
    LOGLN("Try to decrease the match confidence threshold and/or check if you're stitching duplicates.");
    features = features_subset;
    pairwise_matches = pairwise_matches_subset;
    return indices;
}

leaveBiggestComponent的主要目的可以描述为“寻找所有配对中肯定属于一幅全景图像的图片”,主要通过的方法是“并查集”
那什么是“并查集”了?举个简单应用的例子。现在社交网站这么流行,假设现在想知道两个人之间是否存在间接好友关系(A和B为好友,B和C为好友,A和C为间接好友),有什么好方法呢?并查集就是用于这类查询问题的有效数据结构,正如其名(disjoint set),并查集本质上是一个集合,集合的元素为树,因此并查集实际上表示了一个森林(disjoint-set forests)。它的特点是每棵树中的成员都可由根结点所代表,这样要知道两个结点是否属于集合的同一元素,只要看它们是否有同一“代表”。
为此,搜集资料,编写代码
#include "stdafx.h"
#include "opencv2/opencv_modules.hpp"
#include <opencv2/core/utility.hpp>
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/stitching/detail/autocalib.hpp"
#include "opencv2/stitching/detail/blenders.hpp"
#include "opencv2/stitching/detail/timelapsers.hpp"
#include "opencv2/stitching/detail/camera.hpp"
#include "opencv2/stitching/detail/exposure_compensate.hpp"
#include "opencv2/stitching/detail/matchers.hpp"
#include "opencv2/stitching/detail/motion_estimators.hpp"
#include "opencv2/stitching/detail/seam_finders.hpp"
#include "opencv2/stitching/detail/warpers.hpp"
#include "opencv2/stitching/warpers.hpp"
#define  conf_threshold 90  
#define  num_images 10  
using namespace std;
using namespace cv;
using namespace cv::detail;
void main()  
{  
    int max_comp = 0;  
    int max_size = 0;  
    vector<int> confident(num_images*num_images);  
    DisjointSets comps(num_images);  
    //使用随机数模拟多幅图像中每个图像相互匹配的置信度(0-100)  
    //另外1与2的匹配置信度和2与1的置信度我们默认相同(实际中是不相同的)  
    srand((unsigned)time(NULL));  
    for (int i  = 0;i<num_images;i++)  
    {  
        cout<<endl;  
        for (int j = 0;j<num_images;j++)  
        {  
            if (!confident[i*num_images+j])  
            {  
                confident[i*num_images+j] = rand()%100;  
                confident[j*num_images+i] = confident[i*num_images+j];  
            }  
            if (i == j)  
            {  
                confident[i*num_images+j] = 100;  
            }  
            cout<<"   "<<confident[i*num_images+j];  
        }  
    }  
    //根据两幅图匹配置信度是否大于conf_threshold来决定是否属于一个全景集合  
    for (int i = 0; i < num_images; ++i)  
    {  
        for (int j = 0; j < num_images; ++j)  
        {  
            if (confident[i*num_images + j] < conf_threshold)  
                continue;  
            int comp1 = comps.findSetByElem(i);  
            int comp2 = comps.findSetByElem(j);  
            if (comp1 != comp2)  
                comps.mergeSets(comp1, comp2);  
        }  
    }  
    //找出包含图片最多的全景集合  
    for (int i = 0;i< num_images;i++)  
    {  
        if (i == 0)  
        {  
            max_comp = 0;  
            max_size = comps.size[i];  
        }  
        else if(comps.size[i]>max_size)  
        {  
            max_comp = i;  
            max_size = comps.size[i];  
        }  
    }  
    //将该集合中的元素打印出来  
    cout<<endl<<"images in the max_comp:"<<endl;  
    int j = 0;  
    for (int i = 0;i<num_images;i++)  
    {  
        if (comps.findSetByElem(i) == max_comp)  
        {  
            cout<<++j<<":  "<< i<<endl;  
        }  
    }  
    while(1);  
}  

其中相关函数解释:
 comps.mergeSets(comp1, comp2); 
是将comp1和comp2合并起来。
最后得到的,就是在目前情况下,最大可能的符合条件的序列组合。

解析:

这里的理解可能有一些困难,关键是要把握在运算前有什么,运算后有什么?
在运算前,我们得到的是一个矩阵,那就是N*N的图片序列中,每一个图片和其他N-1个图片之间的特征匹配关系,也包括确信值
运算之后,需要获得的是在这些所有的关系中,所有对都符合条件的,但是相互之间不想交的对的集合。并且把最大的那个打印出来。

 

Stitching模块中leaveBiggestComponent初步研究的更多相关文章

  1. Stitching模块中focalsFromHomography初步研究

    在Stitching模块中,通过“光束法平差”的时候,有一个步骤为“通过单应矩阵估算摄像头焦距”,调用的地方为:   , ));    ] ];    d2 ] ]) ] ]);    v1 ] ]  ...

  2. Stitching模块中对特征提取的封装解析(以ORB特性为例)

    titching模块中对特征提取的封装解析(以ORB特性为例)     OpenCV中Stitching模块(图像拼接模块)的拼接过程可以用PipeLine来进行描述,是一个比较复杂的过程.在这个过程 ...

  3. opencv笔记--stitching模块

    opencv 提供了全景图像拼接的所有实现,包括: 1)stitching 模块提供了图像拼接过程中所需要的基本元素,该模块主要依赖于 features2d 模块: 2)提供了 stitching_d ...

  4. iOS多线程的初步研究(六)

    iOS多线程的初步研究(六) iOS平台提供更高级的并发(异步)调用接口,让你可以集中精力去设计需完成的任务代码,避免去写与程序逻辑无关的线程生成.运行等管理代码.当然实质上是这些接口隐含生成线程和管 ...

  5. iOS多线程的初步研究3

    iOS多线程的初步研究(三) 弄清楚NSRunLoop确实需要花时间,这个类的概念和模式似乎是Apple的平台独有(iOS+MacOSX),很难彻底搞懂(iOS没开源,呜呜). 官网的解释是说run ...

  6. iOS多线程的初步研究1

    iOS多线程的初步研究(一) 对于多线程的开发,iOS系统提供了多种不同的接口,先谈谈iOS多线程最基础方面的使用.产生线程的方式姑且分两类,一类是显式调用,另一类是隐式调用. 一.显示调用的类为NS ...

  7. iOS多线程的初步研究

    iOS多线程的初步研究(四) 理解run loop后,才能彻底理解NSTimer的实现原理,也就是说NSTimer实际上依赖run loop实现的. 先看看NSTimer的两个常用方法: + (NST ...

  8. Nginx基础知识之————RTMP模块中的中HLS专题(翻译文档)

    一.在Nginx配置文件的RTMP模块中配置hls hls_key_path /tmp/hlskeys; 提示错误信息: nginx: [emerg] the same path name " ...

  9. 一个Angular模块中可以声明哪些组件?

    一个Angular模块中可以声明哪些组件? (1) controller        控制器 (2) directive                指令 (3) function         ...

随机推荐

  1. Runtime 运行时之一:消息传递

    什么是Runtime? Runtime顾名思义即为运行时.就是系统运行时候的一些机制,它提供了一些使得对象之间能够传递消息的重要函数,其中最主要的就是消息机制了.相较于C语言而言,C语言使用的是“静态 ...

  2. img-图片二进制流 64位前端显示

    碰到的场景:因为使用iframe子窗口打开,多张的二维码图片创建方法调用,导致页面打开缓慢, 所以将调取方式转换成<img src="data:image/png;base64,@it ...

  3. linux 下 git gem 等代理设置问题

    github.com,作为程序员的代码仓库,我们经常会用到.但有时候我们不能直接通过网络链接它,只能通过代理. 这里我有一台代理服务器,起初我以为在终端设置了代理环境就行了,其设置为在你的~/.bas ...

  4. 开源的PaaS方案:在OpenStack上部署CloudFoundry (三)部署BOSH

    BOSH是CloudFoundry提供的用来安装部署和升级CloudFoundry的自动化工具,可是说是CloudFoundry的一部分.总体来说,BOSH是Client/Server结构, BOSH ...

  5. Excel打开csv文件乱码问题的解决办法

    excel打开csv 出现乱码怎么解决 https://jingyan.baidu.com/article/ac6a9a5e4c681b2b653eacf1.html CSV是逗号分隔值的英文缩写,通 ...

  6. Linux学习之批量修改文件名

    1. 通过专业的改名命令rename实现 [root@oldboy oldboy]# ll total -rw-r--r-- root root Nov : stu_102999_1_finished ...

  7. 删除编辑文件警告Swap file “…” already exists!

    Linux下多个用户同时编辑一个文件,或编辑时非正常关闭,再下次编辑打开文件时均为显示如下警告信息: Swap file "test.xml.swp" already exists ...

  8. 解决jquery在IE下removeAttr不生效的问题

    使用jquery动态操纵DOM的时候在IE下会遇到remvoeAttr() 不生效的问题, 解决的办法是使用prop()方法: var node = $("div>input" ...

  9. [分享]收集的Linux学习资源

    下面是我收集的一些Linux资源,与大家分享.大家共同学习,一起进步. 国内的专业Linux网站(GB) 1. ChinaUnix:http://www.chinaunix.net/ 2. Linux ...

  10. 从零打造在线网盘系统之Struts2框架核心功能全解析

    欢迎浏览Java工程师SSH教程从零打造在线网盘系统系列教程,本系列教程将会使用SSH(Struts2+Spring+Hibernate)打造一个在线网盘系统,本系列教程是从零开始,所以会详细以及着重 ...