书名:数字图像处理实战
作者:杨坦 张良均
出版社:人民邮电出版社有限公司
出版时间:2023-11-01
ISBN:9787115623850
第9章 钢轨表面缺陷检测
9.4 基于区域生长算法的钢轨表面缺陷检测
- 经过9.3节中的预处理,原始图像变为只包含个别深色连通区域且背景为白色的图像。接下来要判断保留下来的连通区域是否对应钢轨表面的疤痕类缺陷。
9.4.1 种子点的提取
1、灰度直方图
- 为了考察缺陷区域的特征,本小节利用数据集中提供的掩模图像,绘制缺陷区域像素的灰度直方图,以此来明确判断标准。
先将灰度形式的掩模图像转换为布尔型数组,然后使用布尔型数组来引用图像中被标记为缺陷的像素,再使用自定义函数plt_hist绘制缺陷区域像素的灰度直方图,如代码9-5所示。
import matplotlib.pyplot as plt
mask = cv2.imread(mask_path)
img = cv2.imread(Rail_surface_image_path)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #转灰度图
mask_gray = cv2.cvtColor(mask, cV2.COLOR BGR2GRAY)
img_gray = img_gray.T
mask_gray = mask_gray.T
def plt hist(img):
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.hist(img.ravel(), 256,[0,80])
ax.set title('rail_' + str(picture label) + ' gray plot')
fig.savefig('../tmp/' + str(picture_label) + 'gray.png',dpi=400)
plt.show()
mask_bool = np.where(mask_gray > 20, True, False)
plt_hist(img_gray[mask_bool])
img_gray2 = np.where(mask_bool, img_gray, 255)
cv2.imshow('rail ' + str(picture label), img_gray2)
cv2.waitKey(0)
cv2.destroyAllwindows()
-
根据数据集所提供的掩模,在原图中统计缺陷对应位置的像素灰度,所得灰度值直方图如图9-9所示。
2、不同图像缺陷处的灰度值直方图
-
进一步,在代码9-1中修改要读取的图像标签值再运行代码9-5所示代码,可得到不同图像缺陷处的灰度值直方图,如图9-10所示,以此得出普遍适用的缺陷区域灰度特征。
3、统计归纳出表面缺陷的灰度值
- 观察了几幅图像中不同缺陷区域的像素灰度值直方图后,可以发现疤痕类钢轨表面缺陷的灰度值直方图的峰值都集中在20左右,即缺陷内必定存在灰度值在25以下的像素点。
由此可见I型RSDDs数据集的质量较高,很好地控制了采集装置中的光源强度和光线入射角度,避免疤痕类缺陷内部被光线直接照射,使得缺陷区域的像素灰度值稳定地保持在一个较小的区间内。
4、寻找种子点
- 得到缺陷区域中一定存在灰度值小于25的像素这个先验知识,就可以利用它在去除背景后得到的连通区域内部寻找满足条件的点,作为缺陷区域的种子点,如代码9-6所示。
每一个连通区域中只寻找一个符合灰度阈值的种子点,而一幅图像可能包含多个不同的连通区域,代码9-6中使用字典结构存储对应的连通区域的种子点集合。
# 寻我初始种于点集合
# 先找到所有灰度值在25 以下的像素点,然后将在同一个连通区域的点去除
# 每一个连通区域只保留一个种子
zhongzi_dict = []
zhongz_yuzhi = 25
for i in range(len(img_gray)):
for j in range(len(img_gray[0])):
if img_gray4[i][j]< zhongzi_yuzhi:
# 找到一个符合条件的点后,将该点添加至字典内,键值为所在连通区域的编号
if str(img_flag[i][j]) not in zhongzi dict:
# 判断该连通区域在字典内是否存在符合条件的点
zhongzi_dict[str(img_flag[i][j])]= []
zhongz_dict[str(img_flag[il[jl)].append([i, j])
# 得到了连通区域与内部可用种子点的对应关系后,每个连通区域只保留1个种子点
print('连通区域数量为: [0]'.format(len(zhongzi_dict.keys())))
# 每个连通区域选择的种子点最好在连通区域中心
zhongzi =[]
# for i in range(Len(zhongzi dict.keys())):
for i in zhongzi dict.keys():
k = len(zhongzi dict[i]) // 2
zhongzi.append(zhongzi_dict[il[k])
print('选取的种子点为:',zhongzi)
5、代码说明
- 为了不重复在同一个连通区域内多次寻找种子点,代码9-6中使用代码9-4中去除微小连通区域时生成的数组img_flag,该数组标明了每个像素点所属的连通区域的编号。
- 首先对所有像素点的灰度值进行判断,对于灰度值小于阈值25的点,将其连通区域编号保存在种子字典zhongzi_dict中。
- 为了得到每个连通区域中心的种子,接下来计算字典zhongzi_dict中属于每个连通区域的种子数量。
- 根据前面扫描种子的顺序,可以知道位于连通区域中心的种子加入字典zhongzi_dict的位置也大约在中间。
- 在代码的最后,只为每个连通区域保留一个种子,这些种子保存在最终的列表zhongzi中。
选取样本图像rail_2,如图9-11所示。经过代码9-5所示代码处理后保留了两个连通区域,都包含灰度值小于25的像素点,运行代码9-6所示代码将输出如下内容。