您的位置:首页 > 理论基础 > 数据结构算法

【数据结构】【计算机视觉】并查集(disjoint set)结构介绍

2017-11-07 00:32 537 查看


1.简述 

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

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


   2.结构体及函数定义

     下面我们介绍opencv_stitching中使用的互斥集结构和函数的定义

[cpp] view
plain copy

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标记  

};  

[cpp] view
plain copy

/************************************************************************/  

/* 

  创建一个互斥集,尺寸为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;  

}  

  模拟程序:

[cpp] view
plain copy

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

  

}  

输出结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: