各向异性扩散滤波(Anisotropic Filter,又称 Perona-Malik Filter),主要是用来平滑图像,克服了高斯滤波模糊的缺陷,各向异性扩散在平滑图像的同时又能保留图像边缘;此外,Perona-Malik Filter 在地学影像处理中也得到了相应的应用,如平滑DEM数据、河道提取 等。
将图像看作热量场,每个像元看作热流,根据当前像元和周围像元的关系,来确定是否需要向周围扩散。如果某个邻域像元和当前像元差别较大,那么这个邻域像元可能是边界,当前像元就不向这个方向扩散了,该边界也就得到保留。
主要迭代方程如下:
其中,
为图像,
为迭代次数。
四个散度公式是在四个方向上对当前像素求偏导,公式如下:
而
、
、
和
代表四个方向上的导热系数,公式如下:
整个公式需要设置的参数主要有三个,迭代次数
,根据情况设置;导热系数相关的
,取值越大,结果越平滑,越不易保留边缘;
取值越大,结果越平滑。
C++实现(未使用opencv):
void AnisotropicFilter(float *ppafScan, float *outppafScan, int nImgWidth, int nImgHeight, int iterationSum, float k, float lambda)
{
//ppafScan 输入数据
//outppafScan 输出数据
//nImgWidth, nImgHeight 数据的宽和高
//iterationSum 迭代总次数
//k 导热系数,控制平滑
//lambda 控制平滑
for(int iter = 0; iter < iterationSum; ++iter)
{
for(int i = 0; i < nImgHeight; ++i)
{
for (int j = 0; j < nImgWidth; ++j)
{
if(i == 0 || i == nImgHeight - 1 || j == 0 || j == nImgWidth - 1)
{
outppafScan[i * nImgWidth + j] = ppafScan[i * nImgWidth + j];
continue;
}
float NI = ppafScan[i * nImgWidth + (j - 1)] - ppafScan[i * nImgWidth + j];
float EI = ppafScan[(i - 1) * nImgWidth + j] - ppafScan[i * nImgWidth + j];
float WI = ppafScan[(i + 1) * nImgWidth + j] - ppafScan[i * nImgWidth + j];
float SI = ppafScan[i * nImgWidth + (j + 1)] - ppafScan[i * nImgWidth + j];
float cN = exp(-NI * NI / (k * k));
float cE = exp(-EI * EI / (k * k));
float cW = exp(-WI * WI / (k * k));
float cS = exp(-SI * SI / (k * k));
outppafScan[i * nImgWidth + j] = ppafScan[i * nImgWidth + j] + lambda * (cN * NI + cS * SI + cE * EI + cW * WI);
}
}
}
return;
}
当 , , 时,结果如下图所示:
左:原始图像,右:滤波后的影像
高斯滤波(线性)和Perona-Malik滤波(非线性)的比较:(a)原始影像;(b) Gaussian filtering (the kernels = 7 m);© Perona-Malik filter (t = 50);(d) Gaussian filtering (the kernels = 14 m);(e) Perona-Malik filter (t = 200) [原图链接]
欢迎大家批评指正。