openCV 形态学图像处理


转:wzy1222 http://blog.csdn.net/a576323437/article/details/9204013

形态学图像处理的应用可以简化图像数据,保持它们基本的形状特性,并除去不相干的结构。

一。形态学图像处理的基本运算有4个:膨胀、腐蚀、开操作和闭操作。

结构元素大小的影响:
结构元素大的话,对于前景来说,被腐蚀掉的像素点会有好多,留下来的较少。    膨胀的像素点也会多。。。。  嗯嗯。大概这么个理解法。嘻嘻。

图像的腐蚀和膨胀:(二值图像,和灰度图像,调用的都是同一个函数,理解以二值图像来理解呗。)
腐蚀作用: 去噪音。 或者断开两个区域。
膨胀作用: 可以连通两个区域。

腐蚀膨胀的具体实现:(那个句号,代表了原点。)

腐蚀算法:

简单说,首先构造一个结构元素,结构元素的原点定位在待处理的目标像素上,当结构元素完全被包容在目标区域中,则原点所对应的目标像素点被保留;否则该点被腐蚀掉——成为新的背景点。所有的保留点,构成腐蚀的结果图像。

膨胀算法:

简单说,首先构造一个结构元素B 和B的反射,结构元素的原点定位在背景像素上,当有目标点被覆盖(称之为击中)时,则该点被膨胀为目标点——原点对应的背景像素点被作为新的目标点保留下来,所有的保留点构成膨胀的结果图像。



上面的原理看了挺久的,终于找到一幅好理解的图。。不容易呀。

C++: void erode(InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1),int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& border-
Value=morphologyDefaultBorderValue() )
dilate同上。
结构元素默认3*3矩阵, 原点默认在中心处, 次数默认为1次。
咦,矩阵内容的在哪里,什么十字形什么的。
对前景腐蚀就是对背景膨胀,对前影膨胀就是对背景腐蚀。

开运算和闭运算:
开运算: 先腐蚀,后膨胀。
闭运算: 先膨胀,后腐蚀。
开闭运算的优点: 腐蚀或者膨胀算法非常好,但是改变了原目标物的大小。  开闭运算可以达到腐蚀,膨胀的效果,并且保持目标物大小基本保持不变。
C++: 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() )


二  图像边缘探测和角探测。

1边缘探测原理:  

原图作一次膨胀,原图作一次腐蚀,二者相减即是边缘图。    用的这个结构元素,被称为图像梯度。。不同的图像梯度,可以探测不同粗细的边。。(貌似是这样子,详见下一章)

可以用 cv::morphologyEx(image,mat_edge,cv::MORPH_GRADIENT,cv::Mat())  函数直接实现。也可以手动膨胀腐蚀再相减。。

  1. // 边缘检测, 一个膨胀 减去 一个腐蚀 相减就可以。  
  2.     //探测边,只要用梯度算法就可以了。你敢信。。  
  3.     cv::Mat mat_edge;  
  4.     cv::morphologyEx(image,mat_edge,cv::MORPH_GRADIENT,cv::Mat());  
  5.     /* 上面梯度算法具体实现,膨胀一次,腐蚀一次,两个相减就得出边。 
  6.     cv::Mat tmp; 
  7.     cv::dilate(image,mat_edge,cv::Mat()); 
  8.     cv::erode(image,tmp,cv::Mat()); 
  9.     cv::absdiff(mat_edge,tmp,mat_edge); 
  10. */  
  11.     cv::namedWindow("win_edge");  
  12.     cv::imshow("win_edge",mat_edge);  
  13.   
  14.     cout<<"type = "<<mat_edge.type()<<endl;  
  15.     cv::Mat mat_thre;  
  16.     //二值化一下。变成黑白图,更加清楚  
  17.     cv::threshold(mat_edge,mat_thre,40,255,cv::THRESH_BINARY);  
  18.     //黑白对调一次 - -  
  19.     cv::bitwise_not(mat_thre,mat_thre);  
  20.     cv::namedWindow("win_edge_thre");  
  21.     cv::imshow("win_edge_thre",mat_thre);  


2. 角探测原理:

角探测没有直接调用的函数,检测角的算法是
1>.原图膨胀十字,用结果腐蚀菱形,
2>.原图膨胀x形,用结果腐蚀正方向  1- 2 所得即是。


以下内容转自: http://blog.csdn.net/sunny2038/article/details/9137759#t0
边缘检测:
形态学检测边缘的原理很简单,在膨胀时,图像中的物体会想周围“扩张”;腐蚀时,图像中的物体会“收缩”。比较这两幅图像,由于其变化的区域只发生在边缘。所以这时将两幅图像相减,得到的就是图像中物体的边缘。
角检测:
先用十字形的结构元素膨胀像素,这种情况下只会在边缘处“扩张”,角点不发生变化。接着用菱形的结构元素腐蚀原图像,导致只有在拐角处才会“收缩”,而直线边缘都未发生变化。
第二步是用X形膨胀原图像,角点膨胀的比边要多。这样第二次用方块腐蚀时,角点恢复原状,而边要腐蚀的更多。所以当两幅图像相减时,只保留了拐角处。

  1. //拐角要用到4种图形的结构元素。  
  2.     cv::Mat cross(5,5,CV_8U,cv::Scalar(0)),  //十字  
  3.             diamond(5,5,CV_8U,cv::Scalar(1)),  //菱形  
  4.             square(5,5,CV_8U,cv::Scalar(1)), //正方形  
  5.             x(5,5,CV_8U,cv::Scalar(0)); // x 形。  
  6.     // 十字初始化。     中间十字为1,其它为0  
  7.     for(int i=0;i<5;++i)  
  8.     {  
  9.         cross.at<uchar>(2,i) = 1;  
  10.         cross.at<uchar>(i,2) = 1;  
  11.     }  
  12.     // 菱形初始化  4个角,均有三个像素置成0,其它全为1  
  13.     diamond.at<uchar>(0,0)= 0;  
  14.       diamond.at<uchar>(0,1)= 0;  
  15.       diamond.at<uchar>(1,0)= 0;  
  16.       diamond.at<uchar>(4,4)= 0;  
  17.       diamond.at<uchar>(3,4)= 0;  
  18.       diamond.at<uchar>(4,3)= 0;  
  19.       diamond.at<uchar>(4,0)= 0;  
  20.       diamond.at<uchar>(4,1)= 0;  
  21.       diamond.at<uchar>(3,0)= 0;  
  22.       diamond.at<uchar>(0,4)= 0;  
  23.       diamond.at<uchar>(0,3)= 0;  
  24.       diamond.at<uchar>(1,4)= 0;  
  25.   
  26.       // 正方形全为1  
  27.   
  28.       // x形。 对角线为1,其它全为0  
  29.       for(int i=0;i<5;++i)  
  30.       {  
  31.           x.at<uchar>(i,i)=1;  
  32.           x.at<uchar>(i,4-i)=1;  
  33.       }  
  34.   
  35.       //检测角的算法是:  
  36.       // 1.原图膨胀十字,用结果腐蚀菱形,  
  37.       // 2.原图膨胀x形,用结果腐蚀正方向  1-2所得即是。  
  38.       cv::Mat tmp1;  
  39.       cv::dilate(image,tmp1,cross);  
  40.       cv::erode(tmp1,tmp1,diamond);  
  41.   
  42.       cv::Mat tmp2;  
  43.       cv::dilate(image,tmp2,x);  
  44.       cv::erode(tmp2,tmp2,square);  
  45.   
  46.   
  47.       cv::Mat result_corner;  
  48.       cv::absdiff(tmp1,tmp2,result_corner);  
  49.   
  50.       //二值化一下。变成黑白图,更加清楚  
  51.       cv::threshold(result_corner,result_corner,40,255,cv::THRESH_BINARY);  
  52.       cv::namedWindow("win_corner");  
  53.       cv::imshow("win_corner",result_corner);  


三: 图像分割算法。

1. 分水岭 图像分割算法。 (没有实现,感觉暂时不会用到,先标记在这里)

2. GrabCut 前景后景分割算法。以下两个博客介绍地十分详细。

http://blog.csdn.net/zouxy09/article/details/8534954
http://blog.csdn.net/lcy9819/article/details/6554864

使用 cv::grabCut 大概的步骤:

1> 划定区域。

2> 用掩码图形,确定哪些肯定是前景,哪些肯定是后景。

3> 调用函数。 得到结果(像素值有4种, 分别是 一定前景、一定后景、可能前景、可能后景)

4> 把一定前景和可能前景的位置标出来。

5> 根据4所得的位置,将前景显示出来。

  1. cv::Mat image = cv::imread("/root/Desktop/photos/group.jpg");  
  2.     if( !image.data )  
  3.     {  
  4.         cout<<"failed in read group.jpg..."<<endl;  
  5.         return ;  
  6.     }  
  7.     cv::Rect rect(0,100,400,200);  
  8.     cv::Mat result;  
  9.     cv::Mat bgdModel,fgdModel;  
  10.   
  11.     //原图复制一份,画上框。  
  12.     cv::Mat image_tmp = image.clone();  
  13.     cv::rectangle(image_tmp,rect,cv::Scalar(0,0,255));  
  14.     cv::namedWindow("win_image_tmp");  
  15.     cv::imshow("win_image_tmp",image_tmp);  
  16.   
  17.     // 执行完算法后, result有四种值,0,1,2,3  
  18.     cv::grabCut(image,result,rect,bgdModel,fgdModel,5,cv::GC_INIT_WITH_RECT);  
  19.   
  20.     cv::namedWindow("win_grabcut");  
  21.     cv::imshow("win_grabcut",result);  
  22.   
  23.     //每个像素,比较,相等的话置为255     把所有可能是前景的像素点标志出来了。  
  24.     cv::Mat mat_cmp;  
  25.     cv::compare(result,cv::GC_PR_FGD,mat_cmp,cv::CMP_EQ);  
  26.   
  27.     cv::namedWindow("win_cmp");  
  28.     cv::imshow("win_cmp",mat_cmp);  
  29.   
  30.     //把原图按照标志位 复制一份。  
  31.     cv::Mat fgd;  
  32.     image.copyTo(fgd,mat_cmp);  
  33.     cv::namedWindow("win_fgd");  
  34.     cv::imshow("win_fgd",fgd);  



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenCV是一个非常强大的计算机视觉库,提供了丰富的图像处理和计算机视觉功能。其中包括形态学图像处理,也就是对图像进行形态学操作,比如膨胀、腐蚀、开运算、闭运算等。 下面是一个示例代码,展示了如何使用OpenCV进行形态学图像处理: ```cpp #include <opencv2/opencv.hpp> using namespace cv; int main() { // 读取图像 Mat img = imread("test.jpg"); // 将图像转换为灰度图像 cvtColor(img, img, COLOR_BGR2GRAY); // 对图像进行膨胀操作 Mat dilated; Mat element = getStructuringElement(MORPH_RECT, Size(3, 3)); dilate(img, dilated, element); // 对图像进行腐蚀操作 Mat eroded; erode(img, eroded, element); // 对图像进行开运算操作 Mat opened; morphologyEx(img, opened, MORPH_OPEN, element); // 对图像进行闭运算操作 Mat closed; morphologyEx(img, closed, MORPH_CLOSE, element); // 显示结果图像 namedWindow("Original Image", WINDOW_NORMAL); namedWindow("Dilated Image", WINDOW_NORMAL); namedWindow("Eroded Image", WINDOW_NORMAL); namedWindow("Opened Image", WINDOW_NORMAL); namedWindow("Closed Image", WINDOW_NORMAL); imshow("Original Image", img); imshow("Dilated Image", dilated); imshow("Eroded Image", eroded); imshow("Opened Image", opened); imshow("Closed Image", closed); // 等待用户按下任意键 waitKey(0); return 0; } ``` 这段代码可以对一张名为“test.jpg”的图像进行膨胀、腐蚀、开运算和闭运算操作,并将结果显示出来。需要注意的是,在进行形态学操作之前,需要将图像转换为灰度图像。另外,需要使用`getStructuringElement()`函数创建一个结构元素,用于形态学操作。 在实际应用中,可以根据具体需求选择不同的形态学操作,以便达到更好的图像处理效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值