在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. Android 监听按钮的点击事件

    onClick事件1.Button和ImageButton都拥有一个onClick事件 通过自身的.setOnClickListener(OnClickListener)方法添加点击事件2.所有的控件 ...

  2. LeetCode——Generate Parentheses

    Description: Given n pairs of parentheses, write a function to generate all combinations of well-for ...

  3. Android 跨进程调用忽略权限

    Framework层: @Override    public StackInfo getStackInfo(int stackId) {        final int callingUid = ...

  4. 【BZOJ5082】弗拉格 矩阵乘法

    [BZOJ5082]弗拉格 Description “如果明天进了面试,我就去爆妹子的照”——有妹子的丁相允作为一个oier,自然不能立太多flag,让我们来看一道和flag有关的题目吧 给你n个fl ...

  5. 【BZOJ4424】Cf19E Fairy DFS树

    [BZOJ4424]Cf19E Fairy Description 给定 n 个点,m 条边的无向图,可以从图中删除一条边,问删除哪些边可以使图变成一个二分图. Input 第 1 行包含两个整数 n ...

  6. OC开发_Storyboard——绘制和视图

    1.绘制 不要调用drawRect.调用setNeedsDisplay相当于告知系统视图需要重绘, 它会去调用drawRect,更新屏外缓冲器 2.UIBezierPath绘制图形,   设置图像op ...

  7. 神奇的随机数rand()

    随机数在统计理论中占有很重要的地位,很多应用都需要用到他,系统自带的rand()函数产生的是伪随机数,所以该如何真正的随机数呢? 1.c语言中的时间函数 关于c语言我查到的两个比较好的博文是:http ...

  8. Linux Git服务器安装

    ① 安装 Git ② 服务器端创建 git 用户,用来管理 Git 服务,并为 git 用户设置密码 ③ 服务器端创建 Git 仓库 ④ 客户端 clone 远程仓库 ⑤ 客户端创建 SSH 公钥和私 ...

  9. ASP.NET的页面执行过程

    对于ASP.NET来说,用户访问的页面,都由服务器IIS处理,具体的处理过程如下图: 对于用户模块还是有很多的东西没有写,未完待续...

  10. Oracle等待事件之等待事件详解

    一. 等待事件的相关知识:1.1 等待事件主要可以分为两类:即空闲(IDLE)等待事件和非空闲(NON-IDLE)等待事件.1). 空闲等待事件指ORACLE正等待某种工作,在诊断和优化数据库的时候, ...