图像形态学
形态学操作就是基于形状的一系列图像处理操作,也可以理解为一种滤波行为。最基本的形态学操作使:膨胀和腐蚀。
膨胀和腐蚀
膨胀是图像和核进行卷积,然后取覆盖区域的最大值,这样就会使图像的高亮区域增大,OpenCV的API是dilate。和膨胀相反的,腐蚀是取的覆盖区域最小值。这样会使图像的高亮区域减少,OpenCV的API是erode。
void dilate( InputArray src, OutputArray dst, InputArray kernel,
Point anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
void erode( InputArray src, OutputArray dst, InputArray kernel,
Point anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
和卷积核不同的是,我们可以自定义自己的形态核,形态核不需要任何数值的填充,核在图像上移动时候,核元素只需要确定简单的标明在哪个范围内取最大值和最小值。自定义核的API函数是getStructuringElement。
Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));
综合编程
Mat src,dst,dst1,mapx,mapy;
char OUTPUT[] ="Win2";
int TrackBarPos = 0;
int TrackBarMax = 21;
void CallBack(int, void*);
int main()
{
src = imread("D:/Lena.jpg");
if(!src.data)
{
cout<<"Picture loading failed !"<<endl;
return -1;
}
namedWindow("Win1");
imshow("Win1",src);
namedWindow("Win2");
createTrackbar("Value",OUTPUT,&TrackBarPos,TrackBarMax,CallBack);
CallBack(0,0);
waitKey(0);
return 0;
}
void CallBack(int, void*)
{
int ker = 2*TrackBarPos+1;
//创建形态核(不同于卷积核),只需要确定确定一个移动的范围即可。不需要填充任何数字
Mat StruEle = getStructuringElement(MORPH_RECT,Size(ker,ker),Point(-1,-1));
dilate(src,dst,StruEle,Point(-1,-1),1);//erode(src,dst1,StruEle,Point(-1,-1),1);
imshow(OUTPUT,dst);
}
通用的形态学
通用的形态学操作使用的API函数是:
void morphologyEx( InputArray src, OutputArray dst,
int op, InputArray kernel,
Point anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
其中:op参数可以选择:
①腐蚀操作(MORPH_ERODE = 0)
②膨胀操作(MORPH_DILATE =1)
注意:腐蚀和膨胀都说的是亮的区域,膨胀是亮的区域变大,腐蚀和膨胀相反,是亮的区域变小。
③开运算(MORPH_OPEN =2)
开运算是先腐蚀再膨胀,开操作去除小的明亮区域,剩余亮的区域被隔绝,但是大小不变。
理解:先腐蚀的话,亮的区域变小,再膨胀操作,可以排除小团物体。
下图是进行开操作的结果:
④闭运算(MORPH_CLOSE = 3)
和开操作相反,闭运算是通过先对图像膨胀再腐蚀实现的。
⑤形态学梯度:把团块的边缘突出来。
⑥礼帽
礼帽是从A中减去A的开运算,局部的极大值点被分隔出来。
⑦黑帽
闭运算结果图与原图像之差
综合编程
Mat src,dst,dst1,mapx,mapy;
char OUTPUT[] ="Win2";
int TrackBarPos = 0;
int TrackBarMax = 21;
int ModePos = 0;
int ModeMax = 6;
void CallBack(int, void*);
int main()
{
src = imread("D:/dilate.jpg");
if(!src.data)
{
cout<<"Picture loading failed !"<<endl;
return -1;
}
namedWindow("Win1");
imshow("Win1",src);
namedWindow("Win2",WINDOW_NORMAL);
createTrackbar("Mode",OUTPUT,&ModePos,ModeMax,CallBack);
createTrackbar("Value",OUTPUT,&TrackBarPos,TrackBarMax,CallBack);
CallBack(0,0);
waitKey(0);
return 0;
}
void CallBack(int, void*)
{
int ker = 2*TrackBarPos+1;
//创建形态核(不同于卷积核),只需要确定确定一个移动的范围即可。不需要填充任何数字
Mat StruEle = getStructuringElement(MORPH_RECT,Size(ker,ker),Point(-1,-1));
morphologyEx(src,dst,ModePos,StruEle,Point(-1,-1));
imshow(OUTPUT,dst);
}
实际例子
验证码的读取
int main()
{
//读取图像
Mat src, dst;
src = imread("D:/121.png");
if (!src.data)
{
cout<<"Picture loading failed !"<<endl;
return -1;
}
namedWindow("Win1",WINDOW_NORMAL);
imshow("Win1",src);
//转化为灰度图像
Mat src_gray;
cvtColor(src,src_gray,COLOR_BGR2GRAY);
namedWindow("Win2",WINDOW_NORMAL);
imshow("Win2",src_gray);
//转化为二值图像
Mat src_bin;
adaptiveThreshold(~src_gray,src_bin,255,ADAPTIVE_THRESH_MEAN_C,THRESH_BINARY,7,0);
namedWindow("Win3",WINDOW_NORMAL);
imshow("Win3",src_bin);
//开操作
Mat StrElem = getStructuringElement(MORPH_RECT,Size(3,3),Point(-1,-1));
morphologyEx(src_bin,dst,MORPH_OPEN,StrElem,Point(-1,-1),1);
blur(dst,dst,Size(3,3));
namedWindow("Win4",WINDOW_NORMAL);
imshow("Win4",dst);
waitKey(0);
return 0;
}
程序结果: