在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. Mybatis返回map集合

    <resultMap id="pieMap" type="HashMap"> <result property="value&quo ...

  2. poj_2195 最小费用最大流

    题目大意 一个nxm的地图,地图上的横纵交错成nxm个交叉点,其中有k个交叉点为房间,k个交叉点为k个小人的初始位置.小人可以在地图上沿着水平或垂直方向行走,每走一步的代价为1.求这k个小人分别到达k ...

  3. tp5 集成 layui富文本编辑器

    编辑器地址:http://www.layui.com/doc/modules/layedit.html 一睹芳容 1 去官网:http://www.layui.com/     下载layui ├─c ...

  4. java高级---->Thread之Condition的使用

    Condition 将 Object 监视器方法(wait.notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set ...

  5. 【 Android】使手机屏幕常亮,不进入待机状态

    Android中,申请WakeLock可以让你的进程持续执行即使手机进入睡眠模式,比较实用的是比如后台有网络功能,可以保证操作持续进行. 需要权限 <uses-permission androi ...

  6. Android通知栏的高度获取

    public static int getStatusBarHeight(Context context){ Class<?> c = null; Object obj = null; F ...

  7. Thrift Expected protocol id ffffff82 but got 0

    如果服务端配的也是noblock=false;客户端不能改成noblock=true;

  8. java 中的& &&区别以及 C++ 中& &&的区别

    java中的 & &&两个运算符 (1).&在java中称做: 逻辑与 判断boolean类型,只有两者都是true时,才会返回true 举例: boolean b1= ...

  9. Pandas使用to_csv保存中文数据用Excel打开是乱码

    关于这个问题还是困扰了很久,我生成了一些样本数据,打算保存到csv文件,之后用pandas的命令: # data是DataFrame的格式 data.to_csv('./data/myfile.csv ...

  10. Chinese_remainder_theorem

    https://en.wikipedia.org/wiki/Chinese_remainder_theorem 中国剩余定理 https://en.wikipedia.org/wiki/RSA_(cr ...