作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处
实现原理
AMF(Adaptive Median Filter,自适应中值滤波)是一种用于图像处理和信号处理的滤波算法,其目的是在保持图像细节的同时去除噪声。它是基于中值滤波的一种改进,可以根据局部像素的灰度值特征自适应地调整滤波器的大小和形状。
AMF算法的主要思想是根据像素邻域的特征动态调整滤波器的尺寸和形状,以适应不同区域的噪声水平和图像细节。具体步骤如下:
-
参数和初始化:
- 函数接受一个输入图像
input
和一个整数参数winSize
,表示滤波器的初始大小。 - 创建一个和输入图像大小相同的输出图像
output
,用于存储滤波结果。 - 变量
R
为窗口半径的最大限制值。
- 函数接受一个输入图像
-
并行遍历处理图像每个像素:
- 使用 OpenMP 实现并行化,对图像的每一个像素进行处理。注意需要在设置里打开OpenMP。
-
窗口处理:
- 对于每个像素
(i, j)
,以其为中心构建一个大小为(2*r+1)*(2*r+1)
的窗口。 - 在窗口边界进行限制,防止越界。
- 对于每个像素
-
窗口数据排序:
- 将窗口内的像素值存储在
datas
向量中,并进行排序。
- 将窗口内的像素值存储在
-
计算中值和最值:
- 计算排序后的数据中的最小值
minValue
、最大值maxValue
和中值midValue
。
- 计算排序后的数据中的最小值
-
判断是否需要扩大窗口:
- 根据中值与最小值、最大值的差值是否超过某个阈值
thresh
来决定是否需要扩大窗口。 - 如果窗口内的中值不在最小值和最大值之间一定范围内,则继续扩大窗口,直到r大于R。
- 根据中值与最小值、最大值的差值是否超过某个阈值
-
滤波处理:
- 如果当前像素值与窗口最值的差值大于阈值,说明不需要滤波,直接将当前像素值赋给输出图像的对应位置。
- 否则,将窗口内的中值赋给输出图像的对应位置。
-
返回结果:
- 返回处理后的输出图像。
AMF算法的优点是能够有效地处理不同区域的噪声和图像细节,因为它在滤波器大小和形状上具有自适应性。然而,它也有一些缺点,比如计算复杂度较高,处理速度较慢,特别是对于大尺寸的滤波器。
总的来说,AMF算法是一种灵活而有效的滤波器,特别适用于那些噪声水平不均匀且图像细节丰富的场景,尤其是针对椒盐噪声。
功能函数代码
// AMF算法(Adaptive Median Filtering)
cv::Mat adaptiveMedianFiltering(cv::Mat input, int winSize)
{
int row = input.rows;
int col = input.cols;
cv::Mat output(row, col, CV_8UC1);
int R = winSize / 2;
// 遍历处理
#pragma omp parallel for
for (int i = 0; i < row; i++)
{
vector<float> datas;
for (int j = 0; j < col; j++)
{
int r = 1;
while (r <= R)
{
// 卷积窗口边界限制,防止越界
int ms = ((i - r) > 0) ? (i - r) : 0;
int me = ((i + r) < (row - 1)) ? (i + r) : (row - 1);
int ns = ((j - r) > 0) ? (j - r) : 0;
int ne = ((j + r) < (col - 1)) ? (j + r) : (col - 1);
// 窗口内有效数据排序
datas.clear();
for (int m = ms; m <= me; ++m)
{
for (int n = ns; n <= ne; ++n)
{
datas.push_back(float(input.at<uchar>(m, n)));
}
}
sort(datas.begin(), datas.end());
// 计算数值
float minValue = datas[0];
float maxValue = datas[datas.size() - 1];
float midValue = datas[datas.size() / 2];
// 若窗口内中值不为在最值一定范围内,则说明当前窗口尺寸足够,不需要扩展也可完成有效滤波;反之,则继续扩大窗口,直到最大窗口尺寸
float thresh = (maxValue - minValue) * 0.02f;
if ((midValue - minValue) > thresh && (maxValue - midValue) > thresh)
{
// 若数据本身就不为最值,则不需要滤波,这也是自适应算法保持高分辨的关键
if ((input.at<uchar>(i, j) - minValue) > thresh && (maxValue - input.at<uchar>(i, j)) > thresh)
{
output.at<uchar>(i, j) = input.at<uchar>(i, j);
}
// 若为最值,则说明当前数值大概率是噪声信息,进行中值滤波
else
{
output.at<uchar>(i, j) = uchar(midValue);
}
break;
}
else
{
r++;
}
// 如果窗口尺寸达到限制了,则直接滤波
if (r > R)
{
output.at<uchar>(i, j) = uchar(midValue);
}
}
}
}
return output;
}
C++测试代码
#include <algorithm>
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
// AMF算法(Adaptive Median Filtering)
cv::Mat adaptiveMedianFiltering(cv::Mat input, int winSize)
{
int row = input.rows;
int col = input.cols;
cv::Mat output(row, col, CV_8UC1);
int R = winSize / 2;
// 遍历处理
#pragma omp parallel for
for (int i = 0; i < row; i++)
{
vector<float> datas;
for (int j = 0; j < col; j++)
{
int r = 1;
while (r <= R)
{
// 卷积窗口边界限制,防止越界
int ms = ((i - r) > 0) ? (i - r) : 0;
int me = ((i + r) < (row - 1)) ? (i + r) : (row - 1);
int ns = ((j - r) > 0) ? (j - r) : 0;
int ne = ((j + r) < (col - 1)) ? (j + r) : (col - 1);
// 窗口内有效数据排序
datas.clear();
for (int m = ms; m <= me; ++m)
{
for (int n = ns; n <= ne; ++n)
{
datas.push_back(float(input.at<uchar>(m, n)));
}
}
sort(datas.begin(), datas.end());
// 计算数值
float minValue = datas[0];
float maxValue = datas[datas.size() - 1];
float midValue = datas[datas.size() / 2];
// 若窗口内中值不为在最值一定范围内,则说明当前窗口尺寸足够,不需要扩展也可完成有效滤波;反之,则继续扩大窗口,直到最大窗口尺寸
float thresh = (maxValue - minValue) * 0.02f;
if ((midValue - minValue) > thresh && (maxValue - midValue) > thresh)
{
// 若数据本身就不为最值,则不需要滤波,这也是自适应算法保持高分辨的关键
if ((input.at<uchar>(i, j) - minValue) > thresh && (maxValue - input.at<uchar>(i, j)) > thresh)
{
output.at<uchar>(i, j) = input.at<uchar>(i, j);
}
// 若为最值,则说明当前数值大概率是噪声信息,进行中值滤波
else
{
output.at<uchar>(i, j) = uchar(midValue);
}
break;
}
else
{
r++;
}
// 如果窗口尺寸达到限制了,则直接滤波
if (r > R)
{
output.at<uchar>(i, j) = uchar(midValue);
}
}
}
}
return output;
}
void main()
{
cv::Mat image = cv::imread("test.jpg", cv::IMREAD_GRAYSCALE);
// 添加随机椒盐噪声
int row = image.rows;
int col = image.cols;
cv::Mat noise = image.clone();
for (int i = 0; i < row; i += 10)
{
for (int j = 0; j < col; j += 10)
{
noise.at<uchar>(i, j) = rand() % 255;
}
}
// 传统中值滤波
int winSize = 15;
cv::Mat median;
cv::medianBlur(noise, median, winSize);
// AMF算法处理
cv::Mat resultimage = adaptiveMedianFiltering(noise, winSize);
// 显示
cv::imshow("ori", image);
cv::imshow("noise", noise);
cv::imshow("AMF", resultimage);
cv::waitKey(0);
cout << "end." << endl;
}
测试效果
如上图所示,AMF算法在保留图像细节的同时有效去除了椒盐噪声。
Matlab版本见:
Matlab-AMF算法(自适应中值滤波Adaptive Median Filtering)-CSDN博客
如果函数有什么可以改进完善的地方,非常欢迎大家指出,一同进步何乐而不为呢~
如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!