28.击中击不中变换(二值图像/结构元素/集合/convertTo/saturate_cast/moveWindow)


本文作者:小嗷

微信公众号:aoxiaoji

吹比QQ群:736854977

简书链接:https://www.jianshu.com/u/45da1fbce7d0


在本篇中,您将学习如何通过使用“Hit-or-Miss”转换(也称为“Hit-or-Miss”转换)在二进制映像中找到给定的配置或模式。(命中/错过)

这种变换也是更高级的形态学操作的基础,如细化或修剪。

我们将使用OpenCV函数morphologyEx()。

本文你会找到以下问题的答案:

  1. 二值图像
  2. 结构元素
  3. 集合
  4. 击中击不中变换(Hit-or-Miss)
  5. convertTo
  6. saturate_cast
  7. moveWindow

2.1 二值图像

二值图像(Binary Image)是指将图像上的每一个像素只有两种可能的取值或灰度等级状态,人们经常用黑白、B&W、单色图像表示二值图像。

二值图像是指在图像中,灰度等级只有两种,也就是说,图像中的任何像素不是0就是1,再无其他过渡的灰度值。

2.2 结构元素

结构元素就是核模块。

28.击中击不中变换(二值图像/结构元素/集合/convertTo/saturate_cast/moveWindow)_第1张图片

上图中间这个模块称为结构元素(专业名词)

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)

结构元素(内核)。左:内核“击中”。中间:内核“不击中”。右:最后结合内核

在这种情况下,我们正在寻找一种模式,其中的中心像素属于背景,而北部、南部、东部和西部像素属于前景。附近的其他像素可以是任何类型的,我们不关心它们。现在,让我们将这个核应用到一个输入图像:

28.击中击不中变换(二值图像/结构元素/集合/convertTo/saturate_cast/moveWindow)_第2张图片

二值图(原图)

28.击中击不中变换(二值图像/结构元素/集合/convertTo/saturate_cast/moveWindow)_第3张图片

输出二值图像

您可以看到模式只在图像中的一个位置找到255

前面示例对应的代码如下所示。

#include 
#include 
#include 
using namespace cv;
int main(){
    Mat input_image = (Mat_(8, 8) <<
        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);
    Mat kernel = (Mat_(3, 3) <<
        0, 1, 0,
        1, -1, 1,
        0, 1, 0);
    Mat output_image;
    morphologyEx(input_image, output_image, MORPH_HITMISS, kernel);
    const int rate = 50;
    kernel = (kernel + 1) * 127;
    kernel.convertTo(kernel, CV_8U);
    resize(kernel, kernel, Size(), rate, rate, INTER_NEAREST);
    imshow("kernel", kernel);
    moveWindow("kernel", 0, 0);
    resize(input_image, input_image, Size(), rate, rate, INTER_NEAREST);
    imshow("Original", input_image);
    moveWindow("Original", 0, 200);
    //rate就是用来或大尺寸
    resize(output_image, output_image, Size(), rate, rate, INTER_NEAREST);
    imshow("Hit or Miss", output_image);
    moveWindow("Hit or Miss", 500, 200);
    waitKey(0);
    return 0;
}

效果图

3.1 MorphTypes

看第27篇,ths

网址:

https://docs.opencv.org/master/d4/d86/group__imgproc__filter.html#gga7be549266bad7b2e6a04db49827f9f32acf55ff766595ec0174ba42852f0ac264

“hit or miss” .- 只支持CV_8UC1二进制图像。

3.2 saturate_cast的用法

saturate_cast(value):(value)确保值大小范围为0~255之间

3.3 convertTo的用法

void 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(估计以后实战中,经常使用形态学图像处理问题)

代码如下:

#include 
#include 
#include 
using namespace cv;
int main() {
    Mat input_image = imread("D://9.jpg",2);

    imshow("Hit or Miss原图", input_image);
    Mat kernel = (Mat_(3, 3) <<
        0, 1, 0,
        1, -1, 1,
        0, 1, 0);
    Mat output_image, output_image1;
    Mat element = getStructuringElement(0, Size(3, 3),Point(-1,-1)); 
    erode(input_image, output_image1, element);
    imshow("腐蚀图", output_image1);

    morphologyEx(input_image, output_image, MORPH_HITMISS, kernel);

    imshow("Hit or Miss", output_image);

    waitKey(0);
    return 0;
}

原图:

效果图:

效果有点像内部和外部梯度的效果图,当然日后轮廓相关边缘检测,分水岭要用到

  1. 本人是抱着玩一玩的心态,学习opencv(其实深度学习没有外界说的这么高深,小嗷是白板,而且有工作在身并且于代码无关)
  2. 大家可以把我的数学水平想象成初中水平,毕竟小嗷既不是代码靠吃饭又不是靠数学吃饭,毕业N年
  3. 写文章主要是为了后人少走点弯路,多交点朋友,一起学习
  4. 如果有好的图像识别群拉我进去QQ:631821577
  5. 就我一个白板,最后还是成的,你们别怕,慢慢来把

分享可以无数次,转载成自己文章QQ邮箱通知一下,未经授权请勿转载。

  • 邮箱:[email protected]
  • QQ群:736854977
  • 有什么疑问公众号提问,下班或者周六日回答,ths

推荐文章:

8.更正曝光不足的图像(图像的对比度和亮度及轨迹条) — OpenCV从零开始到图像(人脸 + 物体)识别系列 【没有排版好】

(公众号底下的文章分类 -> 编程 -> 查看第四篇文章)【已经排版好,建议PC电脑看】

25.消除不相关的细节/裂缝桥接(形态学 –膨胀与腐蚀详解 )— OpenCV从零开始到图像(人脸 + 物体)识别系列

27.形态学图像运算(形态学梯度计算/开运算/闭运算/顶帽运算/黑帽)– OpenCV从零开始到图像(人脸 + 物体)识别系列

感言

很多书上都用集合论来讲这一变换,对应用者来说似乎没这必要。简单来说击中-击不中运算常用于二值图像,它用于基于结构元素的配置,从图像中寻找具有某种像素排列特征的目标,如单个像素、颗粒中交叉或纵向的特征、直角边缘或其他用户自定义的特征等。计算时,只有当结构元素与其覆盖的图像区域完全相同时,中心像素的值才会被置为1,否则为0。下图给出了一个例子。

28.击中击不中变换(二值图像/结构元素/集合/convertTo/saturate_cast/moveWindow)_第4张图片

和简单的腐蚀操作不一样。击中或击不中变换,只有当结构元素与其覆盖的图像区域完全相同(包括物体前景点还含有背景点,也就是补集也要一样)时,所对应的区域输出图象。

书上有这么一句话:“当不需要背景时,击中或击不中变换退化为腐蚀操作”

你可能感兴趣的:(OpenCv,-)