【OpenCV】Chapter7.图像噪声与滤波器

举报
zstar 发表于 2022/08/30 23:49:58 2022/08/30
【摘要】 最近想对OpenCV进行系统学习,看到网上这份教程写得不错,于是跟着来学习实践一下。 【youcans@qq.com, youcans 的 OpenCV 例程, https://youcans.bl...

最近想对OpenCV进行系统学习,看到网上这份教程写得不错,于是跟着来学习实践一下。
【youcans@qq.com, youcans 的 OpenCV 例程, https://youcans.blog.csdn.net/article/details/125112487
程序仓库:https://github.com/zstar1003/OpenCV-Learning

添加噪声

高斯噪声

高斯噪声的概率密度函数为:
在这里插入图片描述
示例程序:

"""
高斯噪声
"""
import cv2
import matplotlib.pyplot as plt
import numpy as np


img = cv2.imread("../img/lena.jpg", 1)

mu, sigma = 0.0, 20.0
noiseGause = np.random.normal(mu, sigma, img.shape)
imgGaussNoise = img + noiseGause
imgGaussNoise = np.uint8(cv2.normalize(imgGaussNoise, None, 0, 255, cv2.NORM_MINMAX))  # 归一化为 [0,255]

plt.figure(figsize=(9, 3))
plt.subplot(131), plt.title("Origin"), plt.axis('off')
plt.imshow(img, 'gray', vmin=0, vmax=255)
plt.subplot(132), plt.title("GaussNoise"), plt.axis('off')
plt.imshow(imgGaussNoise, 'gray')
plt.subplot(133), plt.title("Gray Hist")
histNP, bins = np.histogram(imgGaussNoise.flatten(), bins=255, range=[0, 255], density=True)
plt.bar(bins[:-1], histNP[:])
plt.tight_layout()
plt.show()

在这里插入图片描述

瑞利噪声

瑞利噪声的概率密度函数为
在这里插入图片描述
示例程序:

"""
瑞利噪声
"""
import cv2
import matplotlib.pyplot as plt
import numpy as np


img = cv2.imread("../img/lena.jpg", 0)

a = 30.0
noiseRayleigh = np.random.rayleigh(a, size=img.shape)
imgRayleighNoise = img + noiseRayleigh
imgRayleighNoise = np.uint8(cv2.normalize(imgRayleighNoise, None, 0, 255, cv2.NORM_MINMAX))  # 归一化为 [0,255]

plt.figure(figsize=(9, 3))
plt.subplot(131), plt.title("Origin"), plt.axis('off')
plt.imshow(img, 'gray', vmin=0, vmax=255)
plt.subplot(132), plt.title("RayleighNoise"), plt.axis('off')
plt.imshow(imgRayleighNoise, 'gray')
plt.subplot(133), plt.title("Gray Hist")
histNP, bins = np.histogram(imgRayleighNoise.flatten(), bins=255, range=[0, 255], density=True)
plt.bar(bins[:-1], histNP[:])
plt.tight_layout()
plt.show()

在这里插入图片描述

伽马噪声

伽马噪声又称爱尔兰噪声,其概率密度函数为
在这里插入图片描述
示例程序:

"""
伽马噪声
"""
import cv2
import matplotlib.pyplot as plt
import numpy as np


img = cv2.imread("../img/lena.jpg", 0)

a, b = 10.0, 2.5
noiseGamma = np.random.gamma(shape=b, scale=a, size=img.shape)
imgGammaNoise = img + noiseGamma
imgGammaNoise = np.uint8(cv2.normalize(imgGammaNoise, None, 0, 255, cv2.NORM_MINMAX))  # 归一化为 [0,255]

plt.figure(figsize=(9, 3))
plt.subplot(131), plt.title("Origin"), plt.axis('off')
plt.imshow(img, 'gray', vmin=0, vmax=255)
plt.subplot(132), plt.title("Gamma noise"), plt.axis('off')
plt.imshow(imgGammaNoise, 'gray')
plt.subplot(133), plt.title("Gray hist")
histNP, bins = np.histogram(imgGammaNoise.flatten(), bins=255, range=[0, 255], density=True)
plt.bar(bins[:-1], histNP[:])
plt.tight_layout()
plt.show()

在这里插入图片描述

指数噪声

指数噪声的概率密度函数为
在这里插入图片描述
示例程序:

"""
指数噪声
"""
import cv2
import matplotlib.pyplot as plt
import numpy as np


img = cv2.imread("../img/lena.jpg", 0)

a = 10.0
noiseExponent = np.random.exponential(scale=a, size=img.shape)
imgExponentNoise = img + noiseExponent
imgExponentNoise = np.uint8(cv2.normalize(imgExponentNoise, None, 0, 255, cv2.NORM_MINMAX))  # 归一化为 [0,255]

plt.figure(figsize=(9, 3))
plt.subplot(131), plt.title("Origin"), plt.axis('off')
plt.imshow(img, 'gray', vmin=0, vmax=255)
plt.subplot(132), plt.title("Exponential noise"), plt.axis('off')
plt.imshow(imgExponentNoise, 'gray')
plt.subplot(133), plt.title("Gray hist")
histNP, bins = np.histogram(imgExponentNoise.flatten(), bins=255, range=[0, 255], density=True)
plt.bar(bins[:-1], histNP[:])
plt.tight_layout()
plt.show()

在这里插入图片描述

均匀噪声

均匀噪声的概率密度函数为
在这里插入图片描述

示例程序:

"""
均匀噪声
"""
import cv2
import matplotlib.pyplot as plt
import numpy as np


img = cv2.imread("../img/lena.jpg", 0)

mean, sigma = 10, 100
a = 2 * mean - np.sqrt(12 * sigma)  # a = -14.64
b = 2 * mean + np.sqrt(12 * sigma)  # b = 54.64
noiseUniform = np.random.uniform(a, b, img.shape)
imgUniformNoise = img + noiseUniform
imgUniformNoise = np.uint8(cv2.normalize(imgUniformNoise, None, 0, 255, cv2.NORM_MINMAX))  # 归一化为 [0,255]

plt.figure(figsize=(9, 3))
plt.subplot(131), plt.title("Origin"), plt.axis('off')
plt.imshow(img, 'gray', vmin=0, vmax=255)
plt.subplot(132), plt.title("Uniform noise"), plt.axis('off')
plt.imshow(imgUniformNoise, 'gray')
plt.subplot(133), plt.title("Gray hist")
histNP, bins = np.histogram(imgUniformNoise.flatten(), bins=255, range=[0, 255], density=True)
plt.bar(bins[:-1], histNP[:])
plt.tight_layout()
plt.show()

在这里插入图片描述

椒盐噪声

椒盐噪声的概率密度函数为
在这里插入图片描述

示例程序:

"""
椒盐噪声
"""
import cv2
import matplotlib.pyplot as plt
import numpy as np


img = cv2.imread("../img/lena.jpg", 0)

ps, pp = 0.05, 0.02
mask = np.random.choice((0, 0.5, 1), size=img.shape[:2], p=[pp, (1 - ps - pp), ps])
imgChoiceNoise = img.copy()
imgChoiceNoise[mask == 1] = 255
imgChoiceNoise[mask == 0] = 0

plt.figure(figsize=(9, 3))
plt.subplot(131), plt.title("Origin"), plt.axis('off')
plt.imshow(img, 'gray', vmin=0, vmax=255)
plt.subplot(132), plt.title("Choice noise"), plt.axis('off')
plt.imshow(imgChoiceNoise, 'gray')
plt.subplot(133), plt.title("Gray hist")
histNP, bins = np.histogram(imgChoiceNoise.flatten(), bins=255, range=[0, 255], density=True)
plt.bar(bins[:-1], histNP[:])
plt.tight_layout()
plt.show()

在这里插入图片描述

滤波器

当图片中含有噪声时,可以采用滤波器来进行滤除。

算术平均滤波器

算术平均滤波器是最简单的均值滤波器,与空间域滤波中的盒式滤波器相同。
计算公式如下:
在这里插入图片描述
简单理解,就是将一个盒子中的每一个像素点以整个盒子的平均值替代。盒子尺寸越大就越模糊。
在OpenCV中可以用cv2.filter2Dcv2.boxFilter两种方式实现。

示例程序:

"""
算术平均滤波器
"""
import cv2
import matplotlib.pyplot as plt
import numpy as np

img = cv2.imread("../img/lena_noise.jpg", 0)

kSize = (3, 3)
kernalMean = np.ones(kSize, np.float32) / (kSize[0] * kSize[1])  # 生成归一化盒式核
imgConv1 = cv2.filter2D(img, -1, kernalMean)  # cv2.filter2D 方法

kSize = (20, 20)
imgConv3 = cv2.boxFilter(img, -1, kSize)  # cv2.boxFilter 方法 (默认normalize=True)

plt.figure(figsize=(9, 6))
plt.subplot(131), plt.axis('off'), plt.title("Original")
plt.imshow(img, cmap='gray', vmin=0, vmax=255)
plt.subplot(132), plt.axis('off'), plt.title("filter2D(kSize=[3,3])")
plt.imshow(imgConv1, cmap='gray', vmin=0, vmax=255)
plt.subplot(133), plt.axis('off'), plt.title("boxFilter(kSize=[20,20])")
plt.imshow(imgConv3, cmap='gray', vmin=0, vmax=255)
plt.tight_layout()
plt.show()

在这里插入图片描述

几何均值滤波器

几何均值滤波器计算公式如下:
在这里插入图片描述

这里和算术平均滤波器进行对比:

"""
几何均值滤波器
"""
import cv2
import matplotlib.pyplot as plt
import numpy as np

img = cv2.imread("../img/lena_noise.jpg", 0)


img_h = img.shape[0]
img_w = img.shape[1]

# 算术平均滤波 (Arithmentic mean filter)
kSize = (3, 3)
kernalMean = np.ones(kSize, np.float32) / (kSize[0] * kSize[1])  # 生成归一化盒式核
imgAriMean = cv2.filter2D(img, -1, kernalMean)

# 几何均值滤波器 (Geometric mean filter)
m, n = 3, 3
order = 1 / (m * n)
kernalMean = np.ones((m, n), np.float32)  # 生成盒式核

hPad = int((m - 1) / 2)
wPad = int((n - 1) / 2)
imgPad = np.pad(img.copy(), ((hPad, m - hPad - 1), (wPad, n - wPad - 1)), mode="edge")

imgGeoMean = img.copy()
for i in range(hPad, img_h + hPad):
    for j in range(wPad, img_w + wPad):
        prod = np.prod(imgPad[i - hPad:i + hPad + 1, j - wPad:j + wPad + 1] * 1.0)
        imgGeoMean[i - hPad][j - wPad] = np.power(prod, order)

plt.figure(figsize=(9, 6))
plt.subplot(131), plt.axis('off'), plt.title("Original")
plt.imshow(img, cmap='gray', vmin=0, vmax=255)
plt.subplot(132), plt.axis('off'), plt.title("Arithmentic mean filter")
plt.imshow(imgAriMean, cmap='gray', vmin=0, vmax=255)
plt.subplot(133), plt.axis('off'), plt.title("Geometric mean filter")
plt.imshow(imgGeoMean, cmap='gray', vmin=0, vmax=255)
plt.tight_layout()
plt.show()

在这里插入图片描述

谐波平均滤波器

谐波平均滤波器计算公式如下:
在这里插入图片描述
谐波平均滤波器既能处理盐粒噪声(白色噪点),又能处理类似于高斯噪声的其他噪声,但不能处理胡椒噪声(黑色噪点)。

"""
谐波平均滤波器
"""
import cv2
import matplotlib.pyplot as plt
import numpy as np

img = cv2.imread("../img/lena_noise.jpg", 0)

img_h = img.shape[0]
img_w = img.shape[1]

# 算术平均滤波 (Arithmentic mean filter)
kSize = (3, 3)
kernalMean = np.ones(kSize, np.float32) / (kSize[0] * kSize[1])  # 生成归一化盒式核
imgAriMean = cv2.filter2D(img, -1, kernalMean)

# 谐波平均滤波器 (Harmonic mean filter)
m, n = 3, 3
order = m * n
kernalMean = np.ones((m, n), np.float32)  # 生成盒式核

hPad = int((m - 1) / 2)
wPad = int((n - 1) / 2)
imgPad = np.pad(img.copy(), ((hPad, m - hPad - 1), (wPad, n - wPad - 1)), mode="edge")

epsilon = 1e-8
imgHarMean = img.copy()
for i in range(hPad, img_h + hPad):
    for j in range(wPad, img_w + wPad):
        sumTemp = np.sum(1.0 / (imgPad[i - hPad:i + hPad + 1, j - wPad:j + wPad + 1] + epsilon))
        imgHarMean[i - hPad][j - wPad] = order / sumTemp

plt.figure(figsize=(9, 6))
plt.subplot(131), plt.axis('off'), plt.title("Original")
plt.imshow(img, cmap='gray', vmin=0, vmax=255)
plt.subplot(132), plt.axis('off'), plt.title("Arithmentic mean filter")
plt.imshow(imgAriMean, cmap='gray', vmin=0, vmax=255)
plt.subplot(133), plt.axis('off'), plt.title("Harmonic mean filter")
plt.imshow(imgHarMean, cmap='gray', vmin=0, vmax=255)
plt.tight_layout()
plt.show()

在这里插入图片描述

反谐波平均滤波器

反谐波平均滤波器适用于降低或消除椒盐噪声,计算公式如下:
在这里插入图片描述

Q 称为滤波器的阶数,Q 取正整数时可以消除胡椒噪声,Q 取负整数时可以消除盐粒噪声,但不能同时消除这两种噪声。

反谐波平均滤波器当 Q=0 时简化为算术平均滤波器;当 Q=−1时简化为谐波平均滤波器。

示例程序:

"""
反谐波平均滤波器
"""
import cv2
import matplotlib.pyplot as plt
import numpy as np

img = cv2.imread("../img/lena_noise.jpg", 0)

img_h = img.shape[0]
img_w = img.shape[1]

m, n = 3, 3
order = m * n
kernalMean = np.ones((m, n), np.float32)  # 生成盒式核

hPad = int((m - 1) / 2)
wPad = int((n - 1) / 2)
imgPad = np.pad(img.copy(), ((hPad, m - hPad - 1), (wPad, n - wPad - 1)), mode="edge")

Q = 1.5  # 反谐波平均滤波器 阶数
epsilon = 1e-8
imgHarMean = img.copy()
imgInvHarMean = img.copy()
for i in range(hPad, img_h + hPad):
    for j in range(wPad, img_w + wPad):
        # 谐波平均滤波器 (Harmonic mean filter)
        sumTemp = np.sum(1.0 / (imgPad[i - hPad:i + hPad + 1, j - wPad:j + wPad + 1] + epsilon))
        imgHarMean[i - hPad][j - wPad] = order / sumTemp

        # 反谐波平均滤波器 (Inv-harmonic mean filter)
        temp = imgPad[i - hPad:i + hPad + 1, j - wPad:j + wPad + 1] + epsilon
        imgInvHarMean[i - hPad][j - wPad] = np.sum(np.power(temp, (Q + 1))) / np.sum(np.power(temp, Q) + epsilon)

plt.figure(figsize=(9, 6))
plt.subplot(131), plt.axis('off'), plt.title("Original")
plt.imshow(img, cmap='gray', vmin=0, vmax=255)
plt.subplot(132), plt.axis('off'), plt.title("Harmonic mean filter")
plt.imshow(imgHarMean, cmap='gray', vmin=0, vmax=255)
plt.subplot(133), plt.axis('off'), plt.title("Invert harmonic mean")
plt.imshow(imgInvHarMean, cmap='gray', vmin=0, vmax=255)
plt.tight_layout()
plt.show()

在这里插入图片描述

统计排序滤波器

统计排序滤波器是空间滤波器,其响应是基于滤波器邻域中的像素值的顺序,排序结果决定了滤波器的输出。
统计排序包括中值滤波器、最大值滤波器、最小值滤波器、中点滤波器和修正阿尔法均值滤波器。

  • 中值滤波器:用预定义的像素邻域中的灰度中值来代替像素的值,与线性平滑滤波器相比能有效地降低某些随机噪声,且模糊度要小得多。

在这里插入图片描述

  • 最大值滤波器:用预定义的像素邻域中的灰度最大值来代替像素的值,可用于找到图像中的最亮点,或用于消弱与明亮区域相邻的暗色区域,也可以用来降低胡椒噪声。
    在这里插入图片描述

  • 最小值滤波器:用预定义的像素邻域中的灰度最小值来代替像素的值,可用于找到图像中的最暗点,或用于削弱与暗色区域相邻的明亮区域,也可以用来降低盐粒噪声。

在这里插入图片描述

  • 中点滤波器:用预定义的像素邻域中的灰度的最大值与最小值的均值来代替像素的值,注意中点的取值与中值常常是不同的。中点滤波器是统计排序滤波器与平均滤波器的结合,适合处理随机分布的噪声,例如高斯噪声、均匀噪声。

在这里插入图片描述

示例程序:

"""
统计排序滤波器
"""
import cv2
import matplotlib.pyplot as plt
import numpy as np

img = cv2.imread("../img/lena_noise.jpg", 0)

img_h = img.shape[0]
img_w = img.shape[1]

m, n = 3, 3
kernalMean = np.ones((m, n), np.float32)  # 生成盒式核

# 边缘填充
hPad = int((m - 1) / 2)
wPad = int((n - 1) / 2)
imgPad = np.pad(img.copy(), ((hPad, m - hPad - 1), (wPad, n - wPad - 1)), mode="edge")

imgMedianFilter = np.zeros(img.shape)  # 中值滤波器
imgMaxFilter = np.zeros(img.shape)  # 最大值滤波器
imgMinFilter = np.zeros(img.shape)  # 最小值滤波器
imgMiddleFilter = np.zeros(img.shape)  # 中点滤波器
for i in range(img_h):
    for j in range(img_w):
        # # 1. 中值滤波器 (median filter)
        pad = imgPad[i:i + m, j:j + n]
        imgMedianFilter[i, j] = np.median(pad)

        # # 2. 最大值滤波器 (maximum filter)
        pad = imgPad[i:i + m, j:j + n]
        imgMaxFilter[i, j] = np.max(pad)

        # # 3. 最小值滤波器 (minimum filter)
        pad = imgPad[i:i + m, j:j + n]
        imgMinFilter[i, j] = np.min(pad)

        # # 4. 中点滤波器 (middle filter)
        pad = imgPad[i:i + m, j:j + n]
        imgMiddleFilter[i, j] = int(pad.max() / 2 + pad.min() / 2)

plt.figure(figsize=(9, 7))
plt.subplot(221), plt.axis('off'), plt.title("median filter")
plt.imshow(imgMedianFilter, cmap='gray', vmin=0, vmax=255)
plt.subplot(222), plt.axis('off'), plt.title("maximum filter")
plt.imshow(imgMaxFilter, cmap='gray', vmin=0, vmax=255)
plt.subplot(223), plt.axis('off'), plt.title("minimum filter")
plt.imshow(imgMinFilter, cmap='gray', vmin=0, vmax=255)
plt.subplot(224), plt.axis('off'), plt.title("middle filter")
plt.imshow(imgMiddleFilter, cmap='gray', vmin=0, vmax=255)
plt.tight_layout()
plt.show()

在这里插入图片描述
原图添加的椒盐噪声,可以看到中值滤波滤除得较好。

修正阿尔法均值滤波器

修正阿尔法均值滤波器也属于统计排序滤波器,其思想类似于比赛中去掉最高分和最低分后计算平均分。
其计算公式为:

在这里插入图片描述
d表示d个最低灰度值和d个最高灰度值,d 的取值范围是[0,mn/2−1]。选择d的大小对图像处理的效果影响很大,当 d=0 时简化为算术平均滤波器,当 d=mn/2−1 简化为中值滤波器。

示例程序:

"""
修正阿尔法均值滤波器
"""
import cv2
import matplotlib.pyplot as plt
import numpy as np

img = cv2.imread("../img/lena_noise.jpg", 0)

img_h = img.shape[0]
img_w = img.shape[1]

m, n = 5, 5
kernalMean = np.ones((m, n), np.float32)  # 生成盒式核

# 边缘填充
hPad = int((m - 1) / 2)
wPad = int((n - 1) / 2)
imgPad = np.pad(img.copy(), ((hPad, m - hPad - 1), (wPad, n - wPad - 1)), mode="edge")

imgAlphaFilter0 = np.zeros(img.shape)
imgAlphaFilter1 = np.zeros(img.shape)
imgAlphaFilter2 = np.zeros(img.shape)
for i in range(img_h):
    for j in range(img_w):
        # 邻域 m * n
        pad = imgPad[i:i + m, j:j + n]
        padSort = np.sort(pad.flatten())  # 对邻域像素按灰度值排序

        d = 1
        sumAlpha = np.sum(padSort[d:m * n - d - 1])  # 删除 d 个最大灰度值, d 个最小灰度值
        imgAlphaFilter0[i, j] = sumAlpha / (m * n - 2 * d)  # 对剩余像素进行算术平均

        d = 2
        sumAlpha = np.sum(padSort[d:m * n - d - 1])
        imgAlphaFilter1[i, j] = sumAlpha / (m * n - 2 * d)

        d = 4
        sumAlpha = np.sum(padSort[d:m * n - d - 1])
        imgAlphaFilter2[i, j] = sumAlpha / (m * n - 2 * d)

plt.figure(figsize=(9, 7))
plt.subplot(221), plt.axis('off'), plt.title("Original")
plt.imshow(img, cmap='gray', vmin=0, vmax=255)
plt.subplot(222), plt.axis('off'), plt.title("Modified alpha-mean(d=1)")
plt.imshow(imgAlphaFilter0, cmap='gray', vmin=0, vmax=255)
plt.subplot(223), plt.axis('off'), plt.title("Modified alpha-mean(d=2)")
plt.imshow(imgAlphaFilter1, cmap='gray', vmin=0, vmax=255)
plt.subplot(224), plt.axis('off'), plt.title("Modified alpha-mean(d=4)")
plt.imshow(imgAlphaFilter2, cmap='gray', vmin=0, vmax=255)
plt.tight_layout()
plt.show()

在这里插入图片描述

文章来源: zstar.blog.csdn.net,作者:zstar-_,版权归原作者所有,如需转载,请联系作者。

原文链接:zstar.blog.csdn.net/article/details/126586908

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。