《opencv实用探索·九》中值滤波简单理解

1、引言
均值滤波、方框滤波、高斯滤波,都是线性滤波方式。由于线性滤波的结果是所有像素值的线性组合,因此含有噪声的像素也会被考虑进去,噪声不会被消除,而是以更柔和的方式存在。这时使用非线性滤波效果可能会更好。中值滤波是一种非线性滤波方式,不再采用加权求均值的方式计算滤波结果,基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替,让周围的像素值接近的真实值,从而消除孤立的噪声点。

优缺点:中值滤波可以有效的去除斑点和椒盐噪声。但是效率低,其运算时间 为均值滤波的五倍以上

2、中值滤波过程
首先我们先取一个nxn的滤波核,该核是一个空核,核中不在有权重等数字,把滤波核放在图像上滑动,每滑动到一个位置,就把核覆盖下的所有像素值进行排序,然后取排序后中间的像素值替换被核中心覆盖下的原图像像素值。下面演示下滤波过程。

先取一个3x3的空核:
在这里插入图片描述
把3x3的空核放在原图像上进行滑动:
在这里插入图片描述
计算被核覆盖下的像素中值,以上图核放在左上角为例:
先给所有像素进行排序,正序和逆序都可,这里使用正序
20,24,28,35,47,59,68,79,99

由排序可知中间值为:47
最后把中间值替换被核中心覆盖的像素值,即68会重新赋值为47,随着核滑动便可依次计算被核中心覆盖的像素值的中值,核中心滑动过的像素如下图阴影部分。
在这里插入图片描述

3、opencv中值滤波函数使用

void cv::medianBlur(InputArray   src,OutputArray dst,int  ksize
)

src:原图像,可以是单通道,三通道和四通道,数据类型与滤波器的尺寸相关,当滤波器尺寸为3或5时,图像可以是CV 8U,CV 16U或CV 32F类型,对于较大尺寸的滤波器,数据类型只能是CV 8U
dst:滤波后的图像
ksize:滤波核大小,必须是奇数,这样才有核中心

对原图分别执行3x3和9x9滤波,实现效果如下:
原图:
在这里插入图片描述
左边是3x3滤波,右边是9x9滤波
在这里插入图片描述

4、滤波核根据图像自适应调整大小
我们在调用medianBlur时需要手动传入一个滤波核大小,下面的一个demo介绍了核的大小根据局部邻域的均值和标准差进行自适应调整:

#include <opencv2/opencv.hpp>cv::Mat adaptiveMedianBlur(const cv::Mat& src, int maxWindowSize) {cv::Mat result = src.clone();int numChannels = src.channels();for (int y = maxWindowSize / 2; y < src.rows - maxWindowSize / 2; ++y) {for (int x = maxWindowSize / 2; x < src.cols - maxWindowSize / 2; ++x) {int windowSize = 3;  // 初始核大小while (windowSize <= maxWindowSize) {// 提取局部邻域cv::Mat region = src(cv::Range(y - windowSize / 2, y + windowSize / 2 + 1),cv::Range(x - windowSize / 2, x + windowSize / 2 + 1));// 计算标准差cv::Scalar mean, stddev;cv::meanStdDev(region, mean, stddev);// 中值滤波if (numChannels == 1 && src.at<uchar>(y, x) < mean[0] + stddev[0] * 0.5) {// 单通道图像中值滤波cv::Mat subRegion = result(cv::Range(y - windowSize / 2, y + windowSize / 2 + 1),cv::Range(x - windowSize / 2, x + windowSize / 2 + 1));cv::medianBlur(region, subRegion, windowSize);break;} else if (numChannels == 3 &&src.at<cv::Vec3b>(y, x)[0] < mean[0] + stddev[0] * 0.5 &&src.at<cv::Vec3b>(y, x)[1] < mean[1] + stddev[1] * 0.5 &&src.at<cv::Vec3b>(y, x)[2] < mean[2] + stddev[2] * 0.5) {// 三通道图像中值滤波cv::Mat subRegion = result(cv::Range(y - windowSize / 2, y + windowSize / 2 + 1),cv::Range(x - windowSize / 2, x + windowSize / 2 + 1));cv::medianBlur(region, subRegion, windowSize);break;} else {// 增大核大小windowSize += 2;if (windowSize > maxWindowSize) {break;}}}}}return result;
}int main() {// 读取图像cv::Mat image = cv::imread("input_image.jpg", cv::IMREAD_GRAYSCALE);// 应用自适应中值滤波cv::Mat result = adaptiveMedianBlur(image, 11);// 显示原始图像和处理后的图像cv::imshow("Original Image", image);cv::imshow("Adaptive Median Blur Image", result);cv::waitKey(0);cv::destroyAllWindows();return 0;
}

下面对代码做一些解释:
(1)函数需要传入一个原图像和一个滤波核的上限,表示该图像做中值滤波时最大只能用maxWindowSize
(2)最上面两层for循环遍历核中心扫过的像素,例如一个8x8图像被maxWindowSize = 5x5的核扫过的区域如下阴影部分:
在这里插入图片描述
这两层循环确保我们只处理在图像内部且不会越界的像素。这是为了确保局部邻域的提取和处理都在图像内部进行

(3) 根据当前核大小提取局部邻域
cv::Mat region = src(cv::Range(y - windowSize / 2, y + windowSize / 2 + 1),
cv::Range(x - windowSize / 2, x + windowSize / 2 + 1));
代码以被最大核扫过的每个像素分别为当前核的一个中心,提取一个局部邻域,比如当前核为3x3,第一个被扫过像素的局部邻域如下:
在这里插入图片描述
(4)计算邻域的均值和标准差
(5)
if (src.at(y, x) < mean[0] + stddev[0] * 0.5)
这个条件的意思是:如果当前像素 (y, x) 的值小于局部邻域的平均灰度值加上标准差的一半,就执行中值滤波。这样的判断条件旨在处理相对较小的像素值,因为在图像中的边缘或包含细节的区域,这些值可能代表着重要的信息。在这些情况下,使用中值滤波有助于更好地保留细节。如果像素值相对较大,可能处于较均匀的区域,就不执行中值滤波,以免过度平滑图像。

加上标准差的一半的目的是提高容错性,使得判断更加灵活。这个设计的理念是在图像中的一些相对较暗的区域或包含细节的区域,由于灰度值的波动,可能出现一些像素的值略低于整体平均值。通过引入标准差的一半,可以允许更大的变化范围,从而更好地适应图像的局部特征。当然也可以把标准差的一半换成一个固定的值,具体可以根据实验来调整。

下面是带三通道的情况:

cv::Mat adaptiveMedianBlur1(const cv::Mat& src, int maxWindowSize) {cv::Mat result = src.clone();int numChannels = src.channels();for (int y = maxWindowSize / 2; y < src.rows - maxWindowSize / 2; ++y) {for (int x = maxWindowSize / 2; x < src.cols - maxWindowSize / 2; ++x) {int windowSize = 3;  // 初始核大小while (windowSize <= maxWindowSize) {// 提取局部邻域cv::Mat region = src(cv::Range(y - windowSize / 2, y + windowSize / 2 + 1),cv::Range(x - windowSize / 2, x + windowSize / 2 + 1));// 计算标准差cv::Scalar mean, stddev;cv::meanStdDev(region, mean, stddev);// 中值滤波if (numChannels == 1 && src.at<uchar>(y, x) < mean[0] + stddev[0] * 0.5) {// 单通道图像中值滤波cv::Mat subRegion = result(cv::Range(y - windowSize / 2, y + windowSize / 2 + 1),cv::Range(x - windowSize / 2, x + windowSize / 2 + 1));cv::medianBlur(region, subRegion, windowSize);break;}else if (numChannels == 3 &&src.at<cv::Vec3b>(y, x)[0] < mean[0] + stddev[0] * 0.5 &&src.at<cv::Vec3b>(y, x)[1] < mean[1] + stddev[1] * 0.5 &&src.at<cv::Vec3b>(y, x)[2] < mean[2] + stddev[2] * 0.5) {// 三通道图像中值滤波cv::Mat subRegion = result(cv::Range(y - windowSize / 2, y + windowSize / 2 + 1),cv::Range(x - windowSize / 2, x + windowSize / 2 + 1));cv::medianBlur(region, subRegion, windowSize);break;}else {// 增大核大小windowSize += 2;if (windowSize > maxWindowSize) {break;}}}}}return result;
}
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

未势能源亮相中国燃料电池汽车大会,助力京津冀“氢能高速”

2023年12月1日&#xff0c;首届中国燃料电池汽车大会在大兴国际氢能示范区举办。大会由北京市经济和信息化局、北京市大兴区人民政府、中国汽车技术研究中心有限公司共同主办。中国科学技术协会主席万钢作主旨报告&#xff0c;国务院国资委副主任苟坪&#xff0c;中国科学院院士…

CO11N报工时,在填入返工数量后自动产生返工工单

本文档主要说明一种返工流程,当工人报工时,填写返工数量、变式原因即可启动触发点自动创建返工订单,被创建的反工订单为无料号生产订单,且关联报工订单。涉及系统功能点包括状态参数 一、 后台配置 1).用户状态参数:BS02(SPRO-生产-商店低价控制-主数据-订单-定义状态…

无公网IP环境固定地址远程SSH访问本地树莓派Raspberry Pi

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;…

专业做除甲醛净化器的品牌 甲醛净化器什么牌子最好用

室内产生了超标的甲醛&#xff0c;大部分都会采取选择甲醛空气净化器来去除&#xff0c;甲醛净化器逐渐成为室内清除甲醛的主力&#xff0c;在选择甲醛净化器时&#xff0c;人们常常会被市场上琳琅满目的空气净化器品牌所迷惑&#xff0c;各品牌和型号都声称自己最好&#xff0…

freeRTOS创建任务

一.动态创建任务 1.函数xTaskCreate() BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, // 函数指针, 任务函数const char * const pcName, // 任务的名字const configSTACK_DEPTH_TYPE usStackDepth, // 栈大小,单位为word,10表示40字节void * const pvParameters, // …

CCFCSP试题编号:202006-2试题名称:稀疏向量

不断匹配相乘累加就好了 #include<iostream> #include<vector> #include <utility> using namespace std;int main() {int n;int a, b;long long result0; // 使用 long long cin >> n >> a >> b;vector<pair<int, int> > u…

Python面向对象⑤:多态【侯小啾Python基础领航计划 系列(二十三)】

Python面向对象⑤:多态【侯小啾Python基础领航计划 系列(二十三)】 大家好,我是博主侯小啾, 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔…

minio服务端搭建使用

一.minio文件服务搭建 非docker环境部署(Linux部署) 1.官网下载安装包&#xff1a;MinIO | Code and downloads to create high performance object storage 2、上传安装包文件到目录(这个可以自由选择) /home/minio/ 3、为minio添加权限 sudo chmod x minio 4、 创建mini…

开关柜无线测温系统

开关柜无线测温系统是一种基于无源无线通信技术的开关柜温度监测系统&#xff0c;依托电易云-智慧电力物联网实现高压开关柜接头温度的在线监测和报警。该系统通过在开关柜内部安装无线温度探测器&#xff0c;实时监测开关柜内部的接头、电缆接头、母排等的温度监控&#xff0c…

0年费、0月费、免kyc,支持ChatGPTPlus充值虚拟卡

虚拟卡通常是指银行卡的虚拟卡&#xff0c;是在银行卡的基础上的银联、VISA、万事达卡BIN码衍生出的一种虚拟账户。虚拟卡一般都是用于网络上无卡支付&#xff0c;因此虚拟卡都不会配备相应的实体卡片。银行卡的虚拟卡&#xff0c;在分类上与实体卡并无什么区别&#xff0c;也分…

学SQL JOINS看这一篇文章就够了

目录 下面以实例进行分析 内连接 inner join 或者join&#xff08;等同于inner join&#xff09; 外连接 left join 或者left outer join(等同于left join) [ left join 或者left outer join(等同于left join) ] [ where B.column is null ] right join 或者right outer…

Docker Registry本地镜像仓库部署并实现远程连接拉取镜像

Linux 本地 Docker Registry本地镜像仓库远程连接 文章目录 Linux 本地 Docker Registry本地镜像仓库远程连接1. 部署Docker Registry2. 本地测试推送镜像3. Linux 安装cpolar4. 配置Docker Registry公网访问地址5. 公网远程推送Docker Registry6. 固定Docker Registry公网地址…

Centos系列:shell编程综合练习(个人学习记录)

shell编程综合练习&#xff08;个人学习记录&#xff09; shell编程until 循环跳出循环1. break命令2. continue 命令 Shell函数特殊变量输入输出重定向输出重定向输入重定向重定向 Shell实战监控centos7运行状态/proc/stat文件编写脚本free命令监控系统内存 shell编程 until …

h5网站开发-微信浏览器无法自动播放视频的解决方式?

一、需求&#xff1a; 使用h5开发的网站&#xff0c;首页的banner是一个video视频&#xff0c;在PC端上和手机浏览器上都能正常播放&#xff0c;但是在手机微信浏览器里面视频是无法自动播放的。 二、实现效果&#xff1a; 1.微信浏览器的效果&#xff1a; 2.正常效果&…

如何实现高效代码审查,赋能大规模开发

对于许多企业来说&#xff0c;代码审查都是开发过程中不可缺少的一环。软件开发人员通常会对代码审查感到又爱又恨。一般来说&#xff0c;实施代码审查的企业普遍认为通过及早发现问题和低效率&#xff0c;在长远来看可节省时间。 阅读本篇文章&#xff0c;您将了解到什么是代…

JS浮点数精度问题及解决方案

前端面试大全JS浮点数精度问题及解决方案 &#x1f31f;经典真题 &#x1f31f;浮点数精度常见问题 &#x1f31f;为什么会有这样的问题 &#x1f31f;真题解答 &#x1f31f;总结 &#x1f31f;经典真题 为什么 console.log(0.20.10.3) 得到的值为 false &#x1f31f;…

vs-code之vue3插件

1.Vue 3 Support - All In One Vue3 代码片段突出显示了 Visual Studio Code 的格式化程序生成器 生成vue3对应的的代码 如ref等&#xff0c; 2.Volar 相信使用 VSCode 开发 Vue2 的同学一定对 Vetur 插件不会陌生&#xff0c;作为 Vue2 配套的 VSCode 插件&#xff0c;它的主…

C++学习之路(十)C++ 用Qt5实现一个工具箱(增加一个时间戳转换功能)- 示例代码拆分讲解

上篇文章&#xff0c;我们用 Qt5 实现了在小工具箱中添加了《JSON数据格式化》功能&#xff0c;还是比较实用的。为了继续丰富我们的工具箱&#xff0c;今天我们就再增加一个平时经常用到的功能吧&#xff0c;就是「 时间戳转换 」功能&#xff0c;而且实现点击按钮后文字进行变…

Unity中C#如何访问并修改Shader材质

文章目录 前言一、我们用点击按钮来改变Shader传入的颜色值1、在渲染GUI时&#xff0c;绘制一个按钮2、我们使用一个公共的成员变量存储需要进行修改的游戏对象3、最后给绘制的按钮点击增加逻辑即可 二、测试使用的代码1、Shader代码&#xff1a;2、C#脚本 前言 我们写好Shade…

电源自动测试系统| 电源模块温度循环怎么测试?

在一些应用领域&#xff0c;电源模块会在极端环境温度条件下工作。为了确保电源在高低温环境下可以正常运行&#xff0c;满足设备需求&#xff0c;需要对电源模块进行温度循环测试。 温度循环测试是指电源模块经过升温、保温、降温等多次循环试验来检测其在温度变化下的耐热性、…