1. 程式人生 > >全景視訊拼接(三)--並查集法及原始碼分析

全景視訊拼接(三)--並查集法及原始碼分析

原文:

 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);

}


輸出結果: