Android OpenCV(二十一):双边滤波

双边滤波

高斯滤波是以距离为权重,设计滤波模板作为滤波系数,只考虑了像素间的空间位置上的关系,因此滤波的结果会丢失边缘的信息。

高斯滤波的缺陷如下图所示:平坦区域正常滤波,图像细节没有变化,而在突变的边缘上,因为只使用了距离来确定滤波权重,导致边缘被模糊。

在高斯基础上,进一步优化,叠加了像素值的考虑,因此也就引出了双边滤波,一种非线性滤波,滤波效果对保留边缘更有效。

为了理解双边滤波的距离和像素差两个影响因素,先说明下面两个概念帮助理解。

空间距离:当前点距离滤波模板中心点的欧式距离。

空间距离

灰度距离:当前点距离滤波模板中心点的灰度的差值的绝对值。

灰度距离

双边滤波的核函数是空间域核与像素范围域核的综合结果:

1)在图像的平坦区域,像素值变化很小,那么像素差值接近于0,对应的像素范围域权重接近于1,此时空间域权重起主要作用,相当于进行高斯模糊;

2)在图像的边缘区域,像素值变化很大,那么像素差值大,对应的像素范围域权重变大,即使距离远空间域权重小,加上像素域权重总的系数也较大,从而保护了边缘的信息。

双边滤波的效果如下图,在突变的边缘上,使用了像素差权重,所以很好的保留了边缘。

双边滤波效果

双边滤波的原理如下图所示。

双边滤波原理

【引用:https://www.cnblogs.com/pingwen/p/12539722.html】

API

public static void bilateralFilter(Mat src, Mat dst, int d, double sigmaColor, double sigmaSpace, int borderType) 
  • 参数一:src,待双边滤波图像,图像数据类型为必须是CV_8U、CV_32F和CV_64F三者之一,并且通道数必须为单通道或者三通道。
  • 参数二:dst,双边滤波后的图像,尺寸和数据类型与输入图像src相同。
  • 参数三:d,滤波过程中每个像素邻域的直径,如果这个值是非正数,则由第五个参数sigmaSpace计算得到。当滤波器的直径大于5时,函数的运行速度会变慢,因此如果需要在实时系统中使用该函数,建议将滤波器的半径设置为5,对于离线处理含有大量噪声的滤波图像时,可以将滤波器的半径设为9,当滤波器半径为非正数的时候,会根据空间滤波器的标准差计算滤波器的直径
  • 参数四:sigmaColor,颜色空间滤波器的标准差值,这个参数越大表明该像素领域内有越多的颜色被混合到一起,产生较大的半相等颜色区域。
  • 参数五:sigmaSpace,空间坐标中滤波器的标准差值,这个参数越大表明越远的像素会相互影响,从而使更大领域中有足够相似的颜色获取相同的颜色。当第三个参数d大于0时,邻域范围由d确定,当第三个参数小于等于0时,邻域范围正比于这个参数的数值。
  • 参数六:borderType,像素外推法选择标志。默认参数为BORDER_DEFAULT,表示不包含边界值倒序填充。

操作

/**
 * 双边滤波
 * author: yidong
 * 2020/5/1
 */
class BilateralFilterActivity : CardGalleryActivity() {

    override fun buildCards() {
        val bgr = Utils.loadResource(this, R.drawable.timg)
        val source = Mat()
        Imgproc.cvtColor(bgr, source, Imgproc.COLOR_BGR2RGB)
        bgr.release()
        addCardFromMat("原图", source, 240)
        bilateralFilter(source)
        source.release()
    }

    private fun bilateralFilter(source: Mat) {
        val dst9 = Mat()
        Imgproc.bilateralFilter(source, dst9, 9, 10.0, 10.0)
        addCardFromMat("双边滤波 直径9X9 标准差10", dst9, 240)
        dst9.release()

        val dst25 = Mat()
        Imgproc.bilateralFilter(source, dst25, 25, 10.0, 10.0)
        addCardFromMat("双边滤波 直径25X25 标准差10", dst25, 240)
        dst25.release()

        val shift9 = Mat()
        Imgproc.bilateralFilter(source, shift9, 25, 100.0, 100.0)
        addCardFromMat("双边滤波 直径25X25 标准差值100", shift9, 240)
        shift9.release()

        val shift25 = Mat()
        Imgproc.bilateralFilter(source, shift25, 25, 200.0, 200.0)
        addCardFromMat("双边滤波 直径25X25 标准差值200", shift25, 240)
        shift25.release()
    }
}

效果

双边滤波

通过结果可以知道,滤波器的直径对于滤波效果具有重要的影响,滤波器直径越大,滤波效果越明显;同时当滤波器半径相同时,标准差值越大,滤波效果越明显。另外通过结果也可以看出双边滤波确实能对人脸起到美颜的效果。

源码

https://github.com/onlyloveyd/LearningAndroidOpenCV

扫码关注,持续更新

回复【计算机视觉】获取计算机视觉相关必备学习资料
回复【Android】获取Android,Kotlin必备学习资料

onlyloveyd CSDN认证博客专家 Android Kotlin OpenCV
个人公众号【OpenCV or Android】,热爱Android、Kotlin、Flutter和OpenCV。毕业于华中科技大学计算机专业,曾就职于华为武汉研究所。目前在三线小城市生活,专注技术与研发。
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页