图像处理二
滤除噪声干扰
图像平滑处理的目标之一就是消除或减少这些噪声,使图像更清晰、更易于分析或更适合后续处理。不同的平滑技术可以在一定程度上模糊图像,从而有助于平滑图像中的不规则性或噪声,使图像看起来更加均匀和连续。
例如,在数字图像中,常见的噪声类型包括高斯噪声(服从高斯分布的随机噪声)、椒盐噪声(随机出现的黑白点)等。通过应用滤波器(例如均值滤波、高斯滤波、中值滤波等),可以有效地消除或减轻这些噪声。
虽然图像平滑处理的主要目的是滤除噪声,但它也可能会在某些情况下减少图像的细节或轮廓。因此,在应用图像平滑处理时,需要根据特定的应用场景和需求权衡噪声滤除和图像细节保留之间的平衡。
三、噪声
opencv中,"噪声"通常指的是图像中的不希望的、随机的、无规律的像素值变化。
这些变化可能是由于传感器不完美、环境条件不稳定、数据传输过程中的干扰等原因引起的。
噪声可能以各种形式存在,包括高斯噪声、椒盐噪声等。
3.1图像噪声
由于图像采集、处理、传输等过程不可避免的会受到噪声的污染,妨碍人们对图像理解及分析处理。常见的图像噪声有高斯噪声、椒盐噪声等。
高斯噪声是指它的概率密度函数服从高斯分布(即正态分布)的一类噪声。如果一个噪声,它的幅度分布服从高斯
高斯噪声是指噪声密度函数服从高斯分布的一类噪声。由于高斯噪声在空间和频域中数学上的易处理性,这种噪声(也称为正态噪声)模型经常被用于实践中。
椒盐噪声也称为脉冲噪声,是图像中经常见到的一种噪声,它是一种随机出现的白点或者黑点,可能是亮的区域有黑色像素或是在暗的区域有白色像素(或是两者皆有)。
椒盐噪声的成因可能是影像讯号受到突如其来的强烈干扰而产生、类比数位转换器或位元传输错误等。例如失效的感应器导致像素值为最小值,饱和的感应器导致像素值为最大值。
3.2 滤波
我们用在尽量保证不将图像原本信息破坏的情况下,用“滤波”去处理在图像中“突出”的,“不平整”的地方抹除过滤。
3.2.1均值滤波
在opencv中,均值滤波是一种常见的图像滤波技术,用于平滑图像并减少噪声。均值滤波的基本思想是用像素周围邻域的平均值来替代每个像素的原始值。
cv2.blur(src, ksize, anchor, bordertype)
src: 输入图像
ksize:卷积核的大小
anchor:默认值(-1,-1),表示核中心
bordertype: 边界类型
(1)锚点
在函数 cv2.blur
或 cv2.gaussianblur
中,锚点的默认值是 -1, -1
,这意味着它将被设置为核的中心。这是因为核的中心通常位于核的尺寸的中间位置。
在使用这些函数时,你可以通过设置 anchor
参数来指定锚点的位置。例如,如果你希望核的中心位于左上角,你可以将 anchor
设置为 (0, 0)
。
import cv2
import numpy as np
# 读取图像
image = cv2.imread('input_image.jpg')
# 指定滤波器的大小(核的大小),通常为奇数
kernel_size = 5
anchor_point = (0, 0) # 锚点设置为左上角
# 应用均值滤波
blur = cv2.blur(image, (kernel_size, kernel_size), anchor=anchor_point)
# 显示原始图像和经过均值滤波后的图像
cv2.imshow('original image', image)
cv2.imshow('blurred image', blur)
cv2.waitkey(0)
cv2.destroyallwindows()
通过将 anchor_point
设置为 (0, 0)
,我们将核的中心点放置在了左上角
你可以尝试不同的锚点位置,以查看它对滤波结果的影响。在大多数情况下,使用默认值 -1, -1
将中心点放在核的中间通常是合适的。
(2)中心点(下面第3小点会详细解释)
布opencv中,当anchor
参数设置为(-1, -1)时,均值滤波的卷积核(kernel)通常是一个正方形的核,并且中心点位于核的几何中心。对于一个大小为(n,n)的核结构,中心点将位于第(n/2,n/2)个像素位置。
-
奇数大小的核:
- 对于奇数大小的卷积核,中心点就是卷积核的中心位置。例如,对于3x3的卷积核,中心点就在(1, 1)的位置。
-
偶数大小的核:
- 对于偶数的核结构大小,例如对于4x4的核结构,你可以通过在每个像素中心周围插入一个额外的像秦来创建一个5x5的核结构,并将锚点设置为(-1,-1)的位置。然后进行均值滤波,中心点仍然位于核结构的几何中心。
总的来说,当anchor
参数为(-1, -1)时,opencv会根据卷积核的大小选择合适的默认中心点位置。
即l:6x6的图像,想象成7x7的,找见7x7的中心点,却不要真的认为是7x7的就行吗,所以偶数的卷积核可能导致不均匀的平滑效果。
(3)核的大小奇偶数的区别
在使用均值滤波时,核的大小最好选择奇数。这是因为滤波器的中心元素位于核的中心,而选择奇数大小的核可以确保中心点周围有相等数量的像素。如果选择偶数大小的核,中心点就会落在像素之间,可能导致不均匀的平滑效果。
如果你使用偶数大小的核,opencv会向下取整来选择核的中心点位置。例如,如果你指定核的大小为4x4,实际上中心点将位于(2, 2)处。这可能会导致图像平滑效果的不均匀性。
(1)举例奇偶的例子
我们利用随机生成的点数,观看如何随机的变成平滑的,把某点周围差别较大的替换。
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
x=np.random.randint(0,256,(15,15),dtype=np.uint8)
x10=cv.blur(x,(3,3))
x100=cv.blur(x,(4,4))
图像x
图像x10
图像x100
(2)验证奇偶数的中心点
[ 1 ]奇数
[ 2 ] 偶数
(1)随机一个图
(2)随机二图
(4)边界处理
opencv 提供了多种边界处理方式,我们可以根据实际需要选用不同的边界处理模式。
# 因此cv2.blur()的一般形式为:
dst = cv2.blur( src, ksize,)
3.2.2 方框滤波
方框滤波(box filter)是一种基本的图像滤波技术,也称为均值滤波。它的原理很简单,就是用一个固定大小的方框(或者说是矩形窗口)覆盖图像的每个像素,然后取这个窗口内所有像素的平均值来替代原来的像素值。这种操作主要用于平滑图像,去除图像中的噪声,同时也会使图像变得模糊。
(1)实现方框滤波的函数
cv2.boxfilter()
是 opencv 中用于实现方框滤波的函数。下面是这个函数的基本介绍:
cv2.boxfilter(src, ddepth, ksize[, dst[, anchor[, normalize[, bordertype]]]]) → dst
src
: 输入图像,数据类型应为单通道浮点型或整型。ddepth
: 输出图像的深度,通常设置为-1,表示与输入图像的深度相同。ksize
: 方框滤波核的大小,指定一个 (width, height) 的元组。dst
: 可选参数,输出图像。anchor
: 可选参数,表示锚点的位置,默认为(-1, -1),即位于核的中心。normalize
: 可选参数,如果为 true,则对输出图像进行归一化处理,默认为 true。
这种灵活性使得方框滤波在一些特定的图像处理场景中具有更多的应用选择,因为有时候需要保留邻域像素值的总和而不是其平均值。这样的选择取决于具体的图像处理需求。
bordertype
: 可选参数,边界处理的方式,默认为cv2.border_default
。
这个函数实现了方框滤波的核心逻辑。方框滤波的原理是在图像的每个像素位置,用一个固定大小的方框覆盖该像素周围的区域,然后取这个区域内所有像素值的平均值作为该位置的像素值。这样可以达到平滑图像的效果。
下面是一个简单的例子,演示如何使用 cv2.boxfilter()
进行方框滤波:
import cv2
import numpy as np
# 读取图像
image = cv2.imread('input_image.jpg')
# 定义滤波器的大小,这里使用一个5x5的方框
kernel_size = (5, 5)
# 进行方框滤波
result = cv2.boxfilter(image, -1, kernel_size)
# 显示原始图像和滤波后的图像
cv2.imshow('original image', image)
cv2.imshow('box filter result', result)
cv2.waitkey(0)
cv2.destroyallwindows()
通过调整 kernel_size
和其他参数,你可以根据需要对图像进行不同程度的方框滤波。
(2)代码实践一下
【1】图片演示:
原图:
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
imgx=cv.imread('img/test_img.jpg')
clurx=cv.blur(imgx,(3,3))
r10=cv.boxfilter(imgx,-1,(3,3),normalize=1)
r100=cv.boxfilter(imgx,-1,(3,3),normalize=0)
plt.imshow(imgx[:,:,::-1])
print(imgx)
#%%
print("clurx")
plt.imshow(clurx[:,:,::-1])
print(clurx)
#%%
print("r10")
plt.imshow(r10[:,:,::-1])
print(r10)
#%%
print("r100")
plt.imshow(r100[:,:,::-1], vmin=0, vmax=255)
print(r100)
对比:
均值滤波和normalize=1
时,表示进行归一化处理。在这种情况下,cv2.boxfilter()
函数将邻域像素值的和除以邻域的面积,得到平均值作为输出图像中对应位置的像素值。
# 利用==判断仅仅返回一个判断矩阵,
# 表示其中每一个元素是否对应相等。
print((clurx==r10).all())
print((clurx==r10).any())
【2】利用随机数模拟一下实现过程
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
x=np.random.randint(0,256,(15,15),dtype=np.uint8)
x10=cv.blur(x,(3,3))
plt.imshow(x,cmap=plt.cm.gray)
print("x")
print(x)
r10=cv.boxfilter(x,-1,(3,3),normalize=1)
r100=cv.boxfilter(x,-1,(3,3),normalize=0)
plt.imshow(r10,cmap=plt.cm.gray)
print(r10)
【3】模拟中的参数 normalize=0的演示
先说一个plt显示的小东西
我们需要限制其最大数,否则会无限的黑,数字小的就是黑了
当你使用 cmap=‘gray’ 时,matplotlib 期望输入是一个类似于 numpy 数组的 2d 数组结构。在列表的情况下,它将每个内部列表解释为图像的一行,并尝试根据每行中的强度值分配不同的灰度值。
chatgpt给出的原因
当 vmin 和 vmax 的值相同时,颜色映射范围被压缩为一个点,即单一值。在灰度图像的情况下,这意味着只有一个颜色被用于表示所有的像素值,而这个颜色通常是黑色。
换换数据证明:
代码
import numpy as np
import matplotlib.pyplot as plt
y = [[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]]
norm = plt.normalize(vmin=0,vmax=255)
plt.imshow(y, cmap='gray', norm=norm)
plt.colorbar(ticks=[0, 255], format="%d") # 设置ticks和format
plt.show()
解决方案【两种】:
第一
plt.imshow(y_np, cmap='gray', vmin=0, vmax=255)
import numpy as np
import matplotlib.pyplot as plt
# 创建一个二维数组,最小值和最大值相同
data = np.array([[3, 3, 3],
[3, 3, 3],
[3, 3, 3]])
# 使用 imshow 显示图像,vmin 和 vmax 相同
plt.imshow(data, cmap='viridis', vmin=3, vmax=3)
# 显示颜色条
plt.colorbar()
# 显示图像
plt.show()
实际上,由于整个颜色映射范围被压缩成一个点,无论数据的具体值如何,颜色都将是相同的。这在可视化上失去了区分性,因为整个图像都是同一种颜色。
-
默认行为: 默认情况下,
plt.imshow()
将数据线性映射到颜色映射的范围。对于灰度图,颜色映射的默认范围是 [0, 1],因此如果你不指定vmin
和vmax
,plt.imshow()
会将数据线性映射到 [0, 1] 的范围。 -
颜色映射范围: 当你指定
vmin=0
和vmax=255
时,你告诉plt.imshow()
将数据映射到 [0, 255] 的范围,这与灰度图像中的像素值范围一致。这会使得颜色映射正确显示黑白灰。
总之,通过设置 vmin=0
和 vmax=255
,你确保了数据与颜色映射范围的一致性,从而正确地显示了图像。如果你使用默认设置,plt.imshow()
将尝试自动归一化数据,并可能导致显示不准确。
第二种:
plt.imshow(y_np, cmap='gray_r')
3.2.3 高斯滤波
高斯滤波是一种线性平滑滤波技术,它使用高斯函数来计算邻域内各个像素的权重,以进行图像的平滑处理。在高斯滤波中,离中心点越远的像素拥有更小的权重,而中心点的权重通常会被增强。
高斯滤波的主要优点之一是它能够在平滑图像的同时,有效地保留图像的边缘信息。这是因为离中心点较远的像素在计算平均值时得到的权重较小,从而对图像边缘的影响减小。
函数
cv2.gaussianblur(src, ksize, sigmax[, dst[, sigmay[, bordertype]]])
其中:
src
:输入图像,可以是灰度图像或彩色图像。ksize
:高斯核的大小,必须是正奇数(例如,3、5、7…)。sigmax
:x轴方向上的高斯核标准差。dst
:输出图像,可选参数。如果提供了该参数,将把结果存储在这个图像中。sigmay
:y轴方向上的高斯核标准差,可选参数。如果未提供,将默认与sigmax
相同。bordertype
:边界处理类型,可选参数。默认为cv2.border_default
。
使用示例:
import cv2
import numpy as np
# 读取图像
img = cv2.imread('input_image.jpg')
# 执行高斯滤波
ksize = (5, 5) # 高斯核大小为 5x5
sigmax = 0 # x轴方向上的标准差
blurred_img = cv2.gaussianblur(img, ksize, sigmax)
# 显示原始图像和处理后的图像
cv2.imshow('original image', img)
cv2.imshow('blurred image', blurred_img)
cv2.waitkey(0)
cv2.destroyallwindows()
在这个示例中,gaussianblur
函数将图像进行了高斯滤波,ksize
设置为 (5, 5),sigmax
设置为 0,即只在x轴方向进行滤波。函数返回一个新的图像,即经过高斯滤波处理的图像。
3.2.4 中值滤波
中值滤波是一种非线性滤波技术,用于去除图像中的噪声。与线性滤波方法(例如均值滤波和高斯滤波)不同,中值滤波不是基于像素的加权平均,而是基于邻域内像素值的排序。
中值滤波的基本步骤如下:
- 定义一个滑动窗口(通常是正方形或矩形的窗口)在图像上进行扫描。
- 将窗口内的像素值按照大小进行排序。
- 将中间值(中位数)作为窗口中心像素的新值。
中值滤波的优势在于它对图像中的椒盐噪声等离群值具有很好的去除效果。因为中值是在排序后取的,它不受极端值的影响,而均值滤波等线性滤波对异常值比较敏感。
中值滤波的一些特点和注意事项:
-
去除椒盐噪声: 中值滤波在去除椒盐噪声方面效果显著,这种噪声是图像中出现的亮或暗的离群值。
-
保留边缘: 相对于线性滤波方法,中值滤波在保留图像边缘方面更为出色,因为它不会导致像素值的平均化。
-
计算开销: 与线性滤波相比,中值滤波的计算开销较大,特别是对于大型窗口。这是因为它需要对像素进行排序。
使用python中的opencv库进行中值滤波的示例:
import cv2
import numpy as np
# 读取图像
img = cv2.imread('input_image.jpg')
# 中值滤波
median_blur = cv2.medianblur(img, 5) # 第二个参数是窗口大小,必须是正奇数
# 显示原始图像和中值滤波后的图像
cv2.imshow('original image', img)
cv2.imshow('median blur', median_blur)
cv2.waitkey(0)
cv2.destroyallwindows()
在这个示例中,cv2.medianblur
函数对图像进行了中值滤波,窗口大小为5x5。
函数
cv2.medianblur
函数是opencv中用于进行中值滤波的函数,其基本语法如下:
dst = cv2.medianblur(src, ksize)
其中:
src
:输入图像,可以是灰度图像或彩色图像。ksize
:指定中值滤波的窗口大小,必须是正奇数。
该函数返回一个经过中值滤波处理后的图像,存储在 dst
变量中。
使用示例:
import cv2
# 读取图像
img = cv2.imread('input_image.jpg')
# 中值滤波
ksize = 5 # 窗口大小,必须是正奇数
median_blur = cv2.medianblur(img, ksize)
# 显示原始图像和中值滤波后的图像
cv2.imshow('original image', img)
cv2.imshow('median blur', median_blur)
cv2.waitkey(0)
cv2.destroyallwindows()
在这个示例中,cv2.medianblur
函数对图像进行了中值滤波,窗口大小为5x5。中值滤波是一种有效的去除图像噪声的方法,尤其对于椒盐噪声等离群值具有很好的去除效果。
3.2.5 双边滤波
双边滤波(bilateral filtering)是一种非线性滤波技术,它可以在平滑图像的同时保留图像的边缘信息。这个滤波方法考虑到了空间域和灰度值域两个方面,因此对于图像中存在的不同纹理和边缘有着较好的处理效果。
基本的双边滤波函数如下:
dst = cv2.bilateralfilter(src, d, sigmacolor, sigmaspace)
其中:
src
:输入图像,可以是灰度图像或彩色图像。d
:控制滤波器的邻域直径。如果设置为 0,则根据sigmaspace
计算邻域直径。sigmacolor
:颜色空间中的标准差,用于控制颜色相似性。数值越大,颜色相似性越高。sigmaspace
:坐标空间中的标准差,用于控制空间相似性。数值越大,空间相似性越高。
双边滤波的一个重要特点是,它不仅考虑了像素之间的空间距离(空间域),还考虑了它们在灰度值上的相似性(灰度值域)。这使得双边滤波在平滑图像的同时,尽可能地保留了图像的边缘和细节信息。
使用示例:
import cv2
# 读取图像
img = cv2.imread('input_image.jpg')
# 双边滤波
d = 9 # 邻域直径
sigmacolor = 75 # 颜色空间标准差
sigmaspace = 75 # 空间域标准差
bilateral_filtered_img = cv2.bilateralfilter(img, d, sigmacolor, sigmaspace)
# 显示原始图像和双边滤波后的图像
cv2.imshow('original image', img)
cv2.imshow('bilateral filtered image', bilateral_filtered_img)
cv2.waitkey(0)
cv2.destroyallwindows()
在这个示例中,cv2.bilateralfilter
函数对图像进行了双边滤波,参数 d
、sigmacolor
和 sigmaspace
可以根据需要调整以获得最佳效果。
-
空间距离加权: 与高斯滤波不同,双边滤波不仅考虑像素在空间上的距离,而且考虑它们在颜色空间中的距离。像素之间的空间距离越近,权重越大;像素之间的颜色差别越小,权重越大。
-
颜色信息保护: 双边滤波在处理图像时注重保护颜色边缘。当处理到颜色变化较大的区域时,权重减小,从而减少平滑效果,保留颜色边缘信息。
-
边缘保护: 由于权重与空间距离和颜色距离的组合有关,双边滤波能够有效地保护图像中的边缘信息,不会导致边缘模糊。
-
计算开销较大: 与线性滤波方法相比,双边滤波的计算开销较大,因为对于每个像素,都需要计算其
与周围像素的空间距离和颜色距离,这可能导致一些性能上的牺牲。
3.2.6 2d 卷积
2d卷积(二维卷积)是一种图像处理和计算机视觉中常用的操作,用于图像滤波、特征提取等任务。它的基本思想是通过将一个小的核或滤波器在图像上滑动,将核的权重与图像中对应位置的像素值相乘,并将结果相加,从而得到卷积的输出。
在opencv中,cv2.filter2d
函数用于执行2d卷积操作。这个函数的基本语法如下:
dst = cv2.filter2d(src, ddepth, kernel[, dst[, anchor[, delta[, bordertype]]]])
其中:
src
:输入图像,可以是单通道灰度图像或多通道彩色图像。ddepth
:输出图像的深度,通常设置为-1
表示与输入图像的深度相同。kernel
:卷积核,是一个单通道numpy数组或矩阵。如果想在处理彩色图像时,让每个通道使用不
同的核,则必须将彩色图像分解后使用不同的核完成操作。dst
:可选参数,输出图像。如果提供了该参数,将把结果存储在这个图像中。anchor
:可选参数,表示卷积核的中心位置,默认为 (-1, -1),即卷积核的中心。delta
:可选参数,表示在卷积计算结果之前可选的加法操作,默认为 0。bordertype
:可选参数,表示图像边界的处理方式,默认为cv2.border_default
。
使用示例:
import cv2
import numpy as np
# 读取图像
img = cv2.imread('input_image.jpg', cv2.imread_grayscale)
# 定义卷积核
kernel = np.array([[1, 0, -1],
[1, 0, -1],
[1, 0, -1]])
# 进行2d卷积
result = cv2.filter2d(img, -1, kernel)
# 显示原始图像和卷积后的图像
cv2.imshow('original image', img)
cv2.imshow('2d convolution result', result)
cv2.waitkey(0)
cv2.destroyallwindows()
在这个示例中,cv2.filter2d
函数用卷积核 kernel
对灰度图像 img
进行了2d卷积操作,得到了卷积后的结果 result
。这是一种基本的卷积操作,可以通过调整卷积核的权重来实现不同的滤波效果。
发表评论