老猿关于HTM变换的博文目录请见:
https://blog.csdn.net/LaoYuanPython/article/details/110676764 OpenCV-Python击中击不中HITMISS形态变换详解
本文介绍内容大部分源于OpenCV官方资料,与《OpenCV击中击不中HITMISS形态变换公开资料汇总 https://blog.csdn.net/LaoYuanPython/article/details/110676941》中部分博文内容存在交叉,但老猿将尽量包含更多的内容。
击中击不中变换(Hit-or-Miss transform 或 Hit-and-Miss transform,简称HMT变换),用于在二值图像中查找给定的结构或模式,它也是更高级的形态学操作(如细化或修剪)的基础。在OpenCV-Python中,击中击不中变换使用与腐蚀、膨胀等运算相同的函数morphologyEx,具体函数介绍请参考《OpenCV-Python图像形态变换概述及morphologyEx函数介绍 https://blog.csdn.net/LaoYuanPython/article/details/109556425》有关介绍。
形态变换运算根据图像的形状来处理图像,这些运算使用一个或多个结构元素(老猿前面都称为核矩阵)作用于输入图像以获得输出图像,前面介绍的腐蚀和膨胀就是两个最基本的形态变换运算,二者的组合会形成更多高阶形态变换运算,击中击不中变换是基于两次腐蚀组合形成的形态变换运算。
腐蚀运算的腐蚀过程相当于对可以填入结构元素的位置作标记的过程。腐蚀时,虽然标记点取决于锚点在结构元素中的相对位置,但输出图像的形状与此无关,改变锚点的位置,只会导致输出结果发生平移。由于腐蚀的过程相当于对可以填入结构元素的位置作标记的过程,因此可以利用腐蚀标记的内容来确定目标的位置,这就是击中击不中变换模式匹配后面的原理,因此击中击不中变换是形态学中用来检测特定形状所处位置的一个基本工具。
击中击不中变换用于在二值图像中查找由结构元素矩阵指定特征(如单个像素、颗粒中交叉或纵向的特征、直角边缘或其他用户自定义的特征等)的图像模式,不过特殊的是,击中击不中变换进行目标检测时,既要检测到目标的内部,也要检测到外部,即在一次运算中可以同时捕获内外标记。
击中击不中变换使用了两个结构元素B1和B2,要求在目标图像中查找与B1形状匹配且和B2形状不匹配的图像内容,B1用于探测图像内部,作为击中部分,B2用于探测图像外部,作为击不中部分。显然,B1和B2是不应该相连接的,即B1∩B2=Φ。从数学上讲,使用结构元素B1和B2的并集B(B称为复合结构元素)应用于图像A的运算可以表示为:
上述公式可以解释为如下步骤:
上述运算过程中B1为击中使用核,B2为击不中使用核。
击中击不中变换实际上是先在图像A中,寻找满足第一个结构元素B1模式的结构,找到之后相当于“击中”。然后用第二个结构元素B2,直接在原图击中的位置进行匹配,如果不匹配,也就是“击不中”。如果满足以上两点,就是我们要找的结构形状,把其与核锚点对应的中心像素置为255,作为输出。
下面以一个输入图像矩阵和使用不同的结构元素核来图解说明击中击不中变换。
上述三个图例中,第一个是击中使用核,第二个为击不中使用核,第三个为前两个核的组合叠加。在这个案例中,击中核表示的是需要查找中心位置像素为背景(值0对应黑色,在OpenCV中表示背景色),其上下左右四个像素为前景(非0表示前景),核的其他位置的像素无需关注,可以是0或1。
使用上面的核和输入图像进行击中击不中变换,最后的输出图像是矩阵为:
下面是上面输入图像矩阵使用另外两种核的输出图像矩阵案例:
从上述案例可以看出,击中击不中变换的结果图像矩阵保留的像素,是这些像素与核矩阵锚点重合后周边像素与核矩阵像素完全匹配的那些像素。
上面第一个案例使用OpenCV-python实现的代码如下:
import cv2 as cv
import numpy as np
input_image = np.array((
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 255, 255, 255, 0, 0, 0, 255],
[0, 255, 255, 255, 0, 0, 0, 0],
[0, 255, 255, 255, 0, 255, 0, 0],
[0, 0, 255, 0, 0, 0, 0, 0],
[0, 0, 255, 0, 0, 255, 255, 0],
[0,255, 0, 255, 0, 0, 255, 0],
[0, 255, 255, 255, 0, 0, 0, 0]), dtype="uint8")
kernel = np.array((
[0, 1, 0],
[1, -1, 1],
[0, 1, 0]), dtype="int")
output_image = cv.morphologyEx(input_image, cv.MORPH_HITMISS, kernel)
rate = 50
kernel = (kernel + 1) * 127
kernel = np.uint8(kernel)
kernel = cv.resize(kernel, None, fx = rate, fy = rate, interpolation = cv.INTER_NEAREST)
cv.imshow("kernel", kernel)
cv.moveWindow("kernel", 0, 0)
input_image = cv.resize(input_image, None, fx = rate, fy = rate, interpolation = cv.INTER_NEAREST)
cv.imshow("Original", input_image)
cv.moveWindow("Original", 0, 200)
output_image = cv.resize(output_image, None , fx = rate, fy = rate, interpolation = cv.INTER_NEAREST)
cv.imshow("Hit or Miss", output_image)
cv.moveWindow("Hit or Miss", 500, 200)
cv.waitKey(0)
cv.destroyAllWindows()
执行后显示图像如下:
通过上述案例及实现的代码,可以看到几点:
1、代表结构元素的核矩阵元素为int类型,而不是UINT类型;
2、在OpenCV中变换仅使用了一个结构元素,具体关于结构元素的使用和构造将在后续博文中详细介绍。
本节基于OpenCV官方文档基础之上,介绍了击中击不中HITMISS变换处理的原理、算法、图解案例以及案例实现,击中击不中HITMISS变换处理是通过两次腐蚀查找图像内部特定的形状。
老猿在学习这部分内容时,考虑到OpenCV的实现时发现这里有如下几个问题:
这些问题将在后续的博文中回答,在此先留一个悬疑。
https://blog.csdn.net/LaoYuanPython/article/details/110676764 OpenCV-Python击中击不中HITMISS形态变换详解
如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!
更多OpenCV-Python的介绍请参考专栏《OpenCV-Python图形图像处理 》
专栏网址:https://blog.csdn.net/laoyuanpython/category_9979286.html
前两个专栏都适合有一定Python基础但无相关知识的小白读者学习,第三个专栏请大家结合《OpenCV-Python图形图像处理 https://blog.csdn.net/laoyuanpython/category_9979286.html》的学习使用。
对于缺乏Python基础的同仁,可以通过老猿的免费专栏《专栏:Python基础教程目录》(https://blog.csdn.net/laoyuanpython/category_9831699.html)从零开始学习Python。
如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。