手写01矩阵连通域分析

连通域分析其实是一个路径搜索问题,搜索方式就看联通的规则(4联通:上下左右算是联通,8联通:上下左右还有四个对角)

01矩阵背景是0,黑色的,有色区域是1,白色的,从图像的左上角(最外围的边要去掉)进行遍历,将找到的第一个值为1的像素点作为起点,对他进行连通域搜寻,将搜寻到的整个连通域内的像素点标为2(为了避免与本来的颜色1冲突)

继续搜索像素值为1的点(之前联通域分析过的已经将像素值改为大于1的值,所以像素值为1的就是还没有分析过的),直到整个图像遍历完成

 

遍历方法:

找到起点后初始化一个栈,存放连通域的点坐标(pair),将起点的横纵坐标压入栈中,连通域的标记值自增(第一个连通域的标记值为2,从2开始,第二个连通域的标记值为3,以此类推)

当栈不为空时,从栈顶取点,读出他的横纵坐标,在Label图中,根据横纵坐标对连通域进行对应标记值的赋值,然后将该点出栈,同时按照联通规则,根据坐标找到它的相邻像素点,看相邻像素点的值是否为1,如果是1,则是连通域,将这个点入栈(判断时记得要加上边界条件,防止点下标溢出,我的代码偷懒了没有加,正常要加上 0<=Row<BinaryImg.rows&&0<=Col<BinaryImg.cols)

 

代码

void SeedFilling(const Mat &BinaryImg, Mat &LabelImg)
{
    if (BinaryImg.empty || BinaryImg.type() != CV_8UC1)
        return;

    BinaryImg.convertTo(LabelImg, CV_32SC1);

    int Label = 1;// 从2开始,防止和二值图像的像素值重合

    int Row = BinaryImg.rows - 1;
    int Col = BinaryImg.cols - 1;

    for (int i = 1; i < Row; ++i)
    {
        int* data = LabelImg.ptr<int>(i);

        for (int j = 1; j < Col - 1; ++j)
        {
            if (data[j] == 1)
            {
                stack<pair<int, int>> NeighborPixel;
                NeighborPixel.push(pair<int, int>(i, j));

                ++Label;// 新标签

                while (!NeighborPixel.empty)// 栈不为空
                {
                    pair<int, int> CurPixel = NeighborPixel.top();
                    int CurRow = CurPixel.first;
                    int CurCol = CurPixel.second;
                    LabelImg.at<int>(CurRow, CurCol) = Label;
                    NeighborPixel.pop();// 出栈

                    if (LabelImg.at<int>(CurRow, CurCol - 1) == 1)
                        NeighborPixel.push(pair<int, int>(CurRow, CurCol - 1));

                    if (LabelImg.at<int>(CurRow, CurCol + 1) == 1)
                        NeighborPixel.push(pair<int, int>(CurRow, CurCol + 1));

                    if (LabelImg.at<int>(CurRow - 1, CurCol) == 1)
                        NeighborPixel.push(pair<int, int>(CurRow - 1, CurCol));

                    if (LabelImg.at<int>(CurRow + 1, CurCol) == 1)
                        NeighborPixel.push(pair<int, int>(CurRow + 1, CurCol));
                }
            }
        }

        return;
    }
}

 

上一篇:YOLO v4相比较YOLO v3的改进之处


下一篇:路面裂痕检测YOLO算法、目标检测算法实现地面裂缝检测