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

测试效果 

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

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

       Matlab版本见:

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/546771.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

腾讯云轻量应用服务器端口开启教程

腾讯云轻量应用服务器端口怎么打开&#xff1f;在轻量应用服务器控制台的防火墙中开启端口&#xff0c;本文腾讯云百科txybk.com以80端口为例&#xff0c;来详细说下轻量应用服务器端口打开教程&#xff0c;另外可以在腾讯云百科 txy.wiki 查看当前轻量服务器最新的优惠券和配置…

Angular学习第四天--问题记录及父子组件问题

问题一、 拉取完项目&#xff0c;使用npm install命令的时候遇到的。 解决办法&#xff1a; 在查找网上五花八门的解决方案之后&#xff0c;发现都不能解决。 我的解决办法是&#xff1a; 1. 把package-lock.json给删掉&#xff1b; 2. 把package.json中公司自己库的包给删除掉…

112 arcpy 发布 mxd地图文件 到 arcgis服务器 为 地图服务

前言 此文档主要是记录一下 最近的一次机遇 arcpy 来发布 地图文件到 arcgis服务器 上面 arcpy 主要是来自于 ArcGIS_Desktop_105_154030.zip 安装之后会在 python 的安装目录 安装另外的一份带 arcgis 的 python 环境, 然后 本文相关类库 也是基于 这个 arcpy 的 python 环境…

node.js服务器静态资源处理

前言&#xff1a;node.js服务器动态资源处理见 http://t.csdnimg.cn/9D8WN 一、什么是node.js服务器静态资源&#xff1f; 静态资源服务器指的是不会被服务器的动态运行所改变或者生成的文件. 它最初在服务器运行之前是什么样子, 到服务器结束运行时, 它还是那个样子. 比如平…

Mockito单元测试

文章目录 Mockito单元测试 为什么要使用Mock?导入依赖import导入包使用Mock模拟测试某个类中的某个方法是否可以成功执行使用Mock模拟某个类的方法&#xff0c;自己给这个方法返回我们指定的值使用Mock模拟某个方法调用后会抛出指定的异常使用Mock模拟测试某个类中的某个方法(…

语音智能客服机器人有什么优势?ai机器人部署

人工智能技术的进步&#xff0c;在不断的革新我们的工作和生活&#xff0c;同时&#xff0c;拥有人工智能技术的语音智能客服机器人在销售行业的工作熟悉程度也越来越好&#xff0c;那语音智能客服机器人有什么优势&#xff1f;我们一起来看看。 1、ASR语音文本转换 客户可通过…

微服务之分布式链路追踪

一、概述 1.1背景 在微服务框架中&#xff0c;一个由客户端发起的请求在后端系统中会经过多个不同的的服务节点调用来协同产生最后的请求结果&#xff0c;每一个前段请求都会形成一条复杂的分布式服务调用链路&#xff0c;链路中的任何一环出现高延时或错误都会引起整个请求最…

k8s高可用集群部署介绍 -- 理论

部署官网参考文档 负载均衡参考 官网两种部署模式拓扑图和介绍 介绍两种高可用模式 堆叠 拓扑图如下&#xff08;图片来自k8s官网&#xff09;&#xff1a; 特点&#xff1a;将etcd数据库作为控制平台的一员&#xff0c;由于etcd的共识算法&#xff0c;所以集群最少为3个&…

【算法】快速排序的基本思想、优化 | 挖坑填补法和区间分割法

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 更多算法分析与设计知识专栏&#xff1a;算法分析&#x1f525; 给大家跳…

Spire.PDF for .NET【文档操作】演示:合并 PDF 文档

需要合并 PDF 的原因有很多。例如&#xff0c;合并 PDF 文件允许您打印单个文件&#xff0c;而不是为打印机排队多个文档&#xff0c;组合相关文件通过减少要搜索和组织的文件数量来简化管理和存储多个文档的过程。在本文中&#xff0c;您将学习如何使用Spire.PDF for .NET将多…

STM32移植嵌入式开源按键框架

目录 STM32移植嵌入式开源按键框架 MultiButton简介 multi_button.c文件 multi_button.h文件 按键事件 案例使用方法 学习剖析 STM32移植嵌入式开源按键框架 今天移植了一款嵌入式按键框架工程MultiButton&#xff0c;MultiButton是一个小巧简单易用的事件驱动型按键驱动…

OSCP靶场--Wombo

OSCP靶场–Wombo 考点(redis 主从复制RCE ) 1.nmap扫描 ## ┌──(root㉿kali)-[~/Desktop] └─# nmap -sV -sC 192.168.153.69 -p- -Pn --min-rate 2500 Starting Nmap 7.92 ( https://nmap.org ) at 2024-04-13 07:33 EDT Nmap scan report for 192.168.153.69 Host is u…

代理IP服务商:选择、优势与未来趋势

目录 一、代理IP服务商的选择 二、代理IP的优势 三、代理IP的未来发展趋势 在网络爬虫、数据采集、SEO优化等网络应用中&#xff0c;代理IP扮演着不可或缺的角色。代理IP服务商则是提供这些代理IP资源的主体&#xff0c;如何选择合适的服务商&#xff0c;以及代理IP的优势和…

风速Weibull分布和光伏Beta分布的参数拟合方法(含matlab算例)

在风光场景生成、随机优化调度等研究中&#xff0c;常常假设风速服从Weibull分布&#xff0c;太阳辐照度服从Beta分布。那我们如何得到两个分布的参数呢&#xff1f;文本首先介绍了风速Weibull分布和辐照度Beta分布的基本概率模型及其性性质&#xff0c;之后以MATLAB代码为例阐…

【JAVA基础篇教学】第七篇:Java异常类型说明

博主打算从0-1讲解下java基础教学&#xff0c;今天教学第七篇&#xff1a;Java异常类型说明。 在Java中&#xff0c;错误&#xff08;Error&#xff09;是Throwable类及其子类的实例&#xff0c;它们通常表示严重的问题&#xff0c;无法通过程序来处理&#xff0c;而是需要进…

javaWeb项目-外面点餐系统功能介绍

项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot、SSM、vue、MYSQL、MAVEN 数据库工具&#xff1a;Navicat、SQLyog 1、Spring Boot框架 …

vue3第十八节(diff算法)

引言&#xff1a; 上一节说了key的用途&#xff0c;而这个key属性&#xff0c;在vue的vnode 中至关重要&#xff0c;直接影响了虚拟DOM的更新机制&#xff1b; 什么场景中会用到diff算法 如&#xff1a;修改响应式属性需要重新渲染页面&#xff0c;会重新执行render渲染函数返…

AndroidStudio 导出aar包,并使用

打包 1、确认当前选项是否勾选&#xff0c;如未勾选请先勾选。 2、勾选完成后重启Android Studio。 3、重启完成后&#xff0c;选中要打包的module 4、打包完成 使用 1.在项目中新建libs,放入aar文件。 2.修改配置 添加如下代码 flatDir {dirs("libs")}3.修改app…

MongoDB 使用

1 引用依赖包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId></dependency>2 配置文件配置mongodb资料 # MongoDB连接信息 spring.data.mongodb.host 192.168.23.…

ESP32_IDF前端命令开发全过程

ESP32 IDF前端命令开发全过程 开端1. 创建新工程(create-project)2. 创建新组件(create--component)目前文件结构 3. 设置目标芯片4. 配置项目5. 编译工程6. 烧录程序7. 打开监视器8. 一次性编译烧录并打开监视器9. 擦除设备flash10. 查询内存剩余11. 清除编译文件 仅供本人查阅…