基于连通域标记的目标数字分割

本文介绍了使用传统图像处理技术进行二值图像的连通域标记和数字分割。首先,通过读取图像、去噪、生成背景图、获取前景图、二值化等步骤预处理图像。然后,利用连通域标记对前景物体进行分割,并通过分析连通域的面积分布,进一步提取出单独的数字。最后,通过面积阈值分离出不同数字,展示了数字1、7、4、3/5/9和8/0/2/6/9的连通域图像。整个过程详细展示了如何利用Python和OpenCV实现这一目标。
摘要由CSDN通过智能技术生成

1 引言

最近使用传统方法应用于实际生活中的问题,受到了大家一致的关注。
嗯嗯,应该是一致的关注。
那么我们今天来研究一个新的好玩的方向,就是基于二值图像进行连通域标记和分析,从而解决数字分割的问题。
问题描述:

从下图左侧图像中,分割出数字1的图像,如右侧所示:
请添加图片描述
嗯捏。。。
先思考2分钟,然后我们用python来一步一步实现吧。。。

2 解决方案

2.1 读取图像

这里我们直接读取灰度图像,需要注意的是需要将其转化为float型数据.
这是因为我们后面有些操作可能会将像素值超过[0,255]范围,
代码如下:

image = cv2.imread(image_file, cv2.IMREAD_GRAYSCALE)
image = image.astype(np.float32)

结果如下:

请添加图片描述

2.2 去噪

这里我们使用一些滤波器(低通滤波器,保留低频噪声,滤除高频噪声).
以下为opencv中常用的去噪函数:

ksize = 5 # Some odd integer
blurred_image = cv2.blur(image, (ksize, ksize)) # Mean blur
blurred_image = cv2.GaussianBlur(image, (ksize, ksize), 0)
blurred_image = cv2.medianBlur(image, ksize)
blurred_image = cv2.biliteralFilter(imag, 9, 75, 75) # Read the docs

这里经过尝试,我们选用高斯滤波器,kernel size = 5 ,代码如下:

nr_image = cv2.GaussianBlur(image, (5, 5), 0)

结果如下:

请添加图片描述

2.3 生成背景图

我们发现上图中,光照不均匀,有的区域偏亮,有的区域偏暗,这里我们采用大 kernel size的滤波器来生成背景图.
经过尝试发现使用 kernel size=21的高斯滤波器依然工作良好.
相应代码如下:

background = cv2.GaussianBlur(nr_image, (21, 21), 0)

结果如下:

请添加图片描述

2.4 获取前景图

直接使用减法,原图减去背景取可以得到前景图,但是前景图的像素值均接近于0,这里采用归一化在缩放的方式将结果重新映射回去.
代码如下:

br_image = nr_image - background
br_image = 255*(br_image - np.min(br_image)) / (np.max(br_image) - np.min(br_image))
br_image = br_image.astype(np.uint8)

结果如下:

请添加图片描述
上图为我们获取的前景图,可以看出此时图像整体亮度相比之前趋于均衡.

2.5 二值化

为了获取合适的阈值,这里我们首先查看上图图像的灰度直方图,然后从中选择合适的阈值.
灰度直方图如下:

请添加图片描述

观察上图,直方图中间有一个大的尖峰,可以看作大部分为背景的像素点数.
我们感兴趣的前景物体相比背景更暗,所以我们选择保留该阈值下的像素点,同时我们需要将图像由 bool 型转换为 int 型方便后续使用.代码如下:

threshold = 149
thr_image = (br_image < threshold).astype(np.uint8)

结果如下:
请添加图片描述
需要注意的是上图中背景为黑色,我们感兴趣的前景区域为白色.

2.6 连通域标记

接下来我们使用 opencv 中的函数connectedComponentsWithStats 对上图进行连通域标记,
代码如下:

connectivity = 4
output = cv2.connectedComponentsWithStats(thr_image.astype(np.uint8),
                                          connectivity,
                                          cv2.CV_32S)
num_labels = output[0]
label_image = output[1] # Image with a unique label for each connected region
stats = output[2]
centroids = output[3] # Centroid indices for each connected region

函数解释如下:

  • input: connectivity 连通域,默认为8连通,这里我们选择4连通
  • input: cv2.CV_32S 表示输出labels类型
  • output: num_labels 表示标记出的连通域的数量
  • output: label_image 表示输出标记的图像
  • output: stats 统计信息,每个区域的位置 宽高和面积
  • output: centroids 每隔区域的中心位置坐标 cx xy

2.7 可视化

通过上述连通域标记,我们得到了好多返回值,这里我们需要重点关注的为label_image 以及 stats .其中, label_image和输入shape一样,为标记后的图像,该图像中每个连通域均被标记为唯一的一个label.
我们使用以下代码将其可视化:

from skimage.color import label2rgb
fig_num = plot_image(label2rgb(label_image), 'Labels before thresholding', fig_num)

结果如下:
请添加图片描述
同时,stats输出为一个数组,里面包含了每个连通域的统计量,具体如下:

  • stats[:,0]: x,它是连通区域外接框左上角点x坐标
  • stats[:,1]: y,它是连通区域外接框左上角点y坐标
  • stats[:,2]: w,它是连通区域外接框的宽度
  • stats[:,3]: h, 它是连通区域外接框的高度
  • stats[:,4]: Area,它是每个连通区域组件的面积

2.8 分析

接着,我们来分析stats中相关的统计量的具体应用.
1)首先来分析每个连通区域的面积直方图,注意到stats[0,:]表示背景label=0的区域,这时因为相比其他连通区域,背景连通域的面积最大,这里我们将其忽略.
代码如下:

region_area = stats[1:, 4]  # remove index=0 background
fig = plt.figure(fig_num)
plt.hist(region_area, 256,  facecolor='black', alpha=0.75)
plt.xlabel('Region area')

结果如下:

请添加图片描述

上图为前景物体连通域面积分布直方图

2)通过观察上图,我们可以获得以下两条信息:

  • 面积在200以下的区域,对应到图上为前景数字外虚线矩形框每个小虚线区域的面积
  • 面积在200以上的区域,对应到图上为前景每个数字所构成的链接域的面积

基于上述两点我们编写代码实现分离虚线矩形框和相关数字功能,代码如下:

region_area = stats[:, 4]
lower_threshold = 200
upper_threshold = 450
keep_labels = np.where(np.logical_and(stats[:, 4] > lower_threshold,
                                      stats[:, 4] < upper_threshold))
keep_label_image = np.in1d(label_image, keep_labels).reshape(label_image.shape)
ra_thr_image = np.copy(thr_image)
ra_thr_image[keep_label_image] = 255
ra_thr_image[keep_label_image == False] = 0

结果如下:
请添加图片描述

同时,面积在[50-100]的连通域的图像如下:

请添加图片描述

2.9 二次分析

观察上述面积分布直方图,我们可以看出在[200,450]之间存在5个波峰,我们分别将其取出进行可视化,结果如下:
1)连通域面积介于[245,275]之间,对应数字1,图像如下:

请添加图片描述

2)连通域面积介于[275,310]之间,对应数字7,图像如下:

请添加图片描述

3)连通域面积介于[310,340]之间,对应数字4,图像如下:

请添加图片描述

4)连通域面积介于[340,388]之间,对应数字3和5和个别9,此时仅靠面积信息进行区分已经十分困难,图像如下:

请添加图片描述

5)连通域面积介于[388,450]之间,对应剩余数字全部的8,0,2,6以及部分9,图像如下:

请添加图片描述

3 总结

本文介绍了使用传统图像处理方法进行二值图像连通域标记并实现数字分割,最后给出了完整的代码实现.

您学废了吗?

关注公众号《AI算法之道》,获取更多AI算法资讯。
在这里插入图片描述

注: 关注公众号,后台回复 数字 , 可获取完整代码

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵卓不凡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值