给定0-1矩阵求连通域_xunan003的博客-CSDN博客_连通域
求0-1矩阵连通域这篇文章方法讲的算是比较详细,但是程序由于我没学过C++,再加上编程经验很少,这篇博文给出的程序一致没怎么看懂,啃了两天终于有点眉目了,在此做一个总结,也跟小白们分享一下,希望也能对你们有帮助。
求连通域的方法分为三步
第一步:(打开冰箱)对一个二维矩阵,先求出每一行白色团的起始和终止坐标(列),并给每个团标记序列
第二步:合并密接团的标签,鉴别密接的方式是通过轨迹(列)重叠的方式,轨迹重叠,标签归化,若某团与两类不同的团发生密接,代表这两类团等价(初筛阶段以2个为标准),需要统一隔离。
第三步:对等价团进行汇总筛选,凡有交叠的统一归为一类,以此分为不同的感染群类。
给出了三段程序,分别对应上述的三个步骤。
void fillRunVectors(const Mat& bwImage, int& NumberOfRuns, vector& stRun, vector& enRun, vector& rowRun)
void firstPass(vector& stRun, vector& enRun, vector& rowRun, int NumberOfRuns,
vector& runLabels, vector>& equivalences, int offset)
void replaceSameLabel(vector& runLabels, vector>&
equivalence)
第一段程序
拿到每一段程序一定要完全搞清楚程序做了什么事情,是怎么实现的,如果没有详细说明怎么实现的,就需要猜测验证,否则程序会读的很痛苦,就像一篇不认识单词也不知所云的阅读理解。
第一段程序完成每一行白色团的起始和终止坐标,并给每个团标记序列。
1、如何标记坐标
第i行的第j1个点为白色团的起始坐标j2个点为终止坐标,就需要将j1压入start队列中,j2压入end队列中,并对应处其属于第i行。
2、如何分辨起始和终止坐标
起始点(1、第一列为白色像素;2、此列为白色像素,同时左列为黑色像素)
终止点(1、此列为白色色像素,右列为黑色像素;2、最后一列为白色像素)
主体有两个for循环,每个for循环是在循环什么?
i循环行,j循环列,找到起始和终止点的坐标
条件语句是做什么判断(看小括号的内容)?选择后实现什么功能(看大括号最后的结论)?
判断是否为白像素,分别压入了坐标值
NumberofRuns代表白团的数目,rowrun对应每个白团所属的行数
strun代表每个白团的起始坐标,enrun代表每个白团的终止坐标
void fillRunVectors(const Mat& bwImage, int& NumberOfRuns, vector& stRun, vector& enRun, vector& rowRun)
{
for (int i = 0; i < bwImage.rows; i++)
{
const uchar* rowData = bwImage.ptr(i);
if (rowData[0] == 255)
{
NumberOfRuns++;
stRun.push_back(0);
rowRun.push_back(i);
}
for (int j = 1; j < bwImage.cols; j++)
{
if (rowData[j - 1] == 0 && rowData[j] == 255)
{
NumberOfRuns++;
stRun.push_back(j);
rowRun.push_back(i);
}
else if (rowData[j - 1] == 255 && rowData[j] == 0)
{
enRun.push_back(j - 1);
}
}
if (rowData[bwImage.cols - 1])
{
enRun.push_back(bwImage.cols - 1);
}
}
}
第二段程序
依旧是按照上面的四个步骤
一、firstPass函数完成团的标记与等价对列表的生成
a、第一行的团,分别给出标号;
b1、对于除了第一行外的所有行里的团,如果它与前一行中的所有团都没有重合区域,则给它一个新的标号;
b2、如果它仅与上一行中一个团有重合区域,则将上一行的那个团的标号赋给它;
b3、上一行的2个以上的团有重叠区域,则给当前团赋一个相连团的最小标号,并将上一行的这几个团的标记分别写入等价对,说明它们属于一类(等价对是两个团之间的)
1、如何判定相邻行的两个团有重合?
根据两个团的起始和终点列标重合情况进行判断,curstart>preend&curend 二、依旧存在两个嵌套的for循环 for循环实现遍历的功能,根据循环的上限可以提示循环的对象 这一段功能需要遍历所有的团,读取每个团的起始和终止坐标 需要遍历上一行所有的团,读取上一行每个团的起始和终止坐标 将二者信息比对进行重叠判断 第一个条件句实现递归内容的更新替换(上一行内容更新) 第二个条件句实现重复判定,并对团进行标号,生成等价对 三、大胆猜测小心求证每个变量的含义 strun代表团的起始坐标,enrun代表终止坐标,rowrun代表团对应的行数,currowidx代表当前判断行的行数,runlabels代表团的标记,equivalence存储等价对 第三段程序 一、对等价对的处理,需要将它转化为若干个等价序列 比如有如下等价对: (1,2),(1,6),(3,7),(9-3),(8,1),(8,10),(11,5),(11,8),(11,12),(11,13),(11,14),(15,11) 我们需要得到最终序列是: 1-2-5-6-8-10-11-12-13-14-15 3-7-9 4 采用方法是图像深入优先遍历的原理,进行等价序列的查找。 不要着急读程序,先把方法对应的原理吃透,否则读程序会读得很痛苦,看似已经开始了,其实磕磕绊绊地读不下去,理解不了,也不要一个字一个字的读程序(就像英语阅读理解一样),要按照结构和功能读程序。 图像深入优先遍历原理 找到所有团V对应等价(有链接关系)的团W,以及V的相对于W的下一个邻接点。 参考文献: 图的遍历:深度优先遍历(DFS)_Uncertainty!!的博客-CSDN博客_深度优先遍历 二、根据深入优先遍历原理,寻找连通域的过程就需要进行这样几个嵌套的遍历过程。 首先需要遍历所有团(矩阵列自上到下);需要遍历与某个团等价的团(矩阵行自左到右);还需要遍历与这个等价团邻接的等价团(矩阵列自上到下) 分别对应i 三、猜测每个变量的含义 maxLabel代表图数,eqTab代表等价对矩阵,vecPairIt代表循环器,作用是遍历整个eqTab labelFlag代表团所属与的类,tempList代表暂时一类的等价序列,equaList代表最终的等价序列 1、if(a);如果a为真就继续,这里的真包括非0数字和字符。 2、vector 3、iterator vecPairIt C++迭代器iterator详解_C 语言_脚本之家 (jb51.net) 4、vecPairIt-> (1条消息) C中的->透析_范红康的博客-CSDN博客 5、eqTab[vecPairIt->first - 1][vecPairIt->second - 1](1条消息) c++ 里面的map容器的迭代器 first second_imik的博客-CSDN博客_map的first和second 6、 vector 7、"&&"、"||"和"!"。a && b,一假必假,结合性从左至右。||是逻辑或运算符,a || b,一真必真,结合性从左至右,&&!是要&&左边成立且右边不成立才成立; 结束,为什么感觉这么小的程序就好难,5555,开始怀疑适不适合干图像算法,加油呀小猴! 最后感谢在解决问题过程中各位大佬的帮助,如果我的回答帮助到你,还麻烦给我点赞加油呀~~ void firstPass(vector
void replaceSameLabel(vector
PS:程序理解的一些小问题记录