之前我们介绍了 双边滤波 的原理,本文记录在双边滤波基础上简单封装的常见应用 —— 联合双边滤波。
双边滤波(bilateral filter, BF)的思想是利用当前图像的纹理信息结合高斯滤波核为每个像素提供单独的平滑滤波器,以达到在保留图像边缘的同时执行平滑操作。
如果我们需要用其他图像的边缘纹理信息来平滑当前图像时,BF 就不能直接用了,在这种场景下,其实原理是一样的,只是计算像素权重那一步使用的图像不是当前图像,这种应用场景的双边滤波叫做 联合双边滤波 (Joint Bilateral Filter, LBF)
当前待处理的图像 I , 用于提供纹理信息的向导图 \tilde{I} , 二者具有相同尺寸。
$$ J_{p}=\frac{1}{k_{p}} \sum_{q \in \Omega} I_{q} f(|p-q|) g\left(\left|I_{p}-I_{q}\right|\right) $$
p 为待计算的像素位置,q 为邻域像素位置, \Omega 为 p 周围的邻域范围,f 为高斯权重计算函数,g 为颜色差异权重计算函数,注意 BF 中计算颜色差异权重时使用的是待处理图像 I .
$$ J_{p}=\frac{1}{k_{p}} \sum_{q \in \Omega} I_{q} f(|p-q|) g\left(\left|\tilde{I}_{p}-\tilde{I}_{q}\right|\right) $$
在opencv的contrib模块中,也提供了联合双边滤波的API:jointBilateralFilter(引导图,待滤波的图,滤波后的图,像素邻域直径,灰度域sigma,空间域sigma)。
1234567891011121314151617 | #include <opencv2/opencv.hpp>#include <ximgproc.hpp> int main(){ cv::Mat src = cv::imread("data/dp.png", 1); // 原始带噪声的深度图 cv::Mat joint = cv::imread("data/teddy.png", 0); cv::Mat dst; cv::ximgproc::jointBilateralFilter(joint, src, dst, -1, 3, 9); imshow("src", src); imshow("joint", joint); imshow("jointBilateralFilter", dst); cv::waitKey(0); return 0;} |
---|
Python opencv 暂不支持导向滤波, 在 opencv-contrib-python
包的 ximgproc
模块提供了 JBF。
12345678 | cv2.ximgproc.guidedFilter(guide,src,radius,eps,dDepth) guide: 导向图片,单通道或三通道 src: 输入图像对象矩阵,可以为单通道或多通道 radius:用来计算卷积核的领域直径 eps:规范化参数, eps的平方类似于双边滤波中的sigmaColor(颜色空间滤波器标准偏差值) (regularization term of Guided Filter. eps2 is similar to the sigma in the color space into bilateralFilter.) dDepth: 输出图片的数据深度 |
---|
1234 | import cv2 as cvsrc = cv.imread(r"img.jpg")dst = cv.ximgproc.guidedFilter(src,src,33,2,-1) |
---|
Halcon 中 bilateral_filter 算子天然支持 JBF,为啥呢,Joint BF 不是用别的图的梯度信息的吗? 但是当这张图就是自己的话 JBF 就可以退化成 BF。
1 | bilateral_filter(Image, ImageJoint : ImageBilateral : SigmaSpatial, SigmaRange, GenParamName, GenParamValue : ) |
---|
1234 | read_image (test_img, 'test_img.bmp')read_image (guide_img, 'guide_img.bmp')bilateral_filter (test_img, guide_img, result_img, 20, 10, [], []) |
---|
测试图像:
引导图像:
效果图: