[OpenCV] 形态学函数 Dilate 和 Erode ,以及对于引用和指针的一些练习。
原图:

CV_EXPORTS_W void dilate( InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() ); Description : Dilate膨胀 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可,图像通道的数量可以是任意的,但图像深度应为CV_8U、CV_16U、CV_168S、CV_32F或CV_64F其中之一。 第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。 第三个参数,InputArray类型的kernel,膨胀操作的核。当为NULL时,表示的是使用参考点位于中心3x3的核。 我们一般使用函数getStructuringElement配合这个参数的使用。getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵)。其中,getStructuringElement函数的第一个参数表示内核的形状,有如下三种形状可以选择。 矩形:MORPH_RECT; 交叉形:MORPH_CROSS; 椭圆形:MORPH_ELLIPSE。 而getStructuringElement函数的第二和第三个参数分别是内核的尺寸以及锚点的位置。 一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得getStructuringElement函数的返回值。对于锚点的位置,有默认值Point(-1,-1),表示锚点位于中心。此外,需要注意,十字形的element形状唯一依赖于锚点的位置,而在其他情况下,锚点只是影响了形态学运算结果的偏移。 getStructuringElement函数相关的调用示例代码如下。 Int g_nStructElementSize=3;//结构元素(内核矩阵)的尺寸 //获取自定义核 Mat element = getStructuringEllement(MORPH_RECT, Size(2 * g_nStructBLlementSize + 1, 2 * g_nStructElementSize + 1 ), Point(g_nStructELlementSize, g_nStructElementSize)); 调用之后,我们可以在接下来调用erode或dilate函数时,在第三个参数填保存了getStructuringElement返回值的Mat类型变量。对应于上面的示例,就是element变量。 第四个参数,Point类型的anchor,锚的位置,其有默认值(-1,-1),表示锚位于中心。 第五个参数,int类型的iterations,迭代使用erode(0)函数的次数,默认值为1 第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。 第七个参数,const Scalar&类型的borderValue,当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般不用去管它。需要用到它时,可以看官方文档中的createMorphologyFilter()函数,以得到更详细的解释。 使用Dilate函数,一般只需要填写前面的三个参数,后面的四个参数都有默认值,而且往往会结合getStructuringElement 一起使用


CV_EXPORTS_W void erode( InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() ); Description : Erode腐蚀 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。图像通道的数量可以是任意的,但图像深度应为CV_8U、CV_16U、CV_16S8、CV_32F或CV_64F其中之一。 第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。 第三个参数,InputArray类型的kernel,腐蚀操作的内核。为NULL时,表示的是使用参考点位于中心3x3的核。一般使用函数getStructuringElement配合这个参数的使用。getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵,具体看上文中dilate函数的第三个参数讲解部分。 第四个参数,Point类型的anchor,锚的位置。其有默认值(-1-1),表示锚位于单位(element)的中心,一般不用管它。 第五个参数,int类型的iterations,迢代使用erode()函数的次数,默认值为1。 第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。 第七个参数,const Scalar& 类型的BorderValue , 当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般不用去管它。需要用到它时,可以看官方文档中的createMorphologyFilter()函数以得到更详细的解释。


#include "opencv2/opencv.hpp" using namespace std; using namespace cv; int main(int argc , char * argv[]){ Mat srcImage = imread("C:/dev/cpp_test/kun.png",1); Mat dstImage_dilate ,dstImage_erode; srcImage.copyTo(dstImage_dilate); srcImage.copyTo(dstImage_erode); //show source image imshow("SRC" , srcImage); //dilate Mat kernel = getStructuringElement(MORPH_RECT,Size(15,15)); dilate(srcImage,dstImage_dilate,kernel); //erode erode(srcImage,dstImage_erode,kernel); //show dstinction image imshow("DST" , dstImage_dilate); imshow("DST2" , dstImage_erode); while(char(waitKey(10)) != 'q') {} return 0; }

#include "opencv2/opencv.hpp" #define OPREATION_SWITCH "Operation Switch" #define KERNEL_SIZE "Kernel Size" using namespace std; using namespace cv; int g_nOprationSwitch = 0; //0 for erode , 1 for dilate static void switch_onchange(int , void * ); static void process(int , void* ); struct my_data { Mat src; Mat dst; int kernel_size ; }; int main(int argc , char * argv[]){ int g_nStuctElementSize = 3 ; // 3 for deafult Mat srcImage = imread("C:/dev/cpp_test/kun.png",1); Mat dstImage; srcImage.copyTo(dstImage); my_data param = {srcImage,dstImage, g_nStuctElementSize}; //show source image namedWindow("SRC",0); imshow("SRC" , srcImage); //kernel Mat kernel = getStructuringElement(MORPH_RECT,Size(2*g_nStuctElementSize+1,2*g_nStuctElementSize+1),Point(g_nStuctElementSize,g_nStuctElementSize)); namedWindow("DST",0); erode(srcImage,dstImage,kernel); imshow("DST",dstImage); //Track bar for switch createTrackbar(OPREATION_SWITCH,"DST",&g_nOprationSwitch,1,switch_onchange, (void *) ¶m); //Track bar for kernel changed createTrackbar(KERNEL_SIZE,"DST",&g_nStuctElementSize,21,process, (void *)¶m); //show dstinction image imshow("DST" , dstImage); while(char(waitKey(10)) != 'q') {} return 0; } static void process(int kernel_size, void* param){ my_data inner_param = *(my_data *)param; Mat kernel = getStructuringElement(MORPH_RECT, Size( 2 * kernel_size +1 , 2 * kernel_size+1), Point(kernel_size,kernel_size)); //judge erode / dilate if(g_nOprationSwitch == 0){ erode(inner_param.src,inner_param.dst,kernel); } // erode else{ dilate(inner_param.src,inner_param.dst,kernel); }//dilate imshow("DST",inner_param.dst); } static void switch_onchange(int g_nOprationSwitch, void* param){ process(g_nOprationSwitch,param); }


首先,想要本着尽量减少全局变量的原则进行传参。 顺便加固对于指针和引用的用法。 1. 针对滚动条函数createTrackbar的参数再理解。 CV_EXPORTS int createTrackbar(const String& trackbarname, const String& winname, int* value, int count, TrackbarCallback onChange = 0, void* userdata = 0); 第一个参数 : trackbar的名字,没有争议 第二个参数: 窗口名字,仍然没有争议 第三个参数: callback函数的第一个参数, callback函数应该是callback_xxx(int , void *)的格式, 这里传入的是一个地址(指针类型) 第四个参数:回调函数 第五个参数: 需要额外传入的参数,这里只能是一个一维指针,所以,为了创建这样的一个对象,使用void * list[] = {} 的结构传入参数是不可取的,原因是这样是一个二维数组 那么此时就需要引入一个struct对象,或者是一个类对象,那么这里只是简单数据,推荐使用struct类型。 2. 再传入地址的时候,这里的地址其实是指针类型,不只是一个简单地址,所以需要切换指针到固定的类型,这样才可以进行相应转换

浙公网安备 33010602011771号