1.簡述
在實現多圖像無序輸入的拼接中,我們先使用surf算法對任意兩幅圖像進行特徵點匹配,每對圖像的匹配都有一個置信度confidence參數,來衡量兩幅圖匹配的可信度,當confidence>conf_threshold,我們就認爲這兩幅圖可以拼接,屬於一個全景拼接的集合,然後擴展這個集合就可以確定最大的可拼接集合,排除一些無效的圖像,然後進行後續的拼接。
並查集的定義就是並查集是一種樹型的數據結構,用於處理一些不相交集合(Disjoint Sets)的合併及查詢問題。即將屬於相同集合的元素合併起來,中間需要查找某個元素屬於哪個集合,然後需要將兩個元素或者集合進行合併處理。
2.結構體及函數定義
下面我們介紹opencv_stitching中使用的互斥集結構和函數的定義
class DisjointSets
{
public:
//互斥集初始化,元素個數是elem_count
DisjointSets(int elem_count = 0) { createOneElemSets(elem_count); }
void createOneElemSets(int elem_count);//創建互斥集
int findSetByElem(int elem);//查找元素所屬的集合
int mergeSets(int set1, int set2);//合併兩個集合
std::vector<int> parent;//元素所屬集合 parent[elem] = set ,元素elem的集合是set
std::vector<int> size;//集合的包含的元素個數 size[set] = set_size,集合set的元素數是set_size
private:
std::vector<int> rank_;//rank_[set] = rank,集合set標記
};
/************************************************************************/
/*
創建一個互斥集,尺寸爲n
%參數 int n,輸入互斥集的尺寸
*/
/************************************************************************/
void DisjointSets::createOneElemSets(int n)
{
rank_.assign(n, 0);//設置rank_長度爲n,初始值爲0
size.assign(n, 1);//設置size長度爲n,初始值爲1
parent.resize(n);//設置parent的長度爲n
for (int i = 0; i < n; ++i)
parent[i] = i;//parent[elem] = set,初始化每個元素所在的集合
}
/************************************************************************/
/*
查找元素所在的集合
%參數int elem 輸入元素
*/
/************************************************************************/
int DisjointSets::findSetByElem(int elem)
{
//由於互斥集也是樹形結構,所以需要向上遞歸到根節點,即元素所屬的最終集合
int set = elem;
while (set != parent[set])//如果元素的值與所屬集合的值不相同,說明元素是經過集合合併過的,所以要繼續向上遞歸
set = parent[set];
int next;
while (elem != parent[elem])//將之前所有的遞歸過的元素的集合全改成最終的根節點集合
{
next = parent[elem];
parent[elem] = set;
elem = next;
}
return set;
}
/************************************************************************/
/*
合併兩個集合
%參數int set1,int set2 兩個集合set1和set2
*/
/************************************************************************/
int DisjointSets::mergeSets(int set1, int set2)
{
//比較兩個集合的rank_,將rank_值小的集合合併到值大的集合中
if (rank_[set1] < rank_[set2])
{
parent[set1] = set2;
size[set2] += size[set1];
return set2;
}
if (rank_[set2] < rank_[set1])
{
parent[set2] = set1;
size[set1] += size[set2];
return set1;
}
//如果rank_相等,則默認將set1合併到set2中,set2的rank_值+1
parent[set1] = set2;
rank_[set2]++;
size[set2] += size[set1];
return set2;
}
模擬程序:
#include "astdio.h"
#include "disjointset.h"
#define conf_threshold 90
#define num_images 10
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);
}
輸出結果: