【图像处理OpenCV(C++版)】——5.3 图像平滑之均值平滑(滤波)

news2024/11/16 1:22:02

前言

😊😊😊欢迎来到本博客😊😊😊

🌟🌟🌟 本专栏主要结合OpenCV和C++来实现一些基本的图像处理算法并详细解释各参数含义,适用于平时学习、工作快速查询等,随时更新。

😊😊😊 具体食用方式:可以点击本专栏【OpenCV快速查找(更新中)】–>搜索你要查询的算子名称或相关知识点,或者通过这篇博客👉通俗易懂OpenCV(C++版)详细教程——OpenCV函数快速查找(不断更新中)]查阅你想知道的知识,即可食用。

🎁🎁🎁支持:如果觉得博主的文章还不错或者您用得到的话,可以悄悄关注一下博主哈,如果三连收藏支持就更好啦!这就是给予我最大的支持!😙😙😙


文章目录

    • 学习目标
    • 一、均值卷积核的构建及分离性
      • 1.1 相关概念
      • 1.2 均值卷积核构建与分离
    • 二、快速均值平滑
    • 三、 C++实现
      • 3.1 均值平滑
      • 3.2 快速均值平滑
    • 四、 总结

学习目标

  • 了解均值平滑含义
  • 熟悉均值卷积核的构建及分离
  • 熟悉快速均值平滑原理及实现
  • C++实现均值平滑、快速均值平滑案例

  每一张图像都可能包含某种程度的噪声,噪声可以理解为由一种或者多种原因造成的灰度值的随机变化。
  在大多数情况下,通过平滑技术(也常称为滤波技术)进行抑制或者去除,其中具备保持边缘(Edge Preserving)作用的平滑技术得到了更多的关注。
  常用的平滑处理算法包括基于二维离散卷积高斯平滑、均值平滑,基于统计学方法的中值平滑,具备保持边缘作用的平滑算法的双边滤波、导向滤波等。

  下面将详细介绍均值平滑技术原理、常见应用及实现。


一、均值卷积核的构建及分离性

1.1 相关概念

  均值平滑,顾名思义,图像中每一个位置的邻域的平均值作为该位置的输出值

  高为H、宽为W 的均值卷积算子的构建方法很简单,令所有元素均为1/(W*H),即:

  其中,W、H均为奇数,锚点位置为 [(H-1)/2,(W-1)/2]。

1.2 均值卷积核构建与分离

  与高斯滤波核一样,均值平滑算子也是可分离卷积核,即:

  例如:5行3列的均值平滑算子可以进行以下分离:

  代码实现与分离的高斯卷积是类似的,只需将高斯算子替换成均值算子即可。利用卷积核的分离性和卷积的结合律。
  虽然减少了运算量,但是随着卷积核窗口大小的增加,计算量仍会继续增大,可以利用图像的积分,实现时间复杂度为O(1)的快速均值平滑


二、快速均值平滑

  学习快速均值平滑之前,先了解一下图像的积分。r行c列的图像矩阵I的积分Integral可以这样定义:

  即任意一个位置的积分等于该位置左上角所有值的和。例如:

  同时,也可以利用矩阵的积分,计算出矩阵中任意矩形区域的和

  例如:计算I的以(2,2)为中心,从左上角(rTop,cLeft)=(1,1)至右下角(rBottom,cRight)=(3,3)的矩形区域的和:

  可以从积分后的图像矩阵中找到对应的值计算:

即:5+1+7+1+5+9+2+6+2=54+1-8-9

  均值平滑的原理本质上是计算任意一个点的邻域的平均值,而平均值是由该邻域的和除以邻域的面积得到的。这样无论怎样改变平滑窗口的大小,都可以利用图像的积分图快速计算每个点的邻域的和

  对于图像积分,OpenCV提供了函数:


void cv::integral(InputArray src,
OutputArray sum,
int sdepth = -1 
)	
参数解释
src输入H×W矩阵,数据类型为CV_8U、CV_32F或者为CV_64F
sum输出矩阵,大小为(H+1)×(W+1)
depth输出图位深,若为-1则与src一致

  接下来介绍OpenCV均值平滑函数及C++实现快速均值平滑。


三、 C++实现

3.1 均值平滑

  OpenCV提供了函数:

void cv::blur(InputArray src,
		OutputArray dst,
		Size ksize,
		Point anchor = Point(-1,-1),
		int borderType = BORDER_DEFAULT 
)
参数解释
src输入矩阵,数据类型为CV_8U、CV_32F或者为CV_64F
dst输出矩阵,大小和数据类型与src一致
ksize均值平滑卷积核尺寸大小,Size(宽,高)
anchor锚点,Point(-1,-1)表示中心点
borderType边界扩充类型

注:边界扩充说明

  例如:

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include <cmath>
#include <opencv2/imgproc.hpp>

using namespace std;
using namespace cv;

int main(){
	cv::Mat src=cv::imread("image/path");
	cv:Mat dst;
	cv::blur(src,dst,Size(3,3),cv::Point(-1,-1));
	cv::imshow("src",src);
	cv::imshow("dst",dst);
	cv::waitKey(0);
	
	return 0;

  还有一个函数,也能实现均值平滑功能:


void cv::boxFilter(InputArray src,
		OutputArray dst,
		int ddepth,
		Size ksize,
		Pointanchor = Point(-1,-1),
		bool normalize = true,
		int borderType = BORDER_DEFAULT 
)	
参数解释
src输入矩阵,数据类型为CV_8U、CV_32F或者为CV_64F
dst输出矩阵,大小和数据类型与src一致
depth输出图位深,若为-1则与src一致
ksize均值平滑卷积核尺寸大小,Size(宽,高)
anchor锚点,Point(-1,-1)表示中心点
normalize是否归一化
borderType边界扩充类型(具体详见上面blur())

3.2 快速均值平滑

  通过定义函数fastMeanBlur()来实现快速均值平滑,其中该函数的参数image代表输入图像winSize代表平滑窗口的尺寸borderType代表边界扩充类型。具体代码如下:

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include <cmath>
#include <opencv2/imgproc.hpp>
using namespace std;
using namespace cv;

//快速均值平滑滤波
cv::Mat fastMeanBlur(cv::Mat image,cv::Size winSize,int boderType,Scalar value=Scalar()) {
	//判断滑动窗口大小是否为奇数
	int hei = winSize.height;
	int wei = winSize.width;
	CV_Assert(hei % 2 == 1 && wei  % 2 == 1);
	
	//滑动窗口的中心点
	int h_center = (hei - 1) / 2;
	int w_center = (wei - 1) / 2;

	//滑动窗口面积
	float area = float(hei * wei);
	cv::Mat padImg;
	//边界扩充
	cv::copyMakeBorder(image,padImg,h_center, h_center,w_center,w_center,boderType,value);

	//图像积分
	cv::Mat integralImage;
	cv::integral(padImg, integralImage,CV_32FC1);

	//输入图像矩阵宽高
	int cols = image.cols;
	int rows = image.rows;
	int c = 0, r = 0;
	
	Mat meanImage = Mat::zeros(image.size(), CV_32FC1);
	for (int h = h_center;h < h_center+rows; h++)
	{
		for (int w = 0; w < w_center+cols; w++)
		{
			float BottomRight = integralImage.at<float>(h + h_center + 1, w + w_center + 1);
			float TopLeft = integralImage.at<float>(h - h_center, w - w_center);
			float TopRight = integralImage.at<float>(h + h_center + 1, w -w_center);
			float BottomLeft = integralImage.at<float>(h - h_center,w + w_center+1);
			meanImage.at<float>(r, c) =(BottomRight + TopLeft - TopRight - BottomLeft) / area;
			c++;
		}
		r++;
		c = 0;
	}
	return meanImage;
}
	
}	

四、 总结

  最后,长话短说,大家看完就好好动手实践一下,切记不能三分钟热度、三天打鱼,两天晒网。OpenCV是学习图像处理理论知识比较好的一个途径,大家也可以自己尝试写写博客,来记录大家平时学习的进度,可以和网上众多学者一起交流、探讨,有什么问题希望大家可以积极评论交流,我也会及时更新,来督促自己学习进度。希望大家觉得不错的可以点赞、关注、收藏。


🚶🚶🚶 今天的文章就到这里啦~
喜欢的话,点赞👍、收藏⭐️、关注💟哦 ~

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

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

相关文章

Flutter学习四:Flutter开发基础(一)Widget

目录 0 引言 1 Widget 简介 1.1 Widget 概念 1.2 Widget 接口 1.3 Flutter中的四棵树 1.4 StatelessWidget 1.4.1 简介 1.4.2 Context上下文 1.5 StatefulWidget 1.6 State 1.6.1 简介 1.6.2 State生命周期 1.7 在 widget 树中获取State对象 1.7.1 通过Context…

详解如何使用nvm管理Node.js多版本

目录 NVM进行NodeJS多版本管理 背景 安装步骤 1. 下载nvm安装包 2. 安装nvm 使用步骤 下载nodejs 切换版本nodejs ​编辑 常用命令 NVM进行NodeJS多版本管理 背景 有的时候开发环境需要多个NodeJS的版本&#xff0c;这个时候就可以用NVM进行管理。 安装步骤 1. 下载n…

9 从0开始学PyTorch | 过拟合欠拟合、训练集验证集、关闭自动求导

这一小节在开始搞神经网络之前&#xff0c;我们先熟悉几个概念&#xff0c;主要还是把模型训练的流程打通。 过拟合和欠拟合 我们在日常的工作中&#xff0c;训练好的模型往往是要去评价它的准确率的&#xff0c;通过此来判断我们的模型是否符合我的要求。 几个可能的方案是&…

国外学位论文去哪里查找下载

查找下载国外博士论文最合适的文献数据库就是ProQuest学位论文全文数据库。 ProQuest学位论文全文数据库覆盖了大部分北美地区高等院校以及世界其他地区数千个高等院校每年获得通过的博硕士论文。是将ProQuest公司PQDD文摘库&#xff08;现名PQDT&#xff09;中适合中国科研人…

Windows 11 22H2 中文版、英文版 (x64、ARM64) 下载 (updated Jun 2023)

Windows 11 绕过 TPM 方法总结&#xff0c;通用免 TPM 镜像下载 (2023 年 6 月更新) 在虚拟机、Mac 电脑和 TPM 不符合要求的旧电脑上安装 Windows 11 的通用方法总结 请访问原文链接&#xff1a;https://sysin.org/blog/windows-11-no-tpm/&#xff0c;查看最新版。原创作品…

nuxt3 多级动态路由

需求&#xff1a; 写法&#xff1a; 对应 文件目录 pages\product\[class]\[brand]\[SPU].vue pages/ --| product/ ----| [class] ------| [brand] --------| [SPU].vue script 内跳转方法 const router useRouter() const nuxtApp useNuxtApp()const jumpSPU () >…

caffeine和google-guava cache缓存使用详解和源码介绍

google-guava cache 1.pom引入其依赖 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>20.0</version></dependency> 2.具体使用 com.google.common.cache.LoadingCache<Strin…

【selenium】问题记录

1、驱动和浏览器版本不一致 报错&#xff1a;selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version 106 问题原因&#xff1a; chrome版本114&#xff0c;Chromedriver版本106 …

机器学习之深度神经网络

目录 卷积神经网络与全连接神经网络 前向后向传播推导 通用手写体识别模型 人脸识别模型 电影评论情感分析模型 卷积神经网络与全连接神经网络 卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;和全连接神经网络&#xff08;Fully Conn…

Django学习笔记-用户名密码登录

笔记内容转载自 AcWing 的 Django 框架课讲义&#xff0c;课程链接&#xff1a;AcWing Django 框架课。 CONTENTS 1. 扩充Django数据库2. 实现获取用户信息3. 渲染登录与注册界面4. 实现登录与登出功能5. 实现注册功能6. 修改获取用户信息 1. 扩充Django数据库 首先我们先在 s…

JavaWeb学习路线(7)——文件上传

一、概念 &#xff08;一&#xff09;文件上传概念&#xff1a; 指将本地的图片、视频、音频等文件上传到服务器&#xff0c;供其他用户浏览或下载的过程。 &#xff08;二&#xff09;前端文件上传三元素 method“post”&#xff08;form&#xff09;enctype“multipart/for…

四、Bean 的作用域,Bean 的自动装配以及通过注解实现 Bean 的自动装配

文章目录 一、Bean 的作用域二、Bean 的自动装配三、通过注解实现 Bean 的自动装配 一、Bean 的作用域 Spring 官网 Bean 的作用域讲解 单例(Singleton)作用域&#xff1a;在这种作用域下&#xff0c;容器只会创建一个Bean实例对象&#xff0c;无论该Bean被注入到多少个其它B…

Unity使用MySQL

效果&#xff1a; 问题记录&#xff1a; unity mysql “The given key ‘utf8mb4‘ was not present in the dictionary” – 我这里数据库字符集没有utf8&#xff0c;改选utf8mb4 – 这个改了&#xff0c;那么MySQL配置文件也得改了。如下&#xff1a; – 然后还报错&…

字符、字符集、编码

一、基本概念 在计算机中&#xff0c;所有的内容都是以二进制数据存储的&#xff0c;而我们在屏幕上看到的字和符号以及看不到的字符都是二进制数据转换后的结果。将字符按照某种规则转成对应的二进制数据&#xff0c;这个过程称为编码&#xff1b;而相对应的&#xff0c;将二…

Azure获取linux服务器磁盘和控制台disk的对应关系

从Azure控制台上删除/卸载服务器上不用的磁盘时&#xff0c;需要确定服务器上磁盘和控制台上显示的磁盘的对应关系。以免当有多块磁盘时&#xff0c;卸载了错误的磁盘&#xff0c;引起生产事故。 通过LUN确定磁盘对应关系 什么是LUN&#xff1f; 逻辑单元号 (LUN) 是用于标识…

Vue之事件处理(v-on)

文章目录 前言一、v-on基本使用二、使用举例1.传参和不传参使用2.$event占位代表事件对象3.函数用箭头函数时this作用域4.正常未用箭头函数的this指向&#xff08;与未用箭头函数作比较&#xff09; 总结 前言 v-on&#xff1a;事件绑定 一、v-on基本使用 格式&#xff1a;&l…

Linux安装ElasticSearch和Kibana

es官网下载地址&#xff1a;https://www.elastic.co/cn/downloads/past-releases#elasticsearch 可以去官网下载包然后放到服务器 也可以使用wget进行下载安装 如果使用wget方式下载的话需要先安装 安装wget yum install -y wgetwget下载es&#xff1a;wget https://artifacts…

B+树的设计步骤

1.节点的结构&#xff08;如下图&#xff09; &#xff08;1&#xff09;键值对--key是标识&#xff1b;value是存储的具体数据 &#xff08;2&#xff09;节点的子节点--存储的是具体的子节点 &#xff08;3&#xff09;节点的后节点--标记后一个节点 &#xff08;4&#xff0…

JSP实现自定义标签【上】

目录 一、基础概念 1、标签语言的形式或结构 2、分类 二、自定义标签的开发及步骤 三、标签生命周期 1、返回值 四、案例 1、if 2、out 一、基础概念 JSP自定义标签是一种扩展JSP标记语言的方法。通过自定义标签&#xff0c;我们可以将自定义功能封装在一个独立的标签…

# rust abc(6): 字符串的简单使用

文章目录 1. 目的2. 数据类型2.1 str 类型2.2 标准库 String 类型 3. 常用 API3.1 len() 方法3.2 is_empty() 方法3.3 starts_with() 方法3.4 find() 方法 4. References 1. 目的 学习 Rust 语言中的字符串&#xff0c; 包括数据类型&#xff0c; 常用 API。 2. 数据类型 Ru…