本文转载自贾志刚老师的博客https://blog.csdn.net/jia20003/article/details/78415384
-
各向异性滤波的定义及应用范围
对图像来说各向异性就是在每个像素点周围四个方向上梯度变化都不一样,滤波的时候我们要考虑图像的各向异性对图像的影响,而各向同性显然是说各个方向的值都一致,常见的图像均值或者高斯均值滤波可以看成是各向同性滤波。
各向异性扩散滤波是将图像看成物理学的力场或者热流场,图像像素总是向跟他的值相异不是很大的地方流动或者运动,这样那些差异大的地方(边缘)就得以保留,所以本质上各向异性滤波是图像边缘保留滤波器(EPF)。主要是用来平滑图像的,克服了高斯模糊的缺陷,和双边滤波(各向同性滤波)很像。
-
各向异性滤波公式
其中
称为扩散因子,当q=1时称为正常扩散,当q<1时称为次扩散,当q>1时称为超扩散。
在不同时刻,扩散过程可以表示如下:
I就是图像,t表示当前的迭代次数,四个散度公式就是在当前四个方向上求导,得到结果与系数乘积并求和。各向异性就是四个方向的系数各不相同,如果相同就称为各向同性。
四个方向的导数计算如下:
四个方向的导热系数计算如下:
上述公式需要初始化三个输入参数,
-
opencv代码实现
原图及效果图:
opencv代码:
#include<opencv2\opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
float k = 15;
float lambda = 0.25;
int t = 20;
void anisotropy_demo(Mat &image, Mat &result);
int main(int argc, char** argv) {
Mat src = imread("1.jpg");
imshow("input image", src);
//转换图像数据类型
vector<Mat> mv;
vector<Mat>results;
split(src, mv);//通道分离
for (size_t i = 0; i < mv.size(); i++)
{
Mat m = Mat::zeros(src.size(), CV_32FC1);
mv[i].convertTo(m, CV_32FC1);
results.push_back(m);
}
//迭代滤波
Mat copy = Mat::zeros(src.size(), CV_32FC1);
for (size_t i = 0; i < t; i++)
{
anisotropy_demo(results[0], copy);
copy.copyTo(results[0]);
anisotropy_demo(results[1], copy);
copy.copyTo(results[1]);
anisotropy_demo(results[2], copy);
copy.copyTo(results[2]);
}
//归一化
normalize(results[0], results[0], 0, 255, NORM_MINMAX);
normalize(results[1], results[1], 0, 255, NORM_MINMAX);
normalize(results[2], results[2], 0, 255, NORM_MINMAX);
//格式转换
results[0].convertTo(mv[0], CV_8UC1);
results[1].convertTo(mv[1], CV_8UC1);
results[2].convertTo(mv[2], CV_8UC1);
//通道合并
Mat dst;
merge(mv, dst);
imshow("结果图", dst);
waitKey(0);
return 0;
}
void anisotropy_demo(Mat &image, Mat &result) {
int width = image.cols;
int height = image.rows;
// 四邻域梯度
float n = 0, s = 0, e = 0, w = 0;
// 四邻域系数
float nc = 0, sc = 0, ec = 0, wc = 0;
float k2 = k*k;
for (int row = 1; row < height - 1; row++) {
for (int col = 1; col < width - 1; col++) {
// gradient
n = image.at<float>(row - 1, col) - image.at<float>(row, col);
s = image.at<float>(row + 1, col) - image.at<float>(row, col);
e = image.at<float>(row, col - 1) - image.at<float>(row, col);
w = image.at<float>(row, col + 1) - image.at<float>(row, col);
nc = exp(-n*n / k2);
sc = exp(-s*s / k2);
ec = exp(-e*e / k2);
wc = exp(-w*w / k2);
result.at<float>(row, col) = image.at<float>(row, col) + lambda*(n*nc + s*sc + e*ec + w*wc);
}
}
}