本文作者:小嗷
微信公众号:aoxiaoji
吹比QQ群:736854977
微信链接:https://mp.weixin.qq.com/s?__biz=MzU1MTgxNjQyMg==&mid=2247483871&idx=1&sn=d291fddb429e335ca801f7cffb017878&chksm=fb8adc56ccfd554082cb87416d3f95f308302981bcd570161815a70e8ddb47dcf8fa1c8684b3#rd
在本篇中,您将学习如何通过使用“Hit-or-Miss”转换(也称为“Hit-or-Miss”转换)在二进制映像中找到给定的配置或模式。(命中/错过)
这种变换也是更高级的形态学操作的基础,如细化或修剪。
我们将使用OpenCV函数morphologyEx()。
本文你会找到以下问题的答案:
二值图像
结构元素
集合
击中击不中变换(Hit-or-Miss)
convertTo
saturate_cast
moveWindow
2.1 二值图像
二值图像(Binary Image)是指将图像上的每一个像素只有两种可能的取值或灰度等级状态,人们经常用黑白、B&W、单色图像表示二值图像。
二值图像是指在图像中,灰度等级只有两种,也就是说,图像中的任何像素不是0就是1,再无其他过渡的灰度值。
2.2 结构元素
结构元素就是核模块。
上图中间这个模块称为结构元素(专业名词)
2.3 集合
集合是指具有某种特定性质的具体的或抽象的对象汇总成的集体,这些对象称为该集合的元素。
例如全中国人的集合,它的元素就是每一个中国人。
我们通常用大写字母如A,B,S,T,...表示集合,而用小写字母如a,b,x,y,...表示集合的元素。
2.3.1 若x是集合S的元素,则称x属于S,
记为x∈S。
2.3.2 若y不是集合S的元素,则称y不属于S,
记为y∉S。
2.3.3 空集
有一类特殊的集合,它不包含任何元素,如{x|x∈R x²+1=0} ,我们称之为空集,记为∅。
2.3.4 子集
设S,T是两个集合,如果S的所有元素都属于T
则称S是T的子集,记为
2.3.5 相等
如果两个集合S和T的元素完全相同,则称S与T两个集合相等,记为S=T 。显然我们有
2.3.6 并交集
并集定义
并集定义:由所有属于集合A或属于集合B的元素所组成的集合,记作A∪B(或B∪A),读作“A并B”(或“B并A”),即A∪B={x|x∈A,或x∈B}。并集越并越多。
交集定义
由属于A且属于B的相同元素组成的集合,记作A∩B(或B∩A),读作“A交B”(或“B交A”),即A∩B={x|x∈A,且x∈B}。交集越交越少。
若A包含B,则A∩B=B,A∪B=A
2.3.7 补集(重点)
击中击不中需要用到。所以,小嗷就写写集合
相对补集定义:由属于A而不属于B的元素组成的集合,称为B关于A的相对补集,记作A-B或A\B,即A-B={x|x∈A,且x∉B'}。
绝对补集定义:A关于全集合U的相对补集称作A的绝对补集,记作A'或∁u(A)或~A。有U'=Φ;Φ'=U
例如:A的补集
意思就是除了A中的元素外的元素所组成的集合
也就是说A里面有的,A的补集一定没有
A里面没有的,A的补集里一定有
所以A的补集和A的交集是空集
2.3.8 幂集
定义:设有集合A,由集合A所有子集组成的集合,称为集合A的幂集。 定理:有限集A的幂集的基数等于2的有限集A的基数次幂
2.4 击中击不中变换(Hit-or-Miss)理论
形态学运算符根据图像的形状来处理图像。
这些操作符将一个或多个结构化元素应用到输入映像中,以获得输出映像。两个基本的形态学操作是侵蚀和扩张。
这两个操作的组合产生高级形态转换,如打开、关闭或顶帽转换。要了解这些和其他基本的形态学操作的更多信息,请参考以前的教程(第25篇腐蚀和膨胀)和(第27篇更多的形态学转换)。
对于在二值图中查找模式,“Hit-or-Miss”转换非常有用。特别地,它找到了那些邻域与第一个结构元素B1的形状匹配的像素,同时又与第二个结构元素B2的形状不匹配。在数学上,应用于图像A的操作可以表示为:
简单来说:
“Hit-or-Miss”找到那些邻域与B1(核)的形状匹配的像素
“Hit-or-Miss”找到那些邻域与B2(核)的形状不匹配的像素
具体操作:
首先,建立一个比B大的模板W;使用此模板对图像A进行腐蚀,得到图像假设为Process1;
其次,用B减去W,从而得到V模板(W-B);使用V模板对图像A的补集进行腐蚀,得到图像假设为Process2;
然后,Process1与Process2取交集;得到的结果就是B的位置。这里的位置可能不是B的中心位置,要视W-B时对齐的位置而异;
因此,“Hit-or-Miss” 操作包括三个步骤:
用结构元素B1腐蚀图像A(B1等于W)。
用结构元素B2腐蚀图像A (Ac)的补集(B2=B1-B)。
第一步的结果和第二步的结果的交集。
第二步例子,第一步和第三步相对简单就不写(如果不懂就公众号或者QQ邮箱call小嗷)
结构元素B1和B2可以组合成单个元素b。我们来看一个例子:
B1为第一个结构元素,B2为第二个结构元素,b为第三个结构元素(B1-B2=b)
结构元素(内核)。左:内核“击中”。中间:内核“不击中”。右:最后结合内核
在这种情况下,我们正在寻找一种模式,其中的中心像素属于背景,而北部、南部、东部和西部像素属于前景。附近的其他像素可以是任何类型的,我们不关心它们。现在,让我们将这个核应用到一个输入图像:
二值图(原图)
输出二值图像
您可以看到模式只在图像中的一个位置找到255
前面示例对应的代码如下所示。
1#include 2#include 3#include 4using namespace cv; 5int main(){ 6 Mat input_image = (Mat_(8, 8) << 7 0, 0, 0, 0, 0, 0, 0, 0, 8 0, 255, 255, 255, 0, 0, 0, 255, 9 0, 255, 255, 255, 0, 0, 0, 0,10 0, 255, 255, 255, 0, 255, 0, 0,11 0, 0, 255, 0, 0, 0, 0, 0,12 0, 0, 255, 0, 0, 255, 255, 0,13 0, 255, 0, 255, 0, 0, 255, 0,14 0, 255, 255, 255, 0, 0, 0, 0);15 Mat kernel = (Mat_(3, 3) <<16 0, 1, 0,17 1, -1, 1,18 0, 1, 0);19 Mat output_image;20 morphologyEx(input_image, output_image, MORPH_HITMISS, kernel);21 const int rate = 50;22 kernel = (kernel + 1) * 127;23 kernel.convertTo(kernel, CV_8U);24 resize(kernel, kernel, Size(), rate, rate, INTER_NEAREST);25 imshow("kernel", kernel);26 moveWindow("kernel", 0, 0);27 resize(input_image, input_image, Size(), rate, rate, INTER_NEAREST);28 imshow("Original", input_image);29 moveWindow("Original", 0, 200);30 //rate就是用来或大尺寸31 resize(output_image, output_image, Size(), rate, rate, INTER_NEAREST);32 imshow("Hit or Miss", output_image);33 moveWindow("Hit or Miss", 500, 200);34 waitKey(0);35 return 0;36}
效果图
3.1 MorphTypes
看第27篇,ths
网址:
https://docs.opencv.org/master/d4/d86/groupimgprocfilter.html#gga7be549266bad7b2e6a04db49827f9f32acf55ff766595ec0174ba42852f0ac264
"hit or miss" .- 只支持CV_8UC1二进制图像。
3.2 saturate_cast的用法
saturate_cast
3.3 convertTo的用法
1void convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 ) const;
参数:
m:目标矩阵。如果m在运算前没有合适的尺寸或类型,将被重新分配。
rtype:目标矩阵的类型。因为目标矩阵的通道数与源矩阵一样,所以rtype也可以看做是目标矩阵的位深度。如果rtype为负值,目标矩阵和源矩阵将使用同样的类型。
alpha:尺度变换因子(可选)。【比例因子】
beta:附加到尺度变换后的值上的偏移量(可选)【将输入数组元素按比例缩放后添加的值】。
(在第5篇线性混合addWeighted谈到alpha、beta)
函数将源矩阵中的像素值转换为目标类型。最后会使用溢出保护函数saturate_cast<> ,以避免转换过程中可能出现的溢出。函数执行如下运算:
convertTo:就是转换类型
3.4 MoveWindow
改变指定窗口的位置和大小。
任务:
简单调用API函数就OK(估计以后实战中,经常使用形态学图像处理问题)
代码如下:
1#include 2#include 3#include 4using namespace cv; 5int main() { 6 Mat input_image = imread("D://9.jpg",2); 7 8 imshow("Hit or Miss原图", input_image); 9 Mat kernel = (Mat_(3, 3) <<10 0, 1, 0,11 1, -1, 1,12 0, 1, 0);13 Mat output_image, output_image1;14 Mat element = getStructuringElement(0, Size(3, 3),Point(-1,-1)); 15 erode(input_image, output_image1, element);16 imshow("腐蚀图", output_image1);1718 morphologyEx(input_image, output_image, MORPH_HITMISS, kernel);1920 imshow("Hit or Miss", output_image);2122 waitKey(0);23 return 0;24}
原图:
效果图:
效果有点像内部和外部梯度的效果图,当然日后轮廓相关边缘检测,分水岭要用到
本人是抱着玩一玩的心态,学习opencv(其实深度学习没有外界说的这么高深,小嗷是白板,而且有工作在身并且于代码无关)
大家可以把我的数学水平想象成初中水平,毕竟小嗷既不是代码靠吃饭又不是靠数学吃饭,毕业N年
写文章主要是为了后人少走点弯路,多交点朋友,一起学习
如果有好的图像识别群拉我进去QQ:631821577
就我一个白板,最后还是成的,你们别怕,慢慢来把
分享可以无数次,转载成自己文章QQ邮箱通知一下,未经授权请勿转载。
QQ群:736854977
有什么疑问公众号提问,下班或者周六日回答,ths
推荐文章:
8.更正曝光不足的图像(图像的对比度和亮度及轨迹条) --- OpenCV从零开始到图像(人脸 + 物体)识别系列 【没有排版好】
(公众号底下的文章分类 -> 编程 -> 查看第四篇文章)【已经排版好,建议PC电脑看】
25.消除不相关的细节/裂缝桥接(形态学 --膨胀与腐蚀详解 )--- OpenCV从零开始到图像(人脸 + 物体)识别系列
27.形态学图像运算(形态学梯度计算/开运算/闭运算/顶帽运算/黑帽)-- OpenCV从零开始到图像(人脸 + 物体)识别系列
感言
很多书上都用集合论来讲这一变换,对应用者来说似乎没这必要。简单来说击中-击不中运算常用于二值图像,它用于基于结构元素的配置,从图像中寻找具有某种像素排列特征的目标,如单个像素、颗粒中交叉或纵向的特征、直角边缘或其他用户自定义的特征等。计算时,只有当结构元素与其覆盖的图像区域完全相同时,中心像素的值才会被置为1,否则为0。下图给出了一个例子。
和简单的腐蚀操作不一样。击中或击不中变换,只有当结构元素与其覆盖的图像区域完全相同(包括物体前景点还含有背景点,也就是补集也要一样)时,所对应的区域输出图象。
书上有这么一句话:“当不需要背景时,击中或击不中变换退化为腐蚀操作”