在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个图片之间的特征匹配关系,也包括确信值
运算之后,需要获得的是在这些所有的关系中,所有对都符合条件的,但是相互之间不想交的对的集合。并且把最大的那个打印出来。