OpenCV4学习笔记(15)——图像边缘保留滤波

本次要整理记录的是关于图像边缘保留滤波算法(EPF)的相关内容,主要有高斯双边模糊、均值迁移模糊和快速边缘保留滤波算法。这些算法在OpenCV中都提供了完善的API可以调用,我只是对其基本原理做了些许了解,并在此基础上学习各个参数的调教,下面就逐一来进行整理。

- 高斯双边模糊

说到高斯双边模糊感觉有些高大上,但是说到高斯模糊就显得接地气多了,之前曾经整理过,高斯模糊就是利用一个不断移动的窗口来获取该区域中各个像素点的值,并根据高斯分布来为中心像素点邻域的各个像素点赋予权重,最后根据这个权重来加权求和,从而得出中心像素点的新的像素值。在高斯模糊的权重中,主要是以邻域像素点与中心像素点的空间距离来计算的,这样子的话呢,如果是同样在这一个领域里,出现了像素值差异很大的像素点,那这些像素点很有可能是属于边缘的,可是高斯模糊计算权重并没有把这些考虑进去,所以这些很可能属于边缘的像素点仍然被模糊掉了。所以为了解决这个问题,就出现了高斯双边模糊,不仅考虑领域中其他像素点在空间分布上对中心像素点的影响,同时考虑邻域中其他像素点的RGB三通道像素值的影响。也就是说普通的高斯模糊,只从(x,y)两个维度计算邻域像素点权重,只在空间上使用了一个滤波器;而高斯双边模糊呢,管的多一点,不仅仅是x、y两个维度,还考虑了RGB的影响,所以是从(x,y,R,G,B)五个维度来计算权重,既在空间上使用了一个滤波器,又在色彩空间上使用了一个滤波器,所以被称为双边滤波。
说白了,高斯双边模糊就是:不仅考虑空间分布权重,同时考虑像素值分布权重,将像素值差异过大的区域(即边缘)进行保留。
这一看起来五个维度,就知道代码实现一定非常困难,还好OpenCV已经封装好了针对这种算法的API,我们可以直接进行调用(否则要die)。下面看下代码:

	Mat test_image;
	test_image = imread("D:\\opencv_c++\\opencv_tutorial\\data\\images\\example.png");
	Mat bila_image;
	bilateralFilter(test_image, bila_image, 0, 100, 10, 4);
	imshow("bila_image", bila_image);
	imshow("test_image", test_image);
	//合并显示
	Mat mergeImage_bila = Mat::zeros(test_image.rows, test_image.cols * 2, test_image.type());
	Rect left_rect(0, 0, test_image.cols, test_image.rows);
	Rect right_rect(test_image.cols, 0, test_image.cols, test_image.rows);
	Mat left_roi = mergeImage_bila(left_rect);
	Mat right_roi = mergeImage_bila(right_rect);
	test_image.copyTo(left_roi);
	bila_image.copyTo(right_roi);
	imshow("mergeImage_bila", mergeImage_bila);

其中最主要的就是:bilateralFilter(test_image, bila_image, 0, 100, 10, 4)这个专门实现高斯双边模糊的API。介绍一下它的参数:
第一个参数:需要进行处理的输入图像;
第二个参数:处理完成后的输出图像;
第三个参数d: 表示在过滤过程中每个像素邻域的直径范围。如果这个值是非正数,则函数会从第五个参数sigmaSpace来计算该值。官方文档中推荐对于实时处理中建议值为d=5;非实时建议d=9;也可以直接设置为0,由sigmaSpace来自行计算。该参数设置越大,效果更好但是速度会非常慢。
第四和第五个参数sigmaColor和sigmaSpace:当小于10时对滤波器影响很小,当大于150时会使图像变得卡通化;sigmaColor可以设置稍大,越大表明该像素邻域内有越宽广的颜色会被混合到一起,产生较大的半相等颜色区域;sigmaSpace可设置偏小(>=10),使运行速度提高,如果参数d为0,则参数d跟sigmaSpace成正比。
最后处理效果如下:在这里插入图片描述
在这里插入图片描述
通过对比能够很明显的看出,高斯双边模糊将人脸的边缘轮廓很好的保留了下来,但是同样实现了一个非常好的平滑模糊效果。而且在参数设置得当的情况下,就达到了一种磨皮美颜的效果,话说本来想用自己照片尝试一下,想了想还是算了。。。。。。。。。。。。。

- 均值迁移模糊

均值迁移模糊的名字还是很顾名思义的,三个关键词:均值、迁移、模糊。
首先仍然会使用两个窗口,一个是物理空间窗口,一个是色彩空间窗口,利用物理空间窗口内的元素去进行均值计算得到梯度dx和dy,利用色彩空间窗口内的元素进行均值计算得到新的RGB值,然后通过dx和dy得到物理窗口需要移动的方向和距离,并进行窗口迁移;在迁移到新的物理空间窗口后,同样计算梯度dx和dy,并在新的色彩空间计算RGB值。通过不断的迁移,直到满足了设定好的停止条件,就停止窗口迁移,并把最终的RGB值赋给中心像素点。
均值迁移模糊属于图像在色彩层面的平滑滤波,可以中和色彩分布相近的颜色,平滑色彩细节,侵蚀掉面积较小的颜色区域,同样具有边缘保留效果。经常用在对图像进行分水岭分割操作之前的降噪过程,可以大幅度提升分水岭分割的效果。下面给出OpenCV中的API代码实现:

	Mat meanShift_image;
	pyrMeanShiftFiltering(test_image, meanShift_image, 15, 30);
	//合并显示
	Mat mergeImage_meanShift = Mat::zeros(test_image.rows, test_image.cols * 2, test_image.type());
	Rect left_rect(0, 0, test_image.cols, test_image.rows);
	Rect right_rect(test_image.cols, 0, test_image.cols, test_image.rows);
	Mat left_roi = mergeImage_meanShift(left_rect);
	Mat right_roi = mergeImage_meanShift(right_rect);
	test_image.copyTo(left_roi);
	meanShift_image.copyTo(right_roi);
	imshow("mergeImage_meanShift", mergeImage_meanShift);

其中主要代码是:pyrMeanShiftFiltering(test_image, meanShift_image, 15, 30)
其中第一个参数:需要处理的输入图像;
第二个参数:处理完成的输出图像;
第三个参数sp:定义的迁移物理空间半径大小;
第四个参数sr:定义的迁移色彩空间半径大小;
关键参数是sp和sr的设置,二者设置的值越大,对图像色彩的平滑效果越明显,同时函数耗时也越多
最后两个参数分别为金字塔层数、迭代终止条件,使用default值即可。
下面是效果图:
在这里插入图片描述
通过对比可以看出,均值迁移模糊同样具有明显的边缘保留作用,并且把人脸部那些小的颜色区域(色斑)给侵蚀掉的。尤其是右边的头发和鬓角的区域,肤色和发色发生了中和,色彩细节被抹除掉了,留下了半相等的颜色。均值迁移模糊后的图像给人的视觉效果,就好像是一幅油画一样,具有非常浓厚的涂抹感。

- 快速边缘保留滤波算法

高斯双边滤波和均值迁移滤波这两种滤波算法都具有不错的边缘保留效果,在计算的时候使用了五维向量(x,y,B,G,R),然而它们带来好的效果的同时,也带来了巨大的运算量,在运算速度上都属于比较慢的滤波器。所以在某些场合下如实时处理等,这些滤波算法并不适合派上用场,所以OpenCV针对这个问题,又提供了快速边缘保留滤波算法,这名字听起来就知道它是在保留边缘的基础上对运算量进行缩减,从而提高运行速度。快速边缘保留滤波算法是通过将五个维度的向量等价变换到低维度空间,实现了数据降维与快速计算,当然了在提升速度的同时对于效果可能就会有所牺牲,总归是有舍必有得。
下面是代码实现:

	Mat image_fast_edge_Recursive, image_fast_edge_Normalized_Convolution;
	edgePreservingFilter(test_image, image_fast_edge_Recursive, 1, 120, 0.4);			//递归滤波器, flag = 1;
	edgePreservingFilter(test_image, image_fast_edge_Normalized_Convolution, 2, 120, 0.4);			//归一化卷积滤波器, flag = 2

	//合并显示
	Mat mergeImage = Mat::zeros(test_image.rows, test_image.cols * 3, test_image.type());
	Rect left_rect(0, 0, test_image.cols, test_image.rows);
	Rect median_rect(test_image.cols, 0, test_image.cols, test_image.rows);
	Rect right_rect(test_image.cols * 2, 0, test_image.cols, test_image.rows);
	Mat left_roi = mergeImage(left_rect);
	Mat median_roi = mergeImage(median_rect);
	Mat right_roi = mergeImage(right_rect);
	test_image.copyTo(left_roi);
	image_fast_edge_Recursive.copyTo(median_roi);
	image_fast_edge_Normalized_Convolution.copyTo(right_roi);
	imshow("mergeImage", mergeImage);

主要API:edgePreservingFilter(test_image, image_fast_edge_Recursive, 1, 120, 0.4)
其中第一个参数:要处理的输入图像;
第二个参数:处理完成的输出图像;
第三个参数flag:可选的滤波器类型,OpenCV中提供了两种滤波器:RECURS_FILTER(递归滤波器)和NORMCONV_FILTER(归一化卷积滤波器),分别的flag为1和2;
第四、五个参数:sigma_s取值为(0,200);sigma_r取值为(0,1);
当sigma_s 取值不变时,sigma_r 越大图像滤波效果越明显;
当sigma_r 取值不变时,窗口sigma_s 越大图像模糊效果越明显;
当sgma_r取值很小时,窗口sigma_s 取值无论如何变化,图像双边滤波效果都不好。
下面是效果图:
在这里插入图片描述
在上图中,最左边为原图,中间是递归滤波器处理图,最右边是归一化卷积滤波器处理图。可以看出,快速边缘保留滤波器能够实现和高斯双边模糊类似的效果,但是时间上略有优势。而两种滤波器的对比,感觉递归滤波器处理后的图像其细节要丰富一点,人脸轮廓也更丰满一些;而归一化卷积滤波器处理后的图像感觉会更亮一些,对比度相比之下会稍微低一些。

总结:不同的边缘保留滤波算法都有各自的应用场合,而且也都具有不错的效果,可以根据具体需求来选择合适的算法。

本次整理到此结束,谢谢阅读~

PS:本人的注释比较杂,既有自己的心得体会也有网上查阅资料时摘抄下的知识内容,所以如有雷同,纯属我向前辈学习的致敬,如果有前辈觉得我的笔记内容侵犯了您的知识产权,请和我联系,我会将涉及到的博文内容删除,谢谢!

发布了36 篇原创文章 · 获赞 43 · 访问量 1811

猜你喜欢

转载自blog.csdn.net/weixin_45224869/article/details/104625134