Python图像处理【13】使用PIL执行图像降噪

news2024/10/7 20:34:40

使用PIL执行图像降噪

    • 0. 前言
    • 1. 均值滤波器
      • 1.1 均值滤波器原理
      • 1.2 使用均值滤波器去除椒盐噪声
    • 2. 高斯滤波器
      • 2.1 高斯滤波器原理
      • 2.2 使用高斯模糊滤波器去除椒盐噪声
    • 3. 中值滤波器
      • 3.1 中值滤波器原理
      • 3.2 使用中值滤波器去除椒盐噪声
    • 小结
    • 系列链接

0. 前言

在本节中,我们将介绍一些空域滤波器,以及如何使用 Pillow 库函数实现这些滤波器。我们将介绍诸如平均 (mean) 和加权平均 (weighted mean) 之类的线性滤波器,在后续的学习中我们会介绍诸如 maxmin 滤波器之类的非线性滤波器。通过在图像上滑动应用卷积核窗口,每个输出像素是输入图像中对应输入像素的邻域像素的(线性或非线性)函数。

1. 均值滤波器

1.1 均值滤波器原理

移动均值或方形滤波器是所有滤波器中最简单的,它用以像素为中心的正方形中的像素值的平均值替换像素中心值。我们可以使用以下公式定义通用线性滤波器,方形滤波器是线性滤波器的一种特殊情况:

( 2 m + 1 ) × ( 2 m + 1 ) (2m+1)\times(2m+1) (2m+1)×(2m+1) 线性滤波器:
g i j = ∑ k = − m m ∑ l = − m m w k l ⋅ f i + k , j + l g_{ij}=\sum ^m _{k=-m} \sum ^m _{l=-m} wkl \cdot f_{i+k,j+l} gij=k=mml=mmwklfi+k,j+l
m = 1 m=1 m=1 时表示 3 × 3 3\times 3 3×3 滤波器,在方形滤波器中 w k l = 1 ( 2 m + 1 ) 2 w_{kl}=\frac 1 {(2m+1)^2} wkl=(2m+1)21。将以上滤波器展开,可得:
g i j = w − 1 , − 1 f i − 1 , j − 1 + w − 1 , 0 f i − 1 , j + w − 1 , 1 f i − 1 , j + 1 + w 0 , − 1 f i , j − 1 + w 0 , 0 f i , j + w 0 , 1 f i , j + 1 + w 1 , − 1 f i + 1 , j − 1 + w 1 , 0 f i + 1 , j + w 1 , 1 f i + 1 , j + 1 g_{ij}=w_{-1,-1}f_{i-1,j-1}+w_{-1,0}f_{i-1,j}+w_{-1,1}f_{i-1,j+1}+w_{0,-1}f_{i,j-1}+w_{0,0}f_{i,j}+w_{0,1}f_{i,j+1}+w_{1,-1}f_{i+1,j-1}+w_{1,0}f_{i+1,j}+w_{1,1}f_{i+1,j+1} gij=w1,1fi1,j1+w1,0fi1,j+w1,1fi1,j+1+w0,1fi,j1+w0,0fi,j+w0,1fi,j+1+w1,1fi+1,j1+w1,0fi+1,j+w1,1fi+1,j+1

在本节中,我们将使用 PILfilter() 函数将方形模糊滤波器应用于带有噪声的输入 RGB 图像,并观察不同噪声水平的平滑度。

1.2 使用均值滤波器去除椒盐噪声

(1) 首先代码导入所需库:

import numpy as np
import matplotlib.pylab as plt
from PIL import Image, ImageFilter
from copy import deepcopy

(2) 定义函数 plot_image() 使用 matlplotlib.pyplot 模块的 imshow() 函数显示图像如下:

def plot_image(image, title=None, sz=10):
    plt.imshow(image)
    plt.title(title, size=sz)
    plt.axis('off')

(3) 定义函数 add_noise() 在图像中添加椒盐(脉冲)噪声。除了输入图像外,该函数还可以接受三个参数,其中 prop_noise 参数用于定义输入像素的噪声比例,参数 saltpepper 用于控制图像应用盐噪声(白像素)还是椒噪声(黑像素),令函数更加通用,默认情况下,同时使用两种类型的噪声像素:

def add_noise(im, prop_noise, salt=True, pepper=True):
    im = deepcopy(im)
    n = int(im.width * im.height * prop_noise)
    x, y = np.random.randint(0, im.width, n), np.random.randint(0, im.height, n)
    for (x,y) in zip(x,y):
        im.putpixel((x, y),         # generate salt-and-pepper noise
        ((0,0,0) if np.random.rand() < 0.5 else (255,255,255)) if salt and pepper \
        else (255,255,255) if salt \
        else (0, 0, 0)) # if pepper
    return im

(4) 读取输入图像。对于不同的噪声级别/比例,在输入图像中添加脉冲噪声,然后使用 image.filter() 方法应用模糊滤波器以平滑带有噪声的图像,绘制每种情况下获得的输出图像。

如前所述,模糊滤波器通过将每个像素设置为方形核窗口中像素的平均值来模糊图像,从而在每个方向上延伸半径像素。支持任意大小的浮点类型半径,默认使用 3x3` 方形模糊滤波器。

orig = Image.open('1.png')
i = 1
plt.figure(figsize=(12,35))

for prop_noise in np.linspace(0.05,0.3,6):
    # choose random locations inside image
    im = add_noise(orig, prop_noise)
    plt.subplot(6,2,i), plot_image(im, 'Original Image with ' + str(int(100*prop_noise)) + '% added noise')
    im1 = im.filter(ImageFilter.BLUR)
    plt.subplot(6,2,i+1), plot_image(im1, 'Blurred Image')
    i += 2

plt.show()

均值滤波器
从以上图像可以看出,噪声比例越少,降噪和平滑效果越好(模糊程度越低)。

2. 高斯滤波器

2.1 高斯滤波器原理

尽管移动平均滤波器 (moving average filter) 的计算非常方便快捷,但它具有以下两个缺点,因此可能导致滤波图像中产生伪影:

  • 它并不是各向同性的(即圆形对称的),沿着对角线比沿着行和列更平滑
  • 权重间的变化非常突兀,而不是逐渐衰减至零,这会使平滑图像中的产生不连续性

为了克服这些缺点,可以计算近似于圆形而不是正方形邻域的平均值。为了实现此目的,我们通常可以使用高斯滤波器实现,高斯过滤器是唯一可分解的滤波器,可以将高斯滤波器分解表示为两个 1D 高斯滤波器的乘积,并且至少是近似圆形对称。从核中心到核边缘的权重会逐渐过渡衰减为零。以下表达式展示了高斯滤波器核,并给出了两个高斯核示例,核尺寸大小分别为 3x35x5

高斯滤波器核权重:
w k l = 1 2 π σ 2 e x p { − ( k 2 + l 2 ) 2 σ 2 } w_{kl}=\frac 1 {2\pi \sigma ^2}exp\{\frac {-(k^2+l^2)} {2\sigma ^2}\} wkl=2πσ21exp{2σ2(k2+l2)}

3 × 3 3\times3 3×3 高斯滤波器如下:
1 16 [ 1 2 1 2 4 2 1 2 1 ] \frac 1 {16} \left[ \begin{array}{ccc} 1 & 2 & 1\\ 2 & 4 & 2\\ 1 & 2 & 1\\ \end{array} \right] 161 121242121

5 × 5 5\times5 5×5 高斯滤波器如下:
1 256 [ 1 4 6 4 1 4 16 24 16 4 6 24 36 24 6 4 16 24 16 4 1 4 6 4 1 ] \frac 1 {256} \left[ \begin{array}{ccc} 1 & 4 & 6 & 4 & 1\\ 4 & 16 & 24 & 16 & 4\\ 6 & 24 & 36 & 24 & 6\\ 4 & 16 & 24 & 16 & 4\\ 1 & 4 & 6 & 4 & 1\\ \end{array} \right] 2561 1464141624164624362464162416414641

2.2 使用高斯模糊滤波器去除椒盐噪声

(1) 首先读取输入 RGB 彩色图像,并添加固定比例 (20%) 的脉冲噪声:

import numpy as np
import matplotlib.pylab as plt
from PIL import Image, ImageFilter
from copy import deepcopy

def plot_image(image, title=None, sz=10):
    plt.imshow(image)
    plt.title(title, size=sz)
    plt.axis('off')

def add_noise(im, prop_noise, salt=True, pepper=True):
    im = deepcopy(im)
    n = int(im.width * im.height * prop_noise)
    x, y = np.random.randint(0, im.width, n), np.random.randint(0, im.height, n)
    for (x,y) in zip(x,y):
        im.putpixel((x, y),         # generate salt-and-pepper noise
        ((0,0,0) if np.random.rand() < 0.5 else (255,255,255)) if salt and pepper \
        else (255,255,255) if salt \
        else (0, 0, 0)) # if pepper
    return im

im = Image.open('1.png')
im = add_noise(im, prop_noise = 0.2)

(2) 使用 PIL 中的 image.filter() 方法,使用 ImageFilter.GaussianBlur 实例化具有不同的半径参数值(从 1 开始到 3 )的高斯滤波器,并绘制输出图像:

plt.figure(figsize=(20,15))
i = 1
for radius in np.linspace(1, 3, 12):
    im1 = im.filter(ImageFilter.GaussianBlur(radius))
    plt.subplot(3,4,i)
    plot_image(im1, 'radius = ' + str(round(radius,2)))
    i += 1
plt.suptitle('PIL Gaussian Blur with different Radius', size=13)
plt.show()

高斯模糊

上图显示了代码的执行结果。可以看出,在使用高斯滤波器执行去噪任务时,半径越大,图像就会变得更加平滑,可以消除更多的噪声,但同时会使图像逐渐模糊,丢失细节。

3. 中值滤波器

3.1 中值滤波器原理

邻域平均可以抑制孤立的异常值噪声,但相应的副作用是它也会模糊图像中较为突然变化,例如线条特征、锐利的边缘和其他图像细节,这些图像细节均与高频相对应。非线性中值滤波器在保持图像中有用细节方面通常比线性均值滤波器更加有效,并且更适合去除图像中的椒盐噪声。
与平均滤波器一样,中值滤波器依次考虑图像中的每个像素,并查看其窗口邻域中的像素值来决定该像素能否表示周围邻域。它不是简单地用相邻像素值的平均值替换像素,而是用这些值的中位数代替。首先将周围邻域中的所有像素值按数字顺序排序,然后用排序后的序列中间值替换像素值。

3.2 使用中值滤波器去除椒盐噪声

首先,导入所需 Python 库,读取输入 RGB 彩色图像,并在输入图像中添加 1% 随机脉冲噪声:

import numpy as np
import matplotlib.pylab as plt
from PIL import Image, ImageFilter
from copy import deepcopy

def plot_image(image, title=None, sz=10):
    plt.imshow(image)
    plt.title(title, size=sz)
    plt.axis('off')

def add_noise(im, prop_noise, salt=True, pepper=True):
    im = deepcopy(im)
    n = int(im.width * im.height * prop_noise)
    x, y = np.random.randint(0, im.width, n), np.random.randint(0, im.height, n)
    for (x,y) in zip(x,y):
        im.putpixel((x, y),         # generate salt-and-pepper noise
        ((0,0,0) if np.random.rand() < 0.5 else (255,255,255)) if salt and pepper \
        else (255,255,255) if salt \
        else (0, 0, 0)) # if pepper
    return im

im = Image.open('1.png')
im = add_noise(im, prop_noise = 0.1)

使用 PILimage.filter() 函数指定参数 ImageFilter.MedianFilter 创建多个不同核窗口大小的中值滤波器,绘制使用不同尺寸大小的滤波器得到的输出图像。

如前所述,中值滤波器为从给定大小的滑动窗口中选取中值像素值:

plt.figure(figsize=(20,10))
plt.subplot(1,4,1)
plot_image(im, 'Input noisy image')
i = 2
for sz in [3,7,11]:
    im1 = im.filter(ImageFilter.MedianFilter(size=sz))
    plt.subplot(1,4,i), plot_image(im1, 'Output (Filter size=' + str(sz) + ')', 10)
    i += 1
plt.tight_layout()
plt.show()

中值滤波器
从以上输出结果可以看出,与平均滤波器相比,中值滤波器产生的模糊性较小,但是对于较大尺寸的中值滤波器核,它会在输出图像中导致较多纹理损失。

小结

噪声是干扰图像正常分析和处理的一个重要因素,一幅图像在实际应用中可能存在各种各样的噪声,噪声可能在拍摄中产生,也可能在传输过程中产生。在本节中,我们学习了几种常见的线性滤波器包括均值模糊和高斯模糊,以及非线性滤波器中值滤波器,并将这些滤波器用于图像降噪,从而提高图像质量,便于后续进行处理与分析。

系列链接

Python图像处理【1】图像与视频处理基础
Python图像处理【2】探索Python图像处理库
Python图像处理【3】Python图像处理库应用
Python图像处理【4】图像线性变换
Python图像处理【5】图像扭曲/逆扭曲
Python图像处理【6】通过哈希查找重复和类似的图像
Python图像处理【7】采样、卷积与离散傅里叶变换
Python图像处理【8】使用低通滤波器模糊图像
Python图像处理【9】使用高通滤波器执行边缘检测
Python图像处理【10】基于离散余弦变换的图像压缩
Python图像处理【11】利用反卷积执行图像去模糊
Python图像处理【12】基于小波变换执行图像去噪

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

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

相关文章

MAXENT模型的生物多样性教程

详情点击链接&#xff1a;基于MAXENT模型的生物多样性生境模拟与保护优先区甄选、自然保护区布局优化及未来气候变化下评估中的应用及论文写作 一&#xff1a;生物多样性保护格局与自然保护区格局优化 1.我国生物多样性格局与分布&#xff1b; 2.我国自然保护区格局与分布&…

Emacs之改造搜索文件fd-dired(基于fd命令)(一百二十一)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

【【51单片机AD转换模块】】

代码是简单的&#xff0c;板子是坏的&#xff0c;电阻是识别不出来的 main.c #include <REGX52.H> #include "delay.h" #include "LCD1602.h" #include "XPT2046.h"unsigned int ADValue;void main(void) {LCD_Init();LCD_ShowString(1,1…

format格式化输出语法详解

hello&#xff0c;这里是Token_w的文章&#xff0c;主要讲解python的基础学习&#xff0c;希望对大家有所帮助 整理不易&#xff0c;感觉还不错的可以点赞收藏评论支持&#xff0c;感谢&#xff01; 使用 % 操作符对各种类型的数据进行格式化输出&#xff0c;这是早期 Python提…

文档、视频、图片上传(点击、拖拽、批量导入)要‍‍‍‍怎么实现?!

文章目录 Excel上传和图片视频上传Excel上传页面中的使用图片和视频上传的错误提醒以及逻辑处理上传进度处理 Excel上传和图片视频上传 Excel上传 excel的上传其实分为两步&#xff1a; 1、下载excel模板 2、上传excel模板 在项目中涉及到excel的业务&#xff0c;基本上都…

Neo4j

存储结构 参考&#xff1a; 《图数据库&#xff08;第二版&#xff09;》 https://www.jianshu.com/p/94c1166eb400 https://blog.csdn.net/sinat_32336967/article/details/103348528 更新日期&#xff1a;2022-8-18 Neo4j版本&#xff1a;4.4 类型ID长度&#xff08;bit&…

使用Ensp配置DHCP协议

如何使用Ensp配置DHCP协议&#xff0c;为PC自动分配IP地址 什么是DHCP&#xff1f; Dynamic Host Configuration Protocol&#xff0c;动态主机配置协议&#xff0c;简单理解为自动分配IP地址&#xff0c;有了这个协议就不用手动配置IP地址了&#xff0c;如图 思路 给路由…

Monkey日志分析

1. Monkey日志详解 Monkey日志由以下几部分组成&#xff1a; 测试命令信息 随机种子seed、运行次数、可运行应用列表、各事件百分比。 App切换和Activity跳转 可以看到切换到了哪个App&#xff0c;从哪个Activity跳转到了哪个Activity&#xff0c;如果发生了异常&#xff0c…

JVM详解(超详细)

目录 JVM 的简介 JVM 执行流程 JVM 运行时数据区 由五部分组成 JVM 的类加载机制 类加载的过程(五个) 双亲委派模型 类加载器 双亲委派模型的优点 JVM 中的垃圾回收策略 GC GC 中主要分成两个阶段 死亡对象的判断算法 引用计数算法 可达性分析算法 垃圾回收算…

Mac m1 下eclipse下载及jdk环境变量配置

一、安装eclipse 1、下载eclipse Eclipse downloads - Select a mirror | The Eclipse Foundation 此版本为m1芯片适用版本 2、下载后下一步安装即可 安装成功后&#xff0c;可以看到图标&#xff1a; 二、安装jdk 1、下载jdk 下载此版本即可&#xff0c;下载完成之后一直…

Linux系统中的SQL语句

本节主要学习&#xff0c;SQL语句的语句类型&#xff0c;数据库操作&#xff0c;数据表操作&#xff0c;和数据操作等。 文章目录 一、SQL语句类型 DDL DML DCL DQL 二、数据库操作 1.查看 2.创建 默认字符集 指定字符集 3.进入 4.删除 5.更改 库名称 字符集 6…

(十三)定时任务

以下内容来自 尚硅谷&#xff0c;写这一系列的文章&#xff0c;主要是为了方便后续自己的查看&#xff0c;不用带着个PDF找来找去的&#xff0c;太麻烦&#xff01; 第 13 章 定时任务 13.1 什么是定时任务 1、InfluxDB任务是一个定时执行的FLUX脚本&#xff0c;它先查询数据…

小程序创建

1&#xff0c;下载HBuilder X ;(3.8.7) HBuilderX-高效极客技巧 2,下载模板&#xff08;不选云服务的&#xff09;&#xff1b; 3&#xff0c;运行-运行到小程序模拟器&#xff1b; 4&#xff0c;安装小程序开发工具&#xff1b; 5&#xff0c;选择稳定版-windows64版&…

骆驼祥子思维导图

《骆驼祥子》简单介绍 《骆驼祥子》小说&#xff0c;以20世纪20年代的旧北京为背景。祥子所处的时代是北洋军阀统治的时代。今天我们就用ProcessOn 思维导图 来给大家解析这本名著。所有文章中的思维导图都可以到ProcessOn 模板社区获得。 1936年&#xff0c;老舍的一位山东大…

【雕爷学编程】Arduino动手做(93)--- 0.96寸OLED液晶屏模块5

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

Wonderful Sql

Wonderful Sql 一. 初识数据库 练习题 1.1 编写一条 CREATE TABLE 语句&#xff0c;用来创建一个包含表 1-A 中所列各项的表 Addressbook &#xff08;地址簿&#xff09;&#xff0c;并为 regist_no &#xff08;注册编号&#xff09;列设置主键约束 表1-A 表 Addressbook…

LeetCode64.Minimum-Path-Sum<最小路径和>

题目&#xff1a; 思路&#xff1a; 一开始使用的深度优先搜索,结果果然是超时了.好吧 是需要动态规划的. 和上次有一题有点像.(12条消息) LeetCode62.Unique-Paths&#xff1c;不同路径&#xff1e;_Eminste的博客-CSDN博客 将边缘初始化为数组原本的数.然后每次只能向下或…

#P1108. [NOIP2008提高组] 双栈排序

题目描述 Tom 最近在研究一个有趣的排序问题。如图所示&#xff0c;通过 22 个栈 S_1S1​ 和 S_2S2​&#xff0c;Tom 希望借助以下 44 种操作实现将输入序列升序排序。 操作 aa&#xff1a;将第一个元素压入栈 S_1S1​。 操作 bb&#xff1a;将 S_1S1​ 栈顶元素弹出至输出序…

13.5.3 【Linux】PAM 模块设置语法

PAM 借由一个与程序相同文件名的配置文件来进行一连串的认证分析需求。我们同样以passwd 这个指令的调用 PAM 来说明好了。 当你执行 passwd 后&#xff0c;这支程序调用 PAM 的流程是&#xff1a; 1. 使用者开始执行 /usr/bin/passwd 这支程序&#xff0c;并输入密码&#xf…