OpenCV数字图像处理基于C++之图像形态学处理详解
qq_43784519 人气:01、图像腐蚀
原理:腐蚀用来收缩或细化二值图像中的前景,借此实现去噪声、元素分割等功能。和所有形态学滤波器一样,腐蚀和膨胀这两个滤波器的作用范围是由结构元素定义的像素集。在某个像素上应用结构元素时,结构元素的锚点与该像素对齐,所有与结构元素相交的像素就包含在当前集合中。腐蚀就是把当前像素替换成所定义像素集合中的最小像素值;膨胀是腐蚀的反运算,它把当前像素替换成所定义像素集合中的最大像素值。由于输入的二值图像只包含黑色(值为0)和白色(值为255)像素,因此每个像素都会被替换成白色或黑色像素。
要形象地理解这两种运算的作用,可考虑背景(黑色)和前景(白色)的物体。腐蚀时,如果结构元素放到某个像素位置时碰到了背景(即交集中有一个像素是黑色的),那么这个像素就变为背景;膨胀时,如果结构元素放到某个背景像素位置时碰到了前景物体,那么这个像素就被标为白色。正因如此,图像腐蚀后物体尺寸会缩小(形状被腐蚀),而图像膨胀后物体会扩大。在腐蚀图像中,有些面积较小的物体(可看作背景中的“噪声”像素)会彻底消失。与之类似,膨胀后的物体会变大.而物体中一些“空隙”会被填满。OpenCV默认使用3×3正方形结构元素。在调用函数时,就能得到默认的结构元素。你也可以通过提供一个矩阵来指定结构元素的大小(以及形状),矩阵中的非零元素将构成结构元素。
作用:去除图像中的某些部分以及会缩小细化目标
1.1 CV腐蚀函数
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() ); src 输入图像;通道的数量可以是任意的,但是深度值应该是以下之一: CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. dst 和源图像同样大小和类型的输出图像。 kernel 用于腐蚀的结构元素;如果element=Mat(),是一个3 x 3的矩形结构元素. Kernel 可以通过使用getStructuringElement来创建。 anchor 素中的锚点的位置,默认是值(-1,-1),也就是说锚点在元素的中心位置。 iterations 腐蚀的迭代次数。 borderType像素外推方法。参见#BorderTypes, BORDER_WRAP不支持。 borderValue 固定边缘的情况下的边缘值。 参考 dilate,morphologyEx,getStructuringElement
Mat cv::getStructuringElement( int shape, Size ksize, Point anchor = Point(-1,-1) ) 参数1:结构元的形状(0:矩形结构元;1:十字架结构元;2:椭圆结构元); 参数2:结构元大小(size(m, n)); 参数3:结构元中心点所在位置(point(x, y))默认为中心点
Mat element = getStructuringElement(0, Size(3, 3)); //构造矩形结构元素 Mat image_erosion; erode(image_bw, image_erosion, element, Point(-1, -1), 3); //执行腐蚀操作 imshow("image_erosion", image_erosion);
原图
二值图
CV腐蚀
1.2 自定义腐蚀函数
void erode_my(Mat &src,Mat &dst,int size) { for (int i = 0; i < src.rows; ++i) { for (int j = 0; j < src.cols; ++j) { uchar minV = 255; //uchar maxV = 0; //遍历周围最小像素值 for (int yi = i - size / 2; yi <= i + size / 2; yi++) { for (int xi = j - size / 2; xi <= j + size / 2; xi++) { if (xi < 0 || xi >= src.cols || yi < 0 || yi >= src.rows) { continue; } minV = (std::min<uchar>)(minV, src.at<uchar>(yi, xi)); //maxV = (std::max<uchar>)(maxV, src.at<uchar>(yi, xi)); } } dst.at<uchar>(i, j) = minV; } } }
自定义腐蚀
1.3 对比
erode_my(image_bw, image_erosion_my,9); 当腐蚀结构扩大到9×9时效果基本与cv自带函数一致。
2、图像膨胀
原理:腐蚀用来收缩或细化二值图像中的前景,借此实现去噪声、元素分割等功能。腐蚀过程:用结构元来逐个像素扫描被腐蚀图像,并根据结构元和被腐蚀图像的关系确定腐蚀结果。
注意,腐蚀操作等形态学操作,是逐个像素地来确定值的,每次判定的点都与结构元中心点所对应,如果结构元完全处于前景图像中,就将结构元中心点所对应的腐蚀结果图像中的像素点处理为前景色(如1)。如果结构元不完全处于前景图像中,就将结构元中心点所对应的腐蚀结果图像中的像素点处理为背景色(如0)。(结构元也被称为核)
作用:增大图像中的目标,或者填充、连接某些目标。
2.1 CV膨胀函数
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() ); src 输入图像;通道的数量可以是任意的,但是深度值应该是以下之一:CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. dst 和源图像同样大小和类型的输出图像。 kernel 膨胀核元素,如果elemenat=Mat(), 是一个3 x 3的矩形核元素,核可以使用getStructuringElement来创建。 anchor 元素中的锚点的位置,默认是值(-1,-1),也就是说锚点在元素的中心位置。 iterations 膨胀的迭代次数。 borderType 像素外推方法。参见#BorderTypes, BORDER_WRAP不支持。 borderValue 固定边缘的情况下的边缘值。 参考:erode,morphologyEx,getStructuringElement
//膨胀 Mat element = getStructuringElement(0, Size(3, 3)); //构造矩形结构元素 Mat image_dilate; dilate(image_bw, image_dilate, element, Point(-1, -1), 9); //执行膨胀操作 imshow("image_dilate", image_dilate);
二值图
CV膨胀
2.2 自定义膨胀函数
void dilate_my(Mat& src, Mat& dst, int size) { for (int i = 0; i < src.rows; ++i) { for (int j = 0; j < src.cols; ++j) { //uchar minV = 255; uchar maxV = 0; //遍历周围最大像素值 for (int yi = i - size / 2; yi <= i + size / 2; yi++) { for (int xi = j - size / 2; xi <= j + size / 2; xi++) { if (xi < 0 || xi >= src.cols || yi < 0 || yi >= src.rows) { continue; } //minV = (std::min<uchar>)(minV, src.at<uchar>(yi, xi)); maxV = (std::max<uchar>)(maxV, src.at<uchar>(yi, xi)); } } dst.at<uchar>(i, j) = maxV; } } }
自定义膨胀
2.3 对比
dilate_my(image_bw, image_dilate_my, 9); 当膨胀结构扩大到9×9时效果基本与cv自带函数一致。
腐蚀图像相当于对其反色图像膨胀后再取反色;
膨胀图像相当于对其反色图像腐蚀后再取反色。
3、开运算
原理:先腐蚀,再膨胀。
作用:平滑物体轮廓、断开狭窄的狭颈、消除细长的突出和物体。可以去掉图像上一些小的对象。(假设图像前景色是白色,背景色是黑色)
原图
3.1 方法一
//先腐蚀后膨胀 Mat open_image; Mat element = getStructuringElement(0, Size(3, 3)); //构造矩形结构元素 erode(image_bw, image_erosion, element, Point(-1, -1), 3); //执行腐蚀操作 dilate(image_erosion, open_image, element, Point(-1, -1), 3); //执行膨胀操作 imshow("open", open_image);
3.2 方法二
morphologyEx(image_bw, open_image, MORPH_OPEN, element); imshow("open2", open_image);
4、闭运算
原理:先膨胀,再腐蚀。
作用:闭运算可以填充小洞,填充小的噪点。
4.1 方法一
Mat close_image; Mat element = getStructuringElement(0, Size(3, 3)); //构造矩形结构元素 dilate(image_bw, image_dilate, element, Point(-1, -1), 3); //执行膨胀操作 erode(image_dilate, close_image, element, Point(-1, -1), 3); //执行腐蚀操作 imshow("close", close_image);
4.2 方法二
morphologyEx(image_bw, close_image, MORPH_CLOSE, element); imshow("close2", close_image);
4.3 morphologyEx函数介绍
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)参数1:InputArray src 输入图像,图像数据类型必须为CV_8U, CV_16U, CV_16S, CV_32F or CV_64F中的一种。 (2)参数2:OutputArray dst 输出图像,数据类型与大小和输入图像一样。 (3)参数3:int op 形态学处理的类型: MORPH_ERODE = 0:腐蚀处理 MORPH_DILATE = 1:膨胀处理 MORPH_OPEN = 2:开运算处理 MORPH_CLOSE = 3:闭运算处理 MORPH_GRADIENT = 4:形态学梯度 MORPH_TOPHAT = 5:顶帽变换 MORPH_BLACKHAT = 6:黑帽变换 MORPH_HITMISS = 7 :击中-击不中变换 (4)参数4:InputArray kernel结构元矩阵 (5)参数5:Point anchor = Point(-1,-1) 结构元中心点, 默认值Point(-1,-1), 表示正中心 (6)参数6:int iterations = 1 腐蚀膨胀处理的次数,默认值为1; 如果是开运算闭运算,次数表示先腐蚀或者膨胀几次,再膨胀腐蚀几次,而不是开运算闭运算几次: 如开运算且次数为2:erode -> erode -> dilate -> dilate (7)参数7:int borderType = BORDER_CONSTANT 图像边框插值类型,默认类型为固定值填充 BORDER_CONSTANT = 0:固定值 i 填充:iiiiii | abcdefgh | iiiiiii BORDER_REPLICATE = 1:两端复制:aaaaaa | abcdefgh | hhhhhhh BORDER_REFLECT = 2:镜像复制:fedcba | abcdefgh | hgfedcb BORDER_WRAP = 3:去除一端的值然后复制: cdefgh | abcdefgh | abcdefg BORDER_REFLECT_101 = 4:去除一端的值然后镜像复制: gfedcb|abcdefgh|gfedcba BORDER_TRANSPARENT = 5:推导赋值 uvwxyz | abcdefgh | ijklmno BORDER_REFLECT101 = BORDER_REFLECT_101: same as BORDER_REFLECT_101 BORDER_DEFAULT = BORDER_REFLECT_101: same as BORDER_REFLECT_101 BORDER_ISOLATED = 16:< do not look outside of ROI (8)参数8:const Scalar& borderValue = morphologyDefaultBorderValue() 文档中说明:param borderValue Border value in case of a constant border. The default value has a special meaning.
5、顶帽运算
原理:顶帽(或礼帽)运算是原始图像减去图像开运算的结果。
顶帽运算:原始图像 — 图像开运算
作用:得到图像的噪声。如下图所示:
5.1 方法一
//构造结构元 Mat kernel = getStructuringElement(0, Size(5, 5)); Mat image_lm; //顶帽变换(礼帽变换) morphologyEx(image_bw, image_lm, 5, kernel); cv::imshow("image_lm", image_lm);
5.2 方法二
Mat image_lm2; //**顶帽运算:原始图像 — 图像开运算** //dst=img1-img2;//这两个减法效果相同 若dst<0,则dst=0 subtract(image_bw,open_image2, image_lm2);//注意:要求被处理图片尺寸一致 cv::imshow("image_lm2",image_lm2);
Mat image_lm2; absdiff(image_bw, open_image2, image_lm2);//若dst<0,则dst=|dst|>=0 用于检测两幅相似图像的不同点,效果比上面的两种减法好 cv::imshow("image_lm2", image_lm2);
6、黑帽运算
原理:黑帽运算是图像闭运算操作减去原始图像的结果。
黑帽运算:闭运算 — 原始图像
作用:得到图像内部的小孔,或者前景色中的小黑点。如下图所示:
6.1 方法一
//构造结构元 Mat kernel = getStructuringElement(0, Size(5, 5)); //底帽变换(黑帽变换) Mat image_hm; morphologyEx(image_bw, image_hm, 6, kernel); cv::imshow("image_hm", image_hm);
6.2 方法二
Mat image_hm2; subtract(image_bw, close_image2, image_hm2);//注意:要求被处理图片尺寸一致 cv::imshow("image_hm2", image_hm2);
Mat image_hm2; absdiff(image_bw, close_image2, image_hm2);//若dst<0,则dst=|dst|>=0 用于检测两幅相似图像的不同点,效果比上面的两种减法好 cv::imshow("image_hm2", image_hm2);
7、形态学梯度
原理:膨胀图与腐蚀图之差;
作用:对二值图进行这一操作可以得到图像中白色区域的边界,因此可以用形态学梯度来保留物体的边界轮廓。
7.1 方法一
//构造结构元 Mat kernel = getStructuringElement(0, Size(5, 5)); Mat image_lm; //形态学梯度 morphologyEx(image_bw, image_td, 4, kernel); cv::imshow("image_td", image_td);
7.2 方法二
Mat image_tw2; subtract(image_dilate, image_erosion, image_tw2);//注意:要求被处理图片尺寸一致 cv::imshow("image_tw2", image_tw2);
Mat image_tw2; absdiff(image_dilate, image_erosion, image_tw2);//若dst<0,则dst=|dst|>=0 用于检测两幅相似图像的不同点,效果比上面的两种减法好 cv::imshow("image_tw2", image_tw2);
部分参考来自:数字图像处理(c++ opencv)–持续更新 - 知乎 (zhihu.com)
总结
加载全部内容