近来,在进行数字图像处理练习过程中,遇到连通区域标记的问题,网上有很多相关算法的讲解,我参考的是这篇文章,根据作者的讲解,可以很轻易地实现连通域的标记。
本人在进行基于行程的标记处理中第三步——”等价对的合并”时编写简单程序实现。希望能对诸君有所参考。
其中equivalences存放所有等价对,overlap存放所有合并后的结果。
void MergeRuns(vector<pair<int,int>>equivalences, vector<vector<int>>&overlap)
{
for(int i=0; i<equivalences.size();i++)
{
vector<int>cur; //存放当前正在合并的团
//初始化当前合并的团(即把第一个未合并的等价对放入其中)
int first = equivalences[i].first;
int second = equivalences[i].second;
cur.push_back(first);
cur.push_back(second);
//从第一个未合并的等价对之后开始对比判断
for(int j=i+1;j<equivalences.size();j++)
{
int pre_size = cur.size(); //当前合并团在该次合并前的大小
for(int k=0;k<cur.size();k++)
{
//判断当前合并团是否与当前等价对有重叠,
//如果重叠,则将另一团标号放入当前合并团,并跳出循环
if(cur[k] == equivalences[j].first)
{
cur.push_back(equivalences[j].second);
vector<pair<int,int>>::iterator iter = equivalences.begin()+j;
equivalences.erase(iter);
iter = equivalences.begin();
break;
}
else if(cur[k]==equivalences[j].second)
{
cur.push_back(equivalences[j].first);
vector<pair<int,int>>::iterator iter = equivalences.begin()+j;
equivalences.erase(iter);
iter = equivalences.begin();
break;
}
}
//判断此次合并是否有新团标号加入,
//如果是,则需从第一个未合并的等价对之后开始对比判断
if(pre_size!=cur.size())
{
j=i;
}
}
overlap.push_back(cur); //将当前合并完成的团放入结果vector中
}
}
结果如图1所示;
图1 合并结果
然而,这段程序有些许不足之处:
1. 产生的结果没有进行排序(想来不会影响最终标记,便未加优化)
2. 再者,在进行合并时未加入单独团标号,即不存在等价对的团标号,比如本例中的4号。
2017-8-29修改
修改代码,完善不足2,以完成合并单独团标号
//添加参数int label_num,表示团标号最大值
void MergeRuns(vector<pair<int,int>>equivalences, vector<vector<int>>&overlap, int label_num)
{
...
//以上为之前代码,未做修改
//下面为添加无等价对的团标号代码
//处理方式其实很无脑,就是对所有团标号进行查找,
//找到不在合并后的团中的就将其放入结果vector中
for(int i = 0;i<=label_num;i++)
{
for(int j=0;j<overlap.size();j++)
{
int k=0;
for(;k<overlap[j].size();k++)
if(overlap[j][k]==i)
break;
if(k<overlap[j].size())
break;
else if(j==overlap.size()-1)
{
vector<int>cur;
cur.push_back(i);
overlap.push_back(cur);
}
}
}
}
处理方式其实很无脑,就是对所有团标号进行查找,找到不在合并后的团中的就将其放入结果vector中。
结果如图2所示;
图2 修改后的合并结果
这里我的团标号是从0开始计的,因此结果中包含0,是单独团标号。如果从1开始,则将代码中循环起始处修改为1。
抛砖之言,望指教!