9.2.2 Python图像处理之图像数学形态学-二值形态学应用-目标检测(击中与击不中)
1 算法原理
采用击中与击不中来进行目标检测
击中击不中变换定义
击中击不中变换(HMT)需要两个结构元素B1和B2,合成一个结构元素对B=(B1,B2)。一个用于探测图像内部,作为击中部分;另一个用于探测图像外部,作为击不中部分。显然,B1和B2是不应该相连接的,即B1∩B2=Φ。击中击不中变换的数学表达式为:
g(x, y)=hitmiss[f(x, y), B]=erode[f(x, y), B1]AND erode[fc(x, y), B2]
其中,fc(x,y)表示的是f(x,y)的补集。
Hit-miss示意图:
已知A,B:在A图中寻找B图所示的图像目标的位置。
4步:
1 确定结构元素
既然是寻找图B所示形状,选取H为图B所示的形状。再选一个小窗口W,W包含H,M=W-H。如下图所示:
2,求H对待检测A的腐蚀
3、求M对A补集的腐蚀
4、求2,3步
结果的交集得到目标图案的位置
2 代码
运行代码说明
1.要改变代码中的图片地址(地址不能有中文)
更改65-66行的图片地址
2.注意最后的
plt.savefig('1.new.jpg')
是保存plt图像,如果不使用可以注释掉代码依赖包:
matplotlib 3.4.2 numpy 1.20.3 opencv-python 4.1.2.30
# pip安装 pip install matplotlib numpy opencv-python
import cv2
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
def plt_show_opcv(title, image):
'''
显示结果图像,只有一个图像
:param title:
:param image:
:return:
'''
if image.shape.__len__() == 3:
plt.imshow(image[:, :, ::-1])
else:
plt.imshow(image, cmap='gray')
plt.title(title)
plt.savefig(title + "Target_Detection.jpg")
plt.show()
def pme(titles, images, rc=None):
'''
显示多张图像在一个画布
:param titles:
:param images:要显示图像的列表
:param rc:
:return:
'''
row = None
col = None
if rc is None:
length = len(titles)
row = int(np.sqrt(length))
col = int(length / row)
if length - row - col > 0:
row += 1
else:
row = rc[0]
col = rc[1]
for i in range(len(titles)):
plt.subplot(row, col, i + 1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.savefig(titles[1]+"Target_Detection.jpg")
plt.show()
def hmt(a, b):
b1 = ~b # 补集
b2 = b
a1 = ~a
a2 = a
pme(["原图补集", "原图", "目标图形补集", "目标图形原图"],[a1, a2,b1, b2])
x1_erode_b1 = cv2.erode(a1, b1)# 补集腐蚀
x2_erode_b2 = cv2.erode(a2, b2) # 正常腐蚀
r = cv2.bitwise_and(x1_erode_b1, x2_erode_b2)
pme(['补集之间腐蚀', '正常图像腐蚀',"最后腐蚀结果"], [x1_erode_b1, x2_erode_b2,r])
return r
image_X = cv2.imread("jiance2.png", 0) # 待检测的图像
image_B = cv2.imread("shuzi2.png", 0) # 模板图像
ret1, image_X = cv2.threshold(image_X, 127, 255, cv2.THRESH_BINARY)
ret2, image_B = cv2.threshold(image_B, 127, 255, cv2.THRESH_BINARY)
re = hmt(image_X, image_B)
targets = []
for i in range(re.shape[0]):
for j in range(re.shape[1]):
if re[i][j]:
targets.append((j, i))
print(i, j)
for target in targets:
image_X = cv2.drawMarker(image_X, target, 125, markerType=cv2.MARKER_CROSS, markerSize=20, thickness=3)
plt_show_opcv("十字标记目标", image_X)
3 效果
使用击中与击不中原理来检测目标,这个我只在方方正正的目标和图像中实现了,其他复杂图像没能成功。
我实验的待检测的图片,左上角的黑色正方形是要检测的目标图案
模板图案:
结果图像
原图Target_Detection.jpg
正常图像腐蚀Target_Detection.jpg
目标结果图像