在我们学习了膨胀腐蚀和基于膨胀腐蚀的变化之后,我比较喜欢的一个是击中击不中,因为喜欢所以就要单独列出来,心里总是觉得他可以有很多的用处,以后模版匹配,特征检测都会用,更深入的是,他会加深对膨胀腐蚀的理解,是一个很好的例子。

下面先看一个算法步骤和原理:

Hit-miss算法步骤:

击中击不中变换是形态学中用来检测特定形状所处位置的一个基本工具。它的原理就是使用腐蚀;如果要在一幅图像A上找到B形状的目标,我们要做的是:

  • 首先,建立一个比B大的模板W;使用此模板对图像A进行腐蚀,得到图像假设为Process1;
  • 其次,用B减去W,从而得到V模板(W-B);使用V模板对图像A的补集进行腐蚀,得到图像假设为Process2;
  • 然后,Process1与Process2取交集;得到的结果就是B的位置。这里的位置可能不是B的中心位置,要视W-B时对齐的位置而异;

其实很简单,两次腐蚀,然后交集,结果就出来了。

 

Hit-miss原理:

基于腐蚀运算的一个特性:腐蚀的过程相当于对可以填入结构元素的位置作标记的过程。

    腐蚀中,虽然标记点取决于原点在结构元素中的相对位置,但输出图像的形状与此无关,改变原点的位置,只会导致输出结果发生平移。

    既然腐蚀的过程相当于对可以填入结构元素的位置作标记的过程,可以利用腐蚀来确定目标的位置。

    进行目标检测,既要检测到目标的内部,也要检测到外部,即在一次运算中可以同时捕获内外标记。

    由于以上两点,采用两个结构基元H、M,作为一个结构元素对B=(H,M),一个探测目标内部,一个探测目标外部。当且仅当H平移到某一点可填入X的内部,M平移到该点可填入X的外部时,该点才在击中击不中变换的输出中。

opencv应用

<span style="font-size:18px;">Mat src;
src=imread("2312.png",0);
Mat input_image = src;  
Mat Kernel_S1 = imread("2311.png");
cvtColor(Kernel_S1, Kernel_S1, CV_RGB2GRAY);  
int threhold = 180;  
threshold(input_image, input_image, threhold, 255, CV_THRESH_BINARY);  
threshold(Kernel_S1, Kernel_S1, threhold, 255, CV_THRESH_BINARY);  
imshow("二值化图像", input_image);  
Mat BigBlankimage = Mat::ones(input_image.size(), input_image.type());  
input_image = BigBlankimage*255-input_image;  
imshow("反置图像", input_image); 
Mat Blankimage = Mat::ones(Kernel_S1.rows, Kernel_S1.cols, CV_8UC1);  
Mat Kernel_S2 = Blankimage * 255 - Kernel_S1;  
imshow("核1", Kernel_S1);  
imshow("核2", Kernel_S2);   
Mat hit_result, hit_result1, hit_result2;  
erode(input_image, hit_result1, Kernel_S1, Point(-1,-1), 1, BORDER_DEFAULT, 0);  
imshow("hit_result1", hit_result1);  
erode(input_image, hit_result2, Kernel_S2, Point(-1,-1), 1, BORDER_DEFAULT, 0);  
imshow("hit_result2", hit_result2);  
hit_result = hit_result1 & hit_result2;  
imshow("击中击不中", hit_result); </span>


matlab应用之函数使用与自定义实现

只要定义好s1 s2 调用bwhitmiss

<span style="font-size:18px;">Ihm = bwhitmiss(I, S1, S2);  
% I为输入图像  
% S1、S2为结构元素  </span>


根据冈萨雷斯的书的说明,如下图,然后用matlab编写代码,最后得到图像

java opencv识别图片上的线条数 opencv识别图形_目标检测

clear all;
I = zeros(120,180);
I(11:80,16:75) = 1;
I(56:105,86:135) = 1;
I(26:55,141:170) = 1;
figure,imshow(I);

se = zeros(58,58);
se(5:54,5:54) = 1;
figure,imshow(se);

%击中击不中变换
Ie1 = imerode(I,se);
figure,imshow(Ie1);

Ic = 1 - I;
figure,imshow(Ic);
S2 = 1 - se;
figure;imshow(S2);
Ie2 = imerode(Ic,S2);
figure,imshow(Ie2);

Ihm = Ie1 & Ie2;
figure,imshow(Ihm);





这里我们看一下结果

java opencv识别图片上的线条数 opencv识别图形_模版_02