全景視訊拼接(三)--並查集法及原始碼分析
阿新 • • 發佈:2019-02-17
原文:
1.簡述
在實現多影象無序輸入的拼接中,我們先使用surf演算法對任意兩幅影象進行特徵點匹配,每對影象的匹配都有一個置信度confidence引數,來衡量兩幅圖匹配的可信度,當confidence>conf_threshold,我們就認為這兩幅圖可以拼接,屬於一個全景拼接的集合,然後擴充套件這個集合就可以確定最大的可拼接集合,排除一些無效的影象,然後進行後續的拼接。
並查集是一種樹型的資料結構,用於處理一些不相交集合(Disjoint Sets)的合併及查詢問題。即將屬於相同集合的元素合併起來,中間需要查詢某個元素屬於哪個集合,然後需要將兩個元素或者集合進行合併處理。
2.結構體及函式定義
下面我們介紹opencv_stitching中使用的互斥集結構和函式的定義
/************************************************************************/ /* 建立一個互斥集,尺寸為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); }
輸出結果: