OpenCV 图像滤波:双边滤波算法

最近在看浅墨前辈的OpenCV教程来做一次复习,其中发现了一个挺有趣的之前没见过的算法,叫双边滤波算法。这个算法可以对图像进行平滑的同时尽量对高频信息进行保留(比如边缘和边角),而相对低频的区域则会被平滑。感觉浅墨一书中讲的还是有点不直观,这里给出我自己的一些理解。

直观理解

双边滤波算法本质是基于高斯滤波,目的是解决高斯滤波造成的边缘模糊。那么算法的做法就是想办法去“推断”出当前像素是否是边缘点或者接近边缘的点。

我们都知道,对图像进行空间域滤波的方法是使用一个结构元素(核)来对原图像进行卷积。比如说高斯核像是这样的:


高斯核

而这个结构元素就会对原图像进行卷积操作,从而得到一个新的图像,即输出图像。我们知道,这个结构元素是不会变的。但是!但是!但是!在双边滤波算法中就不是如此了。

为了使图像的边缘得到保留,就要根据当前被卷积像素的邻域进行观察,“推断”是否是边缘点和接近边缘的点。因此,结构元素就会改变,从而保留边缘点。

下面的一组图中,图a是原图像,图c是输出。而中间的图像是什么呢?显然,这是原图中根据某个点的邻域生成的,专属于这个点的结构元素!


作者给出的一幅图片

可以看到,原图中显然有一个灰度的突变,这就表示是边缘。灰度值高的地方不应该和灰度低的区域进行混合,所以,图像中接近边缘的一个点就会生成图b这样的结构元素。那么这个接近边缘的点在哪里呢?大概就在我标出的这个区域。


红色圆圈中的像素点大概会生成图b这样的结构元素

而生成这样的结构元素的方法,是将我们原本的高斯核,与一个能“推断”出是否在边缘点的结构元素相乘,如下图中间的结构元素


下面就给出数学定义

数学定义

双边滤波器的输出像素依赖于当前被卷积像素的邻域。i和j是当前被卷积像素的坐标点,k和l是邻域像素的坐标点。


双边滤波公式

加权系数ω由定义域核和值域核决定,是它们的乘积。定义域核就是高斯核,不解释


定义域核

而值域核就是用于“推断”是否是边缘点的方法,公式如下


值域核

可以看到,它取决于被卷积像素的灰度值和邻域像素的灰度值的差。我们知道,边缘会有较大的灰度变化,而这个公式就会使边缘和边缘另一边的区域生成比较小的权值,与被卷积像素的灰度值类似的区域会生成比较大的权值,就像之前图中的一个“断崖”。

"断崖"

相乘就得到加权系数ω


加权系数ω

编程实现

这里使用滑动条来观察一下参数对输出的变化。

/********************************************************************
 * Created by 杨帮杰 on 1/25/2019
 * Right to use this code in any way you want without
 * warranty, support or any guarantee of it working
 * E-mail: yangbangjie1998@qq.com
 * Association: SCAU 华南农业大学
 ********************************************************************/

#include <iostream>
#include <vector>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

#define IMG1 "/home/jacob/图片/77.jpg"

using namespace cv;
using namespace std;

int g_d = 15;
int g_sigmaColor = 20;
int g_sigmaSpace = 50;

Mat image1;
Mat image2;

void on_Trackbar(int, void*)
{
    bilateralFilter(image1, image2, g_d, g_sigmaColor, g_sigmaSpace);
    imshow("output", image2);
}

int main()
{
    image1= imread(IMG1);
    //resize(image1,image1,Size(image1.cols/2, image1.rows/2));

    if (!image1.data)
    {
        cout << "img1 没读到" <<endl;
        return 0;
    }

    image2 = Mat::zeros(image1.rows, image1.cols, image1.type());
    bilateralFilter(image1, image2, g_d, g_sigmaColor, g_sigmaSpace);

    namedWindow("output");

    createTrackbar("核直径","output", &g_d, 50, on_Trackbar);
    createTrackbar("颜色空间方差","output", &g_sigmaColor, 100, on_Trackbar);
    createTrackbar("坐标空间方差","output", &g_sigmaSpace, 100, on_Trackbar);

    imshow("input", image1);
    imshow("output", image2);

    waitKey();
    return 0;
}

输入
输出

明显,粗糙的皮肤得到了平滑。这个算法对皮肤不好的妹子有奇效→_→!

References:
Bilateral Filtering for Gray and Color Images
OpenCV学习笔记(七)中值、双边滤波

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 参考资料: 图像卷积与滤波的一些知识点 图像处理基本概念——卷积,滤波,平滑 1.卷积的基本概念 首先,我们有一个...
    keloli阅读 10,142评论 0 26
  • 本节主要记录OpenCV 两类五种常见的滤波方式: 线性滤波:方框滤波、均值滤波、高斯滤波非线性滤波: 中值滤波、...
    hehtao阅读 2,430评论 0 3
  • 不同图像灰度不同,边界处一般会有明显的边缘,利用此特征可以分割图像。需要说明的是:边缘和物体间的边界并不等同,边缘...
    大川无敌阅读 13,953评论 0 29
  • 一分钟微演讲练习打卡第八天,遇见美好的自己。 今日主题:接纳 上周末,宝贝电话告诉我说要和姐姐一起去...
    松子麻麻阅读 280评论 0 1
  • 当包含了相关的多重因素的拖延行为时,就属于复杂拖延了。复杂拖延,是指伴随着诸如“自我怀疑”或“完美主义”等其他因素...
    合一成长导师阅读 297评论 0 4