【Panoramic stitching】并查集(disjoint set)结构及源码

1.简述 

       在实现多图像无序输入的拼接中,我们先使用surf算法对任意两幅图像进行特征点匹配,每对图像的匹配都有一个置信度confidence参数,来衡量两幅图匹配的可信度,当confidence>conf_threshold,我们就认为这两幅图可以拼接,属于一个全景拼接的集合,然后扩展这个集合就可以确定最大的可拼接集合,排除一些无效的图像,然后进行后续的拼接。

      并查集的定义就是并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。即将属于相同集合的元素合并起来,中间需要查找某个元素属于哪个集合,然后需要将两个元素或者集合进行合并处理。

2.结构体及函数定义

下面我们介绍opencv的stitching_detailed.cpp中使用的互斥集结构和函数的定义
class CV_EXPORTS 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 "util.hpp"
#include <iostream>
#include <time.h>
#include <vector>
#include <stdlib.h>//srand()、rand()
#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);

}



输出结果:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值