我们在用美颜相机或者直播时,相信都离不开一个效果那就是 美容 。这次我们就来分析一种常用滤波(双边滤波),刚好就可以实现一些美容效果。**双边滤波(Bilateral Filter)**是非线性滤波中的一种。这是一种结合图像的空间邻近度与像素值相似度的处理办法。在滤波时,该滤波方法同时考虑空间临近信息与颜色相似信息,在滤除噪声、平滑图像的同时,又做到边缘保存。双边滤波采用了两个高斯滤波的结合。一个负责计算空间邻近度的权值,也就是常用的高斯滤波器原理。而另一个负责计算像素值相似度的权值。在两个高斯滤波的同时作用下,就是双边滤波。
首先,我们不妨来回顾一下之前所讲的高斯滤波,**高斯滤波(Gauss Filter)**是线性滤波中的一种。在OpenCV图像滤波处理中,高斯滤波用于平滑图像,或者说是图像模糊处理,因此高斯滤波是低通的。其广泛的应用在图像处理的减噪过程中,尤其是被高斯噪声所污染的图像上。 高斯滤波的基本思想是: 图像上的每一个像素点的值,都由其本身和邻域内其他像素点的值经过加权平均后得到。其具体操作是,用一个核(又称为卷积核、掩模、矩阵)扫描图像中每一个像素点,将邻域内各个像素值与对应位置的权值相称并求和。从数学的角度来看,高斯滤波的过程是图像与高斯正态分布做卷积操作。大家不妨看看这篇文章:Android 性能优化实战 - 界面卡顿
直接的去看概念和文字,大家可能会有些蒙 B ,下面我们来讲通俗一些,如果只是对图片进行单纯的高斯模糊,那么无法较好的保留其轮廓信息,肯定是无法达到预期的效果。那么双边滤波是怎么做到的呢?为啥说他有美容效果?首先双边滤波是基于高斯滤波,但由于高斯滤波无法较好的保留轮廓信息,因此双边滤波就增加了一种方案,那就是考虑两点的色差值。请看上面这张图,头发和脸庞的交界处,它们两边的色差值比较大,那么我在做权重计算时就不考虑进来。也就是说图像轮廓边缘的色差往往比较大,如果我们加入色差值的判断,那么就可以较好的保留轮廓信息。
一、双边滤波的公式
g(i, j)代表输出点;
S(i, j)的是指以(i,j)为中心的(2N+1)(2N+1)的大小的范围;
f(k, l)代表(多个)输入点;
w(i, j, k, l)代表经过两个高斯函数计算出的值(这里还不是权值)
上述公式我们进行转化,假设公式中w(i,j,k,l)为m,则有
设 m1+m2+m3 … +mn = M,则有
此时可以看到,这明显是图像矩阵与核的卷积运算了。其中m1/M代表的第一个点(或最后一个点,看后面如何实现)的权值,而图像矩阵与核通过卷积算子作加权和,最终得到输出值。
接下来我们来讨论最关键的w(i, j, k, l)
ws为空间临近高斯函数,wr为像素值相似度高斯函数
二、OpenCV 的 bilateralFilter
/**
* 对图片进行美容
*/
void hairdressingBitmap(JNIEnv *env, jobject, jobject bitmap) {
Mat mat;
// java bitmap -> opencv mat
cv_helper::bitmap2mat(env, bitmap, mat);
// 双边滤波
Mat dst;
bilateralFilter(mat, dst, 10, 50, 10);
// opencv mat -> java bitmap
cv_helper::mat2bitmap(env, dst, bitmap);
}
上面的效果似乎还未达到我们想要的效果,整个图片看起来比较模糊,我们再对其做一次掩摸操作:
Mat final;
Mat kernel = (Mat_<int>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(dst, final, dst.depth(), kernel);
视频地址:https://pan.baidu.com/s/1-WwELv3s9Du8tKnXc0TODA
视频密码:0dqe