OpenCV对形态学的运算处

一  首先要了解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  
  );  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
); 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(src,dst,element,1);//膨胀图像
        cvErode(dst,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;
}
/*****************************
腐蚀和膨胀,看上去好像是一对互逆的操作,实际上,这两种操作不具有互逆的关系。
开运算和闭运算正是依据腐蚀和膨胀的不可逆性,演变而来的。
先腐蚀后膨胀的过程就称为开运算。
闭运算是通过对腐蚀和膨胀的另一种不同次序的执行而得到的,
闭运算是先膨胀后腐蚀的过程,其功能是用来填充物体内细小空洞、连接邻近物体、平滑其边界,
同时不明显改变不明显改变其面积。
******************************/*******************************
数学形态运算,最常见的基本运算有七种,
分别为:腐蚀、膨胀、开运算、闭运算、击中、细化和粗化,
它们是全部形态学的基础。
********************************/
#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(src,dst,element,1);//膨胀图像
        cvErode(dst,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 模式下需要。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 模式下需要。


  通过查看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;  
}
#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;  
}
发布了15 篇原创文章 · 获赞 25 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/u010281924/article/details/9292775
今日推荐