形态学知识
/**************************************************************************/
-代表腐蚀 +代表膨胀 *代表匹配 一下针对的是二值图像,图片指黑底白字腐蚀 A-B={z|(B)z包含于A} 1.该式指出B对A的腐蚀是一个用z平移的B包含在A中的所有的点z的集合 2.等价于B不与北京共享任何公共元素。膨胀 A+B={z|(B补)z交A!=空集} 1.该公式是以B关于它的原点的映像,并且以z对映像进行平移为基础的。B对A的膨胀是所有位移z的集合,B补和A至少有一个元素是重叠的。 腐蚀会细化图像,膨胀会粗化图像开操作 A。B=(A-B)+B 1.先腐蚀后膨胀,结果是一般会平滑物体的轮廓,断开较窄的狭颈并消除细的突出物 理解:先腐蚀会消除掉比SE小的区域,然后再度膨胀,小的物体会变大,没了的物体就依旧是没了闭操作 A. B=(A+B)-B 1.先膨胀后腐蚀,通常会弥合较窄的间断和细长的沟壑,消除小的孔洞,填充轮廓线中的断裂 理解:由于膨胀会把原来细小的点,间断点连接起来,再腐蚀会把周围变细,但是内部不变。 击中与击不中变换 A*B=(A-D)交(A补-(W减去D)) 理解:不是特别懂。大概就是把B在A中给匹配出来,并且标记为1;在不需要匹配背景的情况下,便可以简化为腐蚀一些基本的形态学算法1.边界提取 边界=A减去(A-B) 理解:B腐蚀掉A就会得到A小一圈的部分(即内部),实心图减去内部即得到一个环(边界)2.孔洞填充 Xk=(Xk-1+B)交A补 迭代至Xk和Xk-1相等为止,然后Xk和原图取交集即可 条件:每个孔洞要预先有填充一个点,B={0,1,0,1,1,1,0,1,0},针对八连通的孔洞 理解:每次对Xk-1进行膨胀时,都会在之前的点的上下左右填充哦你一个点,然后再通过与A补求交集即可得到一个填充区域,最后填充区域与原图求并集就能够填充原图的孔洞。3.连通分量的提取 Xk=(Xk-1+B)交A 迭代至Xk和Xk-1相等为止 条件:在连通区域要有先填充一个点,B(3,3,CV_8U,Scalar::all(1)),针对八连通的区域 理解:每次对Xk-1进行膨胀时,都会在之前的点周围的八个点填充,然后通过与原图求交集即去掉多余的点,即可得到八连通的区域4.凸壳 Xk=(Xk-1*B)并A 迭代至Xk和Xk-1相等为止,执行B1,2,3,4,最终将4个并集起来,即可得到凸壳 B={1,X,X 1,0,X 1,X,X} B1,2,3,4依次旋转90度 理解:对Xk-1无限次匹配B则会在最右侧形成阶梯的形状,向中间靠拢,直到最右侧只有1或2个高度。其他方向一样理解,并集则是确保包含A,最终4个Xk求并集便是凸壳5.细化 A细化B=A-(A*B) 当{B}={B1,1,2,3,4,5}时。A细化{B}=(((A细化B1)细化B2)细化B3)……6.粗化 A粗化B=A并(A*B)形态学重建测地膨胀 对集合进行膨胀后与模板求交集,迭代至不再变化为止测地腐蚀 对集合进行腐蚀后与模板求补集,迭代至不再变化为止重建开操作提取长字母的理解 先对原图进行n次腐蚀,后进行测地膨胀。n次腐蚀可以提取出原图中长字母的一个点,由于每个字母中间有间隔,每次进行测地膨胀的时候,无关的值在求交集的过程中去掉了,剩下了连续的,与原来模板相关的值。对填充孔洞,实现字母涂黑的理解 对边界取反色,然后其余部分为黑色,从边界开始以原图的补为模板进行测地膨胀,得到的结果便是原来的白色字体变成了黑色,被黑色字体包围起来的圈也是黑色,其余部分是白色,再对这张图取反,就得到了白色字体里面的白色孔洞被填充了。边界清除的理解 保留边界的点,然后从这些点开始以原图为模板进行测地膨胀,把原图减去这个结果即可。
灰度级形态学
腐蚀操作,取覆盖区域的最小值 膨胀操作,取覆盖区域的最大值 开操作,在一维的理解下可以认为是一条横线从下往上滑动的最大高度,会截去比较细的部分,变平。 闭操作,从上往下滑动的最低程度,截去低谷部分,变平。 形态学平滑,先进行开操作,再进行闭操作。 形态学梯度,g=(f+b)-(f-b),可以得到和二维微分图像类似的效果。 顶帽变换That=f-(f开b),得到暗背景上的亮物体,可以用来矫正不均匀光照的影响 底帽变换Bhat=f闭b-f,达到的亮背景上的暗物体 灰度级形态学重建 测地膨胀f=min((f+b),g),一样是迭代至不变化为止 测地腐蚀f=max((f-b),g),同上
/**************************************************************************************************************/
介绍一下opencv函数
dilate=膨胀
erode=腐蚀
以上来自于opencv的使用手册
/****************************************************************************************************/
以下是例程(提取长字母和填充字母中的孔洞)
#include<opencv2/opencv.hpp> #include<iostream> using namespace std; using namespace cv; int check_mat(Mat&a,Mat&b)/*判断两幅图像是否相同*/ { int ra=a.rows; int ca=a.cols; int rb=b.rows; int cb=b.cols; if(ra!=rb || ca!=cb)return 0; for(int i=0;i<ra;i++) { char *pa=a.ptr<char>(i); char *pb=b.ptr<char>(i); for(int j=0;j<ca;j++) if(pa[j]!=pb[j])return 0; } return 1; } void border_f(Mat &src)/*取边框反色,其余置0*/ { int r=src.rows; int c=src.cols; for(int i=0;i<r;i++) { char*p=src.ptr<char>(i); p[0]=255-p[0]; p[c-1]=255-p[c-1]; } char*p=src.ptr<char>(0); for(int i=1;i<c-1;i++) p[i]=255-p[i]; p=src.ptr<char>(r-1); for(int i=1;i<c-1;i++) p[i]=255-p[i]; for(int i=1;i<r-1;i++) { char*pt=src.ptr<char>(i); for(int j=1;j<c-1;j++) pt[j]=0; } } int main(int a,char **p) { Mat src=imread("eng.png",CV_LOAD_IMAGE_GRAYSCALE);//载入灰度图像 threshold(src,src,180,255,1);//二值化,由于我的图像是黑字白底的,所以最后一个参数取1,变成白字黑底 imshow("src",src); Mat kern(10,1,CV_8U,Scalar::all(1));//长字符的SE Mat kern2(3,3,CV_8U,Scalar::all(1));//3*3的SE Mat old_output; erode(src,old_output,kern);//腐蚀 dilate(old_output,old_output,kern);//膨胀 /*腐蚀再膨胀,便是开操作*/ imshow("old_ouput",old_output); Mat re_output; erode(src,re_output,kern); Mat last_output; imshow("re",re_output); //*****************重建开操作****************** do{ last_output=re_output.clone(); dilate(re_output,re_output,kern2); re_output=re_output&src; }while(!check_mat(last_output,re_output)); imshow("re_output",re_output);/*提取出了长字符*/ //******************填充孔洞******************* Mat F=src.clone();/*拷贝一份*/ border_f(F); imshow("border_f",F); Mat Ic=Mat::ones(src.size(),CV_8UC1)*255-src; re_output=F; do { last_output=re_output.clone(); dilate(re_output,re_output,kern2); re_output=re_output&Ic; }while(!check_mat(last_output,re_output)); Mat H=Scalar::all(255)-re_output; imshow("oo",H);/*填充了孔洞*/ waitKey(); return 0; }
abc
def
a是输入的原图
b是腐蚀后的效果
c是一般的开操作的结果
d是重建开操作后的结果
e是边界取反色,其余置0的效果
f是孔洞填充的效果
