当前位置: 首页 > news >正文

opencv学习笔记2:卷积、均值滤波、中值滤波

目录

一、卷积概念

1.定义

2.数学原理

3.实例计算

(1) 输入与卷积核

(2)计算输出 g(2,2)

4.作用

二、针对图像噪声的滤波技术——均值滤波

1.均值滤波概念

(1)均值滤波作用

(2)计算方式

(3)均值滤波的缺点

2.均值滤波计算

3.均值滤波 核心函数

(1)cv2.filter2D() ——自定义卷积核

(2)cv.blur()——均值滤波专用函数

 总代码:

代码解释

均值滤波结果:

三.中值滤波

1.定义

2.选择滤波方法

3.中值滤波原理

4.核心函数

 5.总代码

详细解释 添加椒盐噪声函数:

最后还是用subplot将图片并排比较看着明显:



 

一、卷积概念

1.定义

在图像处理领域,卷积是一种极其重要且基础的数学运算。它的核心思想利用一个小矩阵,即卷积核(也常被称为滤波器),在输入图像上进行滑动操作。在滑动过程中,对于图像上的每个位置,卷积核会与该位置周围邻域内的像素进行相互作用。具体来说,就是将卷积核的每个元素与对应位置邻域内的像素值相乘,然后将这些乘积进行求和,得到的结果作为该位置新的像素值通过这样的方式,对图像上的所有位置都进行处理后,最终生成经过卷积操作处理后的新图像。卷积操作就像是一个“特征提取器”,能够根据卷积核的不同设计,提取出图像中不同的特征信息。

2.数学原理

设输入图像为$I$,它可以看作是一个二维的像素矩阵。卷积核为$K$,同样是一个二维矩阵。卷积操作输出图像 $O$ 中每个像素值 $O(i,j)$ 由以下公式计算得出:

$g(x,y)=\sum_{u=-k}^{k}\sum_{v=-l}^{l}f(x+u,y+v)h(u,v)$其中,k和l分别是卷积核在x和y方向上的半径。这个公式的含义是,对于输出图像 $g$ 中坐标为$(x,y)$的像素,需要在输入图像 $f$ 中以 $(x,y)$ 为中心,取与卷积核大小(2k+1)×(2l+1)相同的邻域。然后,将该邻域内的像素值与卷积核 $h$ 对应位置的元素值相乘,并将所有乘积相加,得到的和就是输出图像 $g$ 中 $(x,y)$ 位置的像素值。通过这个公式,卷积操作能够系统地对图像的每个像素进行处理,从而实现对图像的各种变换。

  • g :输出图像,g(x,y) 表示卷积后坐标 (x,y) 处的像素值
  • f:输入图像(二维像素矩阵),f(x,y) 表示坐标 (x,y) 处的像素值
  • h:卷积核(二维矩阵,如 3×3 边缘检测核),h(u,v) 表示卷积核第 u 行、第 v 列的权重
  • u,v为卷积核内的相对坐标,k和l分别是卷积核在x和y方向上的半径,通常卷积核大小为 (2k+1)×(2l+1)

3.实例计算

(1) 输入与卷积核

假设:

  • 输入图像 I(灰度图,截取 5×5 局部):

  • 卷积核 K(均值模糊核,3×3,权重均为 1/9):

(2)计算输出 g(2,2)

假设输入图像是一个 5×5 的矩阵,卷积核是一个 3×3 的矩阵。

输入图像矩阵

卷积核矩阵

这里,卷积核的尺寸为 3×3,因此 k=1,l=1。我们需要计算输出图像中的 g (2,2)。

根据卷积公式:$g(2,2)=\sum_{u=-1}^{1}\sum_{v=-1}^{1}f(2+u,2+v)h(u,v)$

我们需要计算所有 u 和 v 的组合(-1,0,1)对应的乘积并求和:

代入具体数值:

所以,g (2,2) 的值为 - 8。

4.作用

卷积操作在图像处理中具有广泛的应用,它能够改变图像的特征,以满足不同的处理需求。在图像滤波任务中,卷积可以去除图像中的噪声,使图像更加平滑;在边缘检测中,通过特定的卷积核设计,能够突出图像中像素值变化较大的区域,即图像的边缘;在特征提取方面,卷积能够提取出图像中的各种特征,如纹理、形状等,为后续的图像识别、目标检测等任务提供重要的信息。可以说,卷积操作是许多高级图像处理算法的基础。

二、针对图像噪声的滤波技术——均值滤波

图像噪声 是图像处理中常见的问题,它是由于各种原因引入的不希望的随机变化或干扰,导致图像质量下降。噪声可以出现在图像的亮度、颜色和纹理等方面,对图像分析、计算机视觉和图像处理任务造成困难。为了减少或消除图像中的噪声,常常使用不同类型的滤波技术。

高斯噪声:这是一种典型的连续随机噪声,其分布类似于高斯分布。它通常由电子器件或传感器的随机波动引起,会导致图像中像素值的微小随机变化

椒盐噪声:这是一种离散的随机噪声,通常表现为图像中的亮点和暗点,类似于椒盐的颗粒。这种噪声可能是由于传感器损坏或数据传输错误引起的。

均匀噪声:均匀噪声是一种均匀分布的随机噪声,它在图像中引入一种均匀的背景噪声,会降低图像对比度。

波纹噪声:这种噪声表现为图像中的周期性亮度和暗度变化,通常是由于光照不均匀或传感器故障引起的。

1.均值滤波概念

均值滤波概定义:均值滤波是一种线性平滑滤波方法,它通过将每个像素周围的像素值的平均值替换当前像素值来减小噪声。在图像处理中常用于降噪(如消除随机噪声点),但会以模糊图像细节为代价 

(1)均值滤波作用

均值滤波是一种简单而有效的滤波技术,用于去除图像中的噪声。均值滤波对于轻度高斯噪声去除效果良好因为噪声通常表现为图像中随机出现的、与周围像素值差异较大的像素点,通过均值滤波的平均操作,可以使这些噪声点的影响被周围像素值所“稀释”,但在去除噪声的同时可能会导致图像细节的模糊。

(2)计算方式

均值滤波基于一个小的滑动窗口,将窗口中像素的平均值分配给窗口中心的像素。这个操作在整个图像上以滑动窗口的方式进行。它所使用的均值卷积核具有这样的特点:核内所有元素值相同,并且这些元素值的总和为 1。在进行均值滤波时,卷积核在图像上滑动,对于每个位置的邻域像素,将它们的像素值进行简单的平均计算,得到的平均值作为该位置新的像素值。

(3)均值滤波的缺点

由于它对邻域内所有像素一视同仁地进行平均,在平滑噪声的同时,也可能会使图像的边缘变得模糊。因为图像的边缘通常是像素值变化较为剧烈的区域,均值滤波的平均操作会削弱这种变化,导致边缘的清晰度下降。

2.均值滤波计算

均值滤波是一种常见的线性滤波操作,核心是用卷积核覆盖区域内像素的平均值来替换中心像素值,以下用实例计算g (2,2):

3.均值滤波 核心函数

(1)cv2.filter2D() ——自定义卷积核

# 定义均值卷积核
kernel = np.ones((5, 5), np.float32) / 25
# 进行卷积操作(核心步骤)
dst = cv2.filter2D(image, -1, kernel)

① kernel = np.ones((5, 5), np.float32) / 25  解释:

  • 创建一个 5×5 的矩阵,所有元素初始化为 1(ones)
  • 每个元素除以 25(即 1/25 = 0.04
  • 这样的卷积核表示:取周围 25 个像素的平均值
  • 卷积核越大会产生更强的平滑效果,但也会使图像边缘和细节更模糊

② dst = cv2.filter2D(image, -1, kernel)    解释:

  • cv2.filter2D() 是 OpenCV 的通用卷积函数,参数如下:
    • image:输入图像
    • -1:输出图像的深度(-1 表示与输入相同)
    • kernel:使用的卷积核
  • 它会将卷积核在图像上滑动,对每个像素执行以下操作:
    1. 取出当前像素周围 5×5 区域 的像素值
    2. 将这些值与卷积核对应位置相乘(这里相当于直接求和)
    3. 将结果除以 25(即求平均值)
    4. 用这个平均值替换当前像素的值

效果: 

  • 每个像素的值被替换为其 5×5 邻域的平均值
  • 噪声点(异常值)会被周围像素 “平均化”,从而达到 平滑图像、减少噪声 的效果

(2)cv.blur()——均值滤波专用函数

blur = cv.blur(img, (5, 5))
  • cv.blur() 是 OpenCV 提供的均值滤波函数,它会用 (5,5) 大小的卷积核(5×5 窗口),对 img(输入图像)逐像素计算邻域均值,结果存入 blur,实现均值滤波的核心逻辑 。

 总代码:

import cv2
import numpy as np
import matplotlib.pyplot as plt# 读取图像
image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
if image is None:print("无法读取图像,请检查路径。")
else:# 定义均值卷积核kernel = np.ones((5, 5), np.float32) / 25# 进行卷积操作dst = cv2.filter2D(image, -1, kernel)
#上面这两行可以换成 blur = cv.blur(img, (5, 5))# 显示原始图像和卷积后的图像plt.subplot(121), plt.imshow(image, cmap='gray')plt.title('Original Image'), plt.xticks([]), plt.yticks([])plt.subplot(122), plt.imshow(dst, cmap='gray')plt.title('Convolved Image'), plt.xticks([]), plt.yticks([])plt.show()

代码解释

  1. 读取图像:cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE) 使用 OpenCV 的 imread 函数以灰度模式读取图像文件 example.jpg。灰度模式下,图像被表示为单通道矩阵,更便于进行滤波操作。如果图像读取失败,即返回值为 None,则打印提示信息,告知用户检查图像路径是否正确。
  2. 定义均值卷积核:kernel = np.ones((5, 5), np.float32) / 25 使用 NumPy 库创建一个大小为 5×5 的矩阵,其中所有元素初始值都为 1。然后将每个元素除以 25,使得卷积核内所有元素值的总和为 1,符合均值卷积核的要求。
  3. 进行卷积操作:dst = cv2.filter2D(image, -1, kernel) 使用 OpenCV 的 filter2D 函数对输入图像 image 进行二维卷积操作。
    • 参数1:输入图像
    • 参数 2:输出图像的深度(数据类型),决定了像素值的范围。ddepth = -1:表示输出图像的深度与输入图像相同(例如输入是uint8,输出也为uint8)。
    • 参数 3:kernel 则是前面定义的均值卷积核。
    • 函数返回经过卷积处理后的图像 dst。
  4. 显示原始图像和卷积后的图像:使用 matplotlib 库的 subplot 函数创建一个包含两个子图的绘图布局。plt.subplot(121),这里的1表示整个绘图区域被分成 1 行,2表示分成 2 列,最后的1代表当前操作的是第 1 个子图,表示第一个子图位于 1 行 2 列的第 1 个位置。plt.imshow(image, cmap='gray') 显示原始灰度图像,设置颜色映射为 gray 以正确显示灰度图像。plt.title('Original Image') 设置子图标题,plt.xticks([]) 和 plt.yticks([]) 则隐藏坐标轴刻度,使图像显示更加简洁。同理,plt.subplot(122) 显示卷积后的图像 dst,并进行相应的设置。最后 plt.show() 显示整个绘图。
  5. 使用plt.subplot(nrows, ncols, index)创建子图时,最后创建的子图会成为当前活跃子图。plt.xticks([])plt.yticks([])等函数默认作用于当前活跃的子图(即最后一个通过plt.subplot()创建的子图)。若连续调用plt.subplot()创建多个子图后,未明确切换子图,则后续的plt.xticks([])会应用到最后创建的子图。

均值滤波结果:

三.中值滤波

1.定义

中值滤波:中值滤波是一种非线性滤波方法,它用窗口中像素值的中值来替代当前像素的值。中值滤波的原理如下:

  • 将一个小的滑动窗口(通常是正方形的)放在图像的每个像素上。
  • 将窗口中的所有像素值排序,找到中值(即中间位置的像素值)。
  • 使用中值来替代当前像素的值。
     

中值滤波对椒盐噪声脉冲噪声的去除效果非常好,因为它不受极端值的影响。它可以保留图像的边缘和细节,但可能对高斯噪声的去除效果不如高斯滤波

2.选择滤波方法

选择适当的滤波方法取决于噪声的类型和图像的特性。通常,均值滤波对于轻度高斯噪声有效,而高斯滤波对于更强的高斯噪声适用。中值滤波通常在椒盐噪声和脉冲噪声的情况下表现良好,但不适用于高斯噪声。

此外,滤波器的窗口大小也是一个重要的参数。较小的窗口适用于去除细小的噪声,但可能会丧失图像细节。较大的窗口可以更好地去除大面积的噪声,但可能会模糊图像。综上所述,选择合适的滤波方法需要对噪声和图像进行仔细分析,以平衡噪声去除和图像细节保留之间的权衡。
 

3.中值滤波原理

 中值滤波会取当前像素点及其周围临近像素点(一共有奇数个像素点)的像素值,将这些像素值排序,然后将位于中间位置的像素值作为当前像素点的像素值。 对如下矩阵:

将其邻域设置为3×3大小,对其3×3邻域内像素点的像素值进行排序(升序降序均可),按升序排序后得到序列值为:[66,78,90,91,93,94,95,97,101]。在该序列中,处于中心位置(也叫中心点或中值点)的值是“93”,因此用该值替换原来的像素值78,作为当前点的新像素值。中值滤波效果如下:

4.核心函数

 在OpenCV中,实现中值滤波的函数是cv2.medianBlur(),其语法格式如下:

         dst=cv2.medianBlur(src,ksize)
  • dst是返回值,表示进行中值滤波后得到的处理结果。
  • src 是需要处理的图像,即源图像。它能够有任意数量的通道,并能对各个通道独立处理。图像深度应该是CV_8U、CV_16U、CV_16S、CV_32F 或者 CV_64F中的一种。   
  • ksize 是滤波核的大小。滤波核大小是指在滤波处理过程中其邻域图像的高度和宽度。需要注意,核大小必须是比1大的奇数,比如3、5、7等。 例如:ksize=3 表示使用 3×3 的邻域窗口。

 5.总代码

import cv2  as cvdef cv_show(name, img):cv.imshow(name, img)cv.waitKey(0)cv.destroyAllWindows()#添加椒盐噪声函数
def add_peppersalt_noise(image, n=10000):result = image.copy()# 测量图片的长和宽w, h =image.shape[:2]# 生成n个椒盐噪声for i in range(n):x = np.random.randint(1, w)y=  np.random.randint(1, h)if np.random.randint(0, 2) == 0 :result[x, y] = 0else:result[x,y] = 255return result#读图像
img = cv.imread('D:\\dlam.jpg')
if img is None:print('Failed to read the image')
#添加椒盐噪声
img1 = add_peppersalt_noise(img)
cv_show('after', img1)# 中值滤波,可对灰色图像和彩色图像使用
img2 = cv.medianBlur(img1, 3)
cv_show('after1', img2)
# ksize变大图像变模糊
img3 = cv.medianBlur(img1, 9)
cv_show('after2', img3)

详细解释 添加椒盐噪声函数:

#添加椒盐噪声函数
def add_peppersalt_noise(image, n=10000):result = image.copy()# 测量图片的长和宽w, h =image.shape[:2]# 生成n个椒盐噪声for i in range(n):x = np.random.randint(1, w)y=  np.random.randint(1, h)if np.random.randint(0, 2) == 0 :result[x, y] = 0else:result[x,y] = 255return result
  •  add_peppersalt_noise(image, n=10000)参数
    • image:输入图像,是一个 NumPy 数组,数据类型通常为uint8
    • n:要添加的噪声点数量,默认值为 10000。
  • np.random.randint(0, w):生成一个范围在[0, w-1)之间的随机整数,这里的w是图像的宽度。
  • np.random.randint(0, h):生成一个范围在[0, h-1)之间的随机整数,h是图像的高度。
  • np.random.randint(0, 2):生成随机整数 0 或者 1,且生成这两个数的概率是相等的。
  • 噪声类型判断
    • 当结果为 0 时,把当前像素值设为 0,也就是黑色,这就是 “椒噪声”。
    • 当结果为 1 时,将当前像素值设为 255,即白色,这就是 “盐噪声”。

最后还是用subplot将图片并排比较看着明显:

import cv2
import numpy as np
import matplotlib.pyplot as plt
def add_peppersalt_noise(img,n=10000):result=img.copy()h,w=img.shape[:2]for i in range(n):x=np.random.randint(1,w)y=np.random.randint(1,h)if np.random.randint(0,2)==0:result[x,y]=0else:result[x,y]=255return resultimg=cv2.imread('Y:\\pycharm\\lion.png',cv2.IMREAD_GRAYSCALE)
if img is None:print('无法读取')
else:img1=add_peppersalt_noise(img)img2=cv2.medianBlur(img1,3)img3=cv2.medianBlur(img1,5)plt.subplot(131),plt.imshow(img1,cmap='gray')plt.title('img1'),plt.xticks([]),plt.yticks([])plt.subplot(132), plt.imshow(img2, cmap='gray')plt.title('img2'), plt.xticks([]), plt.yticks([])plt.subplot(133), plt.imshow(img3, cmap='gray')plt.title('img3'), plt.xticks([]), plt.yticks([])plt.show()

相关文章:

  • 【数据结构与算法】从广度优先搜索到Dijkstra算法解决单源最短路问题
  • Linux权限探秘:驾驭权限模型,筑牢系统安全
  • 主流嵌入式Shell工具性能对比
  • 视频音频去掉开头结尾 视频去掉前n秒后n秒 电视剧去掉开头歌曲
  • 2025-04-22-X86 架构与 Arm 架构异同及应用
  • 【LeetCode】算法详解#6 ---除自身以外数组的乘积
  • python之可视化图形生成
  • AI短视频创富营
  • MCP(Model Context Protocol)与提示词撰写
  • 打卡第48天
  • 基于 llama-factory进行模型微调
  • android 模拟器如何进行单模块更新
  • SpringSecurity+vue通用权限系统2
  • 【设计模式】2.策略模式
  • Python Selenium登录网易邮箱
  • springboot启动mapper找不到方法对应的xml
  • 分形几何在医学可视化中的应用:从理论到Python实战
  • 支持selenium的chrome driver更新到137.0.7151.68
  • 【CSS-8】深入理解CSS选择器权重:掌握样式优先级的关键
  • LLMs 系列科普文(11)
  • 法语网站建设/百度收录入口
  • 网站开发员纵向发展/长沙网络推广只选智投未来
  • 网页设计网站架构/网站优化名词解释
  • 律师怎样做网站/游戏代理平台
  • 怎么做自助购物网站/谷歌网页版入口
  • 网站标题导航栏/哈尔滨最新疫情