形态学图像处理之连通分量提取

基本概念

        提取连通分量的过程实际上也是标注连通分量的过程,通常的做法是给原图像中的每个连通区分配一个唯一代表该区域的编号,在输出图像中该连通区内的所有的像素值就赋值为该区域的编号,我们将这样的输出图像称为标注图像。这里介绍一种基于形态学的膨胀操作的提取连通分量的方法。
在这里插入图片描述
        以8连通的情况为例,对于图(a)的内含多个连通分量的图像A,从仅为连通分量A1内部某个的图像B开始,不断采用如图©所示的结构S进行膨胀。由于其他连通分量与A1之间至少有一条一像素宽的空白缝隙(如图(a)中的虚线),3*3的结构元素保证了只要B在区域A1内部,则每次膨胀都不会产生位于图像A中其他连通区域之内的点,这样只需用每次膨胀后的结构图像和原始图像A相交,就能把膨胀限制在A1内部。随着对B的不断膨胀,B的区域不断生长,但每次膨胀后与图像A的相交又将B限制在连通分量A1地内部,直到最终B充满整个连通分量A1,对连通分量A1地提取完毕。
在这里插入图片描述

示例演示

        我们用OpenCV实现连通分量提取函数,然后进行细菌计数。完整工程代码。

/*
 *only process binary image
 *iseight = true means eight connected, otherwise four connected
*/
int LabelConnectedComponent(const cv::Mat &src, cv::Mat &dst, bool iseight = true)
{
    Mat structelement;
    if(iseight)
        structelement = getStructuringElement(MORPH_RECT, Size(3, 3));
    else
         structelement = getStructuringElement(MORPH_CROSS, Size(3, 3));

    dst = Mat::ones(src.size(), src.type());
    Mat tmp = Mat::ones(src.size(), src.type()); // save last reuslt image
    Mat img = Mat::ones(src.size(), src.type()); //image B
    int labelnum = 0; //label of connected component

    Mat backupsrc;
    src.copyTo(backupsrc);
    for(int i = 0; i < backupsrc.rows; i++)
    {
        for(int j = 0; j < backupsrc.cols; j++)
        {
            if(backupsrc.at<uchar>(i, j) == 255)
            {
                Mat img = Mat::ones(src.size(), src.type());
                img.at<uchar>(i, j) = 255;
                img.copyTo(tmp);  //Temporary save
                labelnum++;

                while(true)  // until not change
                {
                    cv::dilate(img, img, structelement);
                    bitwise_and(img, src, img);
                    //if img do not change, this connected component is finished
                    if (cv::countNonZero(img - tmp) == 0)
                        break;
                    img.copyTo(tmp);
                }


                //label the connected component
                for(int r = 0; r < img.rows; r++)
                {
                    for(int c = 0; c < img.cols; c++)
                    {
                        if(img.at<uchar>(r, c) == 255)
                        {
                            backupsrc.at<uchar>(r, c) = 0;
                            dst.at<uchar>(r, c) = labelnum;
                        }
                    }
                }
            }
        }
    }
    return labelnum;
}

        先对原始图像进行膨胀
在这里插入图片描述
        然后进行细菌统计,实际的细菌个数为21。
在这里插入图片描述

  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二值图像连通分量提取可以通过以下步骤实现: 1. 定义一个函数模块,用于提取连通分量。该函数会改变传入的图像,因此建议在传参前拷贝图像或传入copy图像。该函数返回两个参数,一个是各个连通分量包含的像素点数,一个是对应连通分量的图像。 2. 在循环中,判断图像中是否存在前景目标。如果不存在,则说明连通分量提取完毕。 3. 获取前景像素的横坐标,并用上一步迭代的结果判断当前连通分量是否与上一次相同,以确定迭代过程是否结束。 4. 对当前连通分量进行膨胀,并与原图求交集,判断是否满足内部迭代结束条件。如果满足,则将提取连通分量图保存到img_pixels中,并将src***任意的初始值赋值给canvas,提取下一次的连通分量。 以下是Python代码示例: ```python import numpy as np import cv2 def extract_connected_components(img): num_pixels = [] img_pixels = [] canvas = np.zeros_like(img) while img.any(): x, y = np.where(img > 0) xk = np.column_stack((x, y)) if len(xk) == 0: break if len(num_pixels) > 0 and len(xk) == len(num_pixels[-1]): break canvas.fill(0) for i in range(len(xk)): cv2.circle(canvas, (y[i], x[i]), 1, 255, -1) while True: tmp = canvas.copy() canvas = cv2.dilate(canvas, np.ones((3, 3), np.uint8), iterations=1) canvas = cv2.bitwise_and(canvas, img) if (tmp == canvas).all(): break if (tmp == canvas).all(): img_pixels.append(canvas) num_pixels.append(len(xk)) img = cv2.bitwise_xor(img, canvas) else: break return num_pixels, img_pixels ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值