OpenCV-AMF算法(自适应中值滤波Adaptive Median Filtering)

2024-04-15 16:20

本文主要是介绍OpenCV-AMF算法(自适应中值滤波Adaptive Median Filtering),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

实现原理

       AMF(Adaptive Median Filter,自适应中值滤波)是一种用于图像处理和信号处理的滤波算法,其目的是在保持图像细节的同时去除噪声。它是基于中值滤波的一种改进,可以根据局部像素的灰度值特征自适应地调整滤波器的大小和形状。

       AMF算法的主要思想是根据像素邻域的特征动态调整滤波器的尺寸和形状,以适应不同区域的噪声水平和图像细节。具体步骤如下:

  1. 参数和初始化

    • 函数接受一个输入图像input和一个整数参数winSize,表示滤波器的初始大小。
    • 创建一个和输入图像大小相同的输出图像output,用于存储滤波结果。
    • 变量 R 为窗口半径的最大限制值。
  2. 并行遍历处理图像每个像素

    • 使用 OpenMP 实现并行化,对图像的每一个像素进行处理。注意需要在设置里打开OpenMP。
  3. 窗口处理

    • 对于每个像素(i, j),以其为中心构建一个大小为(2*r+1)*(2*r+1)的窗口。
    • 在窗口边界进行限制,防止越界。
  4. 窗口数据排序

    • 将窗口内的像素值存储在 datas 向量中,并进行排序。
  5. 计算中值和最值

    • 计算排序后的数据中的最小值 minValue、最大值 maxValue 和中值 midValue
  6. 判断是否需要扩大窗口

    • 根据中值与最小值、最大值的差值是否超过某个阈值 thresh 来决定是否需要扩大窗口。
    • 如果窗口内的中值不在最小值和最大值之间一定范围内,则继续扩大窗口,直到r大于R。
  7. 滤波处理

    • 如果当前像素值与窗口最值的差值大于阈值,说明不需要滤波,直接将当前像素值赋给输出图像的对应位置。
    • 否则,将窗口内的中值赋给输出图像的对应位置。
  8. 返回结果

    • 返回处理后的输出图像。

       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 forfor (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 forfor (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;
}

测试效果 

图1 原图
图2 噪声图
图3 传统中值滤波算法效果
图4 AMF算法效果图

       如上图所示,AMF算法在保留图像细节的同时有效去除了椒盐噪声。

       Matlab版本见:

Matlab-AMF算法(自适应中值滤波Adaptive Median Filtering)-CSDN博客   

       如果函数有什么可以改进完善的地方,非常欢迎大家指出,一同进步何乐而不为呢~

       如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

这篇关于OpenCV-AMF算法(自适应中值滤波Adaptive Median Filtering)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/906310

相关文章

Python使用OpenCV实现获取视频时长的小工具

《Python使用OpenCV实现获取视频时长的小工具》在处理视频数据时,获取视频的时长是一项常见且基础的需求,本文将详细介绍如何使用Python和OpenCV获取视频时长,并对每一行代码进行深入解析... 目录一、代码实现二、代码解析1. 导入 OpenCV 库2. 定义获取视频时长的函数3. 打开视频文

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

Python如何将OpenCV摄像头视频流通过浏览器播放

《Python如何将OpenCV摄像头视频流通过浏览器播放》:本文主要介绍Python如何将OpenCV摄像头视频流通过浏览器播放的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完... 目录方法1:使用Flask + MJPEG流实现代码使用方法优点缺点方法2:使用WebSocket传输视

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

Python中OpenCV与Matplotlib的图像操作入门指南

《Python中OpenCV与Matplotlib的图像操作入门指南》:本文主要介绍Python中OpenCV与Matplotlib的图像操作指南,本文通过实例代码给大家介绍的非常详细,对大家的学... 目录一、环境准备二、图像的基本操作1. 图像读取、显示与保存 使用OpenCV操作2. 像素级操作3.

C/C++中OpenCV 矩阵运算的实现

《C/C++中OpenCV矩阵运算的实现》本文主要介绍了C/C++中OpenCV矩阵运算的实现,包括基本算术运算(标量与矩阵)、矩阵乘法、转置、逆矩阵、行列式、迹、范数等操作,感兴趣的可以了解一下... 目录矩阵的创建与初始化创建矩阵访问矩阵元素基本的算术运算 ➕➖✖️➗矩阵与标量运算矩阵与矩阵运算 (逐元

C/C++的OpenCV 进行图像梯度提取的几种实现

《C/C++的OpenCV进行图像梯度提取的几种实现》本文主要介绍了C/C++的OpenCV进行图像梯度提取的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录预www.chinasem.cn备知识1. 图像加载与预处理2. Sobel 算子计算 X 和 Y

C/C++和OpenCV实现调用摄像头

《C/C++和OpenCV实现调用摄像头》本文主要介绍了C/C++和OpenCV实现调用摄像头,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录准备工作1. 打开摄像头2. 读取视频帧3. 显示视频帧4. 释放资源5. 获取和设置摄像头属性

c/c++的opencv图像金字塔缩放实现

《c/c++的opencv图像金字塔缩放实现》本文主要介绍了c/c++的opencv图像金字塔缩放实现,通过对原始图像进行连续的下采样或上采样操作,生成一系列不同分辨率的图像,具有一定的参考价值,感兴... 目录图像金字塔简介图像下采样 (cv::pyrDown)图像上采样 (cv::pyrUp)C++ O