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


论文解释为:


 

Stitching模块中leaveBiggestComponent初步研究_并查集




Stitching模块中leaveBiggestComponent初步研究_ide_02



对应的函数为:


​​:      :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初步研究_ide_03


运算之后,需要获得的是在这些所有的关系中,所有对都符合条件的,但是相互之间不想交的对的集合。并且把最大的那个打印出来。