一 首先要了解openCv里的核结构:IplConvKernel,以下如何创造
- IplConvKernel* cvCreateStructingElementEx(
- int cols, //行
- int rows, //列
- int anchor_x, //核的封闭矩形内的参考点的坐标
- int anchor_y,
- int shape, //CV_SHAPE_RECT:核是矩形,CV_SHAPE_CROSS:十字交叉形,CV_SHAPE_ELLIPSE:椭圆形,CV_SHAPE_CUSTOM:用户自定 义的值
- int* values = null
- );
释放函数如下:
- void cvReleaseStructingElement(
- IplConvKernel** element
- );
对于二值图像,可以用openCv里的cvErode和cvDilate来腐蚀和膨胀,
void cvDilate(//膨胀
IplImage* src,
IplImage* dst,
IplConvKernel* B = NULL,
int iterations = 1
);
void cvErode(//腐蚀
IplImage* src,
IplImage* dst,
IplConvKernel* B = NULL, //B即核,下同
int iterations = 1 //如名,迭代次数,下同
);
测试代码如下
- /*******************************
- 数学形态运算,最常见的基本运算有七种,
- 分别为:腐蚀、膨胀、开运算、闭运算、击中、细化和粗化,
- 它们是全部形态学的基础。
- ********************************/
- #include "cv.h"
- #include "highgui.h"
- #include <stdlib.h>
- #include <stdio.h>
- IplImage *src=0;
- IplImage *dst=0;
- IplConvKernel *element=0;//声明一个结构元素
- int element_shape=CV_SHAPE_RECT;//长方形形状的元素
- int max_iters=10;
- int open_close_pos=0;
- int erode_dilate_pos=0;
- void OpenClose(int pos)
- {
- int n=open_close_pos-max_iters;
- int an=n>0?n:-n;
- element = cvCreateStructuringElementEx(an*2+1,
- an*2+1,an,an,element_shape,0);//创建结构元素
- /*
- IplConvKernel* cvCreateStructingElementEx(
- int cols, //行
- int rows, //列
- int anchor_x, //核的封闭矩形内的参考点的坐标
- int anchor_y,
- int shape, //CV_SHAPE_RECT:核是矩形,CV_SHAPE_CROSS:十字交叉形,CV_SHAPE_ELLIPSE:椭圆形,CV_SHAPE_CUSTOM:用户自定 义的值
- int* values = null
- );
- */
- if (n<0)//开运算
- {
- cvErode(src,dst,element,1);//腐蚀图像
- cvDilate(dst,dst,element,1);//膨胀图像
- /*
- void cvDilate(
- IplImage* src,
- IplImage* dst,
- IplConvKernel* B = NULL,//默认的为3*3的核
- int iterations = 1 //迭代次数,
- );
- */
- }
- else//闭运算
- {
- cvDilate(dst,dst,element,1);//膨胀图像
- cvErode(src,dst,element,1);//腐蚀图像
- }
- cvReleaseStructuringElement(&element);
- cvShowImage("Open/Close",dst);
- }
- void ErodeDilate(int pos)
- {
- int n=erode_dilate_pos-max_iters;
- int an=n>0?n:-n;
- element = cvCreateStructuringElementEx(an*2+1,an*2+1,an,an,element_shape,0);
- if (n<0)
- {
- cvErode(src,dst,element,1);//腐蚀
- }
- else
- {
- cvDilate(src,dst,element,1);//膨胀
- }
- cvReleaseStructuringElement(&element);//释放核
- cvShowImage("Erode/Dilate",dst);
- }
- int main(int argc,char **argv)
- {
- src = cvLoadImage("D:\\openCV\\openCVProject\\openCv笔记\\openCv笔记\\test.jpg");
- if(!src)
- {
- printf("open file error");
- return 0;
- }
- //菜单 参数介绍
- printf("参数:1.e-CV_SHAPE_ELLIPSE;2.r-CV_SHAPE_RECT,3./r-(element_shape+1)%3");
- dst=cvCloneImage(src);
- cvNamedWindow("Open/Close",1);
- cvNamedWindow("Erode/Dilate",1);
- open_close_pos = erode_dilate_pos = max_iters;
- cvCreateTrackbar("iterations","Open/Close",&open_close_pos,max_iters*2+1,OpenClose);
- cvCreateTrackbar("iterations","Erode/Dilate",&erode_dilate_pos,max_iters*2+1,ErodeDilate);
- for (;;)
- {
- int c;
- OpenClose(open_close_pos);
- ErodeDilate(erode_dilate_pos);
- c= cvWaitKey(0);
- if (c==27)
- {
- break;
- }
- switch(c) {
- case 'e':
- element_shape=CV_SHAPE_ELLIPSE;
- break;
- case 'r':
- element_shape=CV_SHAPE_RECT;
- break;
- case '/r':
- element_shape=(element_shape+1)%3;
- break;
- default:
- break;
- }
- cvReleaseImage(&src);
- cvReleaseImage(&dst);
- cvDestroyWindow("Open/Close");
- cvDestroyWindow("Erode/Dilate");
- return 0;
- }
- /*****************************
- 腐蚀和膨胀,看上去好像是一对互逆的操作,实际上,这两种操作不具有互逆的关系。
- 开运算和闭运算正是依据腐蚀和膨胀的不可逆性,演变而来的。
- 先腐蚀后膨胀的过程就称为开运算。
- 闭运算是通过对腐蚀和膨胀的另一种不同次序的执行而得到的,
- 闭运算是先膨胀后腐蚀的过程,其功能是用来填充物体内细小空洞、连接邻近物体、平滑其边界,
- 同时不明显改变不明显改变其面积。
- ******************************/
二 但是对于灰度图或彩色图,不可以直接用cvErode和cvDilate来处理,这里需要更通用的函数,即cvMorphologyEx;
- cvMorphologyEx void cvMorphologyEx( const CvArr* src, CvArr* dst, CvArr* temp, IplConvKernel* element, int operation, int iterations=1 );
- src 输入图像.
- dst 输出图像.
- temp 临时图像,
- element 结构元素 operation 形态操作的类型:
- CV_MOP_OPEN - 开运算 CV_MOP_CLOSE - 闭运算
- CV_MOP_GRADIENT - 形态梯度
- CV_MOP_TOPHAT - "顶帽"
- CV_MOP_BLACKHAT - "黑帽"
- iterations 膨胀和腐蚀次数.
- 函数 cvMorphologyEx 在膨胀和腐蚀基本操作的基础上,完成一些高级的形态变换:
- 开运算 dst=open(src,element)=dilate(erode(src,element),element)
- 闭运算 dst=close(src,element)=erode(dilate(src,element),element)
- 形态梯度 dst=morph_grad(src,element)=dilate(src,element)-erode(src,element)
- "顶帽" dst=tophat(src,element)=src-open(src,element)
- "黑帽" dst=blackhat(src,element)=close(src,element)-src
- 临时图像 temp 在形态梯度以及对“顶帽”和“黑帽”操作时的 in-place 模式下需要。
注意:不推荐使用(摘自http://blog.csdn.net/shandianling/article/details/6423640)
通过查看cvMorphologyEx的源代码,可以发现,在执行开、闭等运算,在进行第二步形态学腐蚀和膨胀时,该函数仍然采用与第一步相同的结构元素进行。这种方法在针对一般对称的结构元素情况是正确的,但是当结构元素为自定义的非对称结构元素时,结果图像会发生错误的偏移。 正确的方法是,如前面在开、闭运算的介绍中,执行第二步腐蚀、膨胀操作时,应采用结构元素的映射(反射)进行因此,在本文中不提倡使用cvMorphologyEx函数。
测试代码
- #include "StdAfx.h"
- #include "cv.h"
- #include "highgui.h"
- #include "highgui.h"
- int main(int argc, char ** argv)
- {
- cvNamedWindow("sourceImage");
- cvNamedWindow("open");
- cvNamedWindow("close");
- cvNamedWindow("gradient");
- cvNamedWindow("topHat");
- cvNamedWindow("blackHat");
- IplImage * src = cvLoadImage("test.bmp");
- cvShowImage("sourceImage",src);
- IplImage * temp = cvCreateImage(cvGetSize(src), 8,3);
- IplImage * img=cvCreateImage(cvGetSize(src), 8, 3);
- cvCopyImage(src,temp);
- cvCopyImage(src, img);
- //开运算
- cvMorphologyEx(
- src,
- img,
- temp,
- NULL, //default 3*3
- CV_MOP_OPEN,
- 4);
- cvShowImage("open", img);
- //闭运算
- cvMorphologyEx(
- src,
- img,
- temp,
- NULL, //default 3*3
- CV_MOP_CLOSE,
- 4);
- cvShowImage("close", img);
- //形态梯度
- cvMorphologyEx(
- src,
- img,
- temp,
- NULL, //default 3*3
- CV_MOP_GRADIENT,
- 3);
- cvShowImage("gradient", img);
- //cvWaitKey(0);
- //"礼帽"
- cvMorphologyEx(
- src,
- img,
- temp,
- NULL, //default 3*3
- CV_MOP_TOPHAT,
- 3);
- cvShowImage("topHat", img);
- //cvWaitKey(0);
- //“黑帽”
- cvMorphologyEx(
- src,
- img,
- temp,
- NULL, //default 3*3
- CV_MOP_BLACKHAT,
- 3);
- cvShowImage("blackHat", img);
- cvWaitKey(0);
- cvReleaseImage(&temp);
- cvReleaseImage(&src);
- cvReleaseImage(&img);
- cvDestroyAllWindows();
- return 0;
- }