图像噪声、去噪基本方法合集(Python实现)
文章目录
- 前言
- 本文主要参考冈萨雷斯的数字图像处理 (第4版),介绍图片中一些常见的噪声形式和常用的去噪方法,并且给出相应滤波方法的实现代码。
- 一、噪声分类
- 1、高斯噪声
- 2、泊松噪声
- 3、椒盐噪声
- 4、瑞利噪声
- 5、爱尔兰(伽马)噪声
- 6、均匀噪声
- 二、去噪方法
- 1、均值滤波
- 1.1 算术平均滤波
- 1.2 几何均值滤波
- 1.3 谐波平均滤波
- 2、统计排序滤波
- 2.1 中值滤波
- 2.2 最大值和最小值滤波
- 2.3 中点滤波
- 2.4 修正阿尔法均值滤波
- 总结
- 参考文献:
前言
本文主要参考冈萨雷斯的数字图像处理 (第4版),介绍图片中一些常见的噪声形式和常用的去噪方法,并且给出相应滤波方法的实现代码。
如果要使用本文代码,建议在Jupyter Notebook环境下运行。
一、噪声分类
1、高斯噪声
指服从高斯分布(正态分布)的一类噪声,其产生的主要原因是由于相机在拍摄时视场较暗且亮度不均匀造成的,同时相机长时间工作使得温度过高也会引起高斯噪声,另外电路元器件白身噪声和互相影响也是造成高斯噪声的重要原因之一。
概率密度函数(PDF)如下:
初始图片:
注意加噪声时,不能直接将 noise+img,不然最终出来的是一片空白和零星几个噪点,原因在于cv2.imshow输入要求是 0-1 float 或者 0-255 int。
(1)错误显示:
(2)正确显示:
import cv2
import random
import numpy as np
img = cv2.imread('A.png')# 产生高斯随机数
noise = np.random.normal(0,50,size=img.size).reshape(img.shape[0],img.shape[1],img.shape[2])
# 加上噪声
img = img + noise
img = np.clip(img,0,255)
img = img/255 cv2.imshow('Gauss noise',img)
cv2.waitKey(0)
(3)高斯滤波
高斯滤波是一种线性平滑滤波,一般用于消除高斯噪声。对于每一个像素点的值,是由其本身和邻域内的其他像素值经过加权平均后得到。
二维高斯函数:
具体过程:
代码:使用cv2.GaussianBlur()
函数
注意高斯模糊半径不能为偶数
滤波结果:
2、泊松噪声
简言之就是符合泊松分布的噪声模型,又称散粒噪声。
使用**np.random.poisson()**函数
import cv2
import random
import numpy as np
img = cv2.imread('A.png')# 产生泊松噪声
noise = np.random.poisson(lam=20,size=img.shape).astype('uint8')# 加上噪声
img = img + noise
np.clip(img,0,255)
img = img/255cv2.imshow('Poisson noise',img)
cv2.waitKey(0)
λ值越大,噪声程度越深。
3、椒盐噪声
椒盐噪声又称为脉冲噪声,是在图像上随机出现黑色白色的像素,顾名思义就是椒盐噪声 = 椒噪声(值为0,黑色) + 盐噪声(值为255,白色)
直接上代码:
import cv2
import random
import numpy as np
img = cv2.imread('A.png')# 转化成向量
x = img.reshape(1,-1)
# 设置信噪比
SNR = 0.85
# 得到要加噪的像素数目
noise_num = x.size * (1-SNR)
# 得到需要加噪的像素值的位置
list = random.sample(range(0,x.size),int(noise_num))for i in list:if random.random() >= 0.5:x[0][i] = 0else:x[0][i] = 255
img1 = x.reshape(img.shape)cv2.imshow('salt&pepper noise',img1)
cv2.waitKey(0)
SNR越小,噪声越大。
4、瑞利噪声
一般是由由信道不理想引起的,它与信号的关系是相乘,信号在它在,信号不在他也就不在。
瑞利密度对倾斜形状直方图的建模非常有用。
概率密度函数(PDF)如下:
很多地方给出的瑞利分布是下面这个公式:
这两个公式其实是同一个公式,只需要做如下变量替换就得到和第一个公式相同的形式了。
在生成瑞利噪声的时候,其实采用的是**np.random.rayleigh()**
方法生成,而这个方法就是根据第二个公式来的,所以只需要指定1个参数,得到的分布和第一个公式相比本质是相同的。
代码:
import cv2
import random
import numpy as np
img = cv2.imread('A.png')# 产生瑞利噪声
sigma = 70.0
noise = np.random.rayleigh(sigma, size=img.shape)
# 可以试试下面这个效果
# noise = np.random.rayleigh(img, size=img.shape)# 加上噪声
img = img + noise
np.clip(img,0,255)
img = img/255cv2.imshow('Rayleigh noise',img)
cv2.waitKey(0)
print(img.shape)
5、爱尔兰(伽马)噪声
概率密度函数(PDF)如下:(b是一个正整数)
指数分布和卡方分布其实可以看成是伽马分布的特殊形式。
b = 1时:指数分布;
b =n/2,a = 1/2时:卡方分布。
代码:
noise = np.random.gamma(shape=10.0,scale=10.0,size=img.shape)
#其他部分同上
6、均匀噪声
概率密度函数(PDF)如下:
代码:
noise = np.random.uniform(50,100,img.shape)
#其他部分同上
二、去噪方法
1、均值滤波
1.1 算术平均滤波
import cv2
import random
import numpy as np
img = cv2.imread('A.png')# 产生高斯随机数
noise = np.random.normal(0,50,size=img.size).reshape(img.shape[0],img.shape[1],img.shape[2])
# 加上噪声
img = img + noise
img = np.clip(img,0,255)
img = img/255 # 算术平均滤波
img1 = np.transpose(img,(2,0,1)) #转换成[channel,H,W]形式
m = 3 #定义滤波核大小
n = 3
rec_img = np.zeros((img1.shape[0],img1.shape[1]-m+1,img1.shape[2]-n+1))
for channel in range(rec_img.shape[0]):for i in range(rec_img[channel].shape[0]):for j in range(rec_img[channel].shape[1]):rec_img[channel][i,j] = img1[channel][i:i+m,j:j+n].sum()/(m*n)
rec_img = np.transpose(rec_img,(1,2,0))cv2.imshow('average',rec_img)
cv2.waitKey(0)
具体过程可以配合下图理解
去噪效果:
1.2 几何均值滤波
import cv2
import random
import numpy as np
img = cv2.imread('A.png')# 产生高斯随机数
noise = np.random.normal(0,50,size=img.size).reshape(img.shape[0],img.shape[1],img.shape[2])
# 加上噪声
img = img + noise
img = np.clip(img,0,255)
img = img/255 # 几何均值滤波
img1 = np.transpose(img,(2,0,1)) #转换成[channel,H,W]形式
m = 3 #定义滤波核大小
n = 3
rec_img = np.zeros((img1.shape[0],img1.shape[1]-m+1,img1.shape[2]-n+1))
for channel in range(rec_img.shape[0]):for i in range(rec_img[channel].shape[0]):for j in range(rec_img[channel].shape[1]):rec_img[channel][i,j] = np.power(np.prod(img1[channel][i:i+m,j:j+n]),1/(m*n))
rec_img = np.transpose(rec_img,(1,2,0))cv2.imshow('average',rec_img)
cv2.waitKey(0)
去噪效果:
几何均值滤波对0值是非常敏感,缺陷也很明显,那就是当窗口内像素只要有一个值为0,则其计算得到的值就是0。
1.3 谐波平均滤波
rec_img[channel][i,j] = 1/(np.power(img1[channel][i:i+m,j:j+n],-1).sum())*(m*n)
# 其余部分同上
该方法既能处理盐粒噪声,又能处理类似于于高斯噪声的其他噪声,但是不能处理胡椒噪声。
### 1.4 ·
Q:滤波器的阶数。适用于降低或消除椒盐噪声。
注意:Q=0时。简化成算术平均滤波;Q=1,简化为谐波平均滤波。
代码:
import cv2
import random
import numpy as np
img = cv2.imread('A.png')#---------椒盐噪声----------
# 转化成向量
x = img.reshape(1,-1)
# 设置信噪比
SNR = 0.85
# 得到要加噪的像素数目
noise_num = x.size * (1-SNR)
# 得到需要加噪的像素值的位置
list = random.sample(range(0,x.size),int(noise_num))for i in list:if random.random() >= 0.5:x[0][i] = 0else:x[0][i] = 255
img = x.reshape(img.shape)
img = img/255
#--------------------------# 反谐波平均滤波
img1 = np.transpose(img,(2,0,1)) #转换成[channel,H,W]形式
m = 3 #定义滤波核大小
n = 3
Q = 0.1
rec_img = np.zeros((img1.shape[0],img1.shape[1]-m+1,img1.shape[2]-n+1))
for channel in range(rec_img.shape[0]):for i in range(rec_img[channel].shape[0]):for j in range(rec_img[channel].shape[1]):rec_img[channel][i,j] = ((np.power(img1[channel][i:i+m,j:j+n],Q+1)).sum())/((np.power(img1[channel][i:i+m,j:j+n],Q)).sum())
rec_img = np.transpose(rec_img,(1,2,0))cv2.imshow('average',rec_img)
cv2.waitKey(0)
加噪图:
去噪效果:
注意:Q的值不要过大,否则就会变成下图(Q=2时):
2、统计排序滤波
2.1 中值滤波
我们非常熟悉的一种去噪方法,它是用像素邻域中的灰度中值来代替像素的值。
代码:
import cv2
import random
import numpy as np
img = cv2.imread('A.png')# 产生高斯随机数
noise = np.random.normal(0,50,size=img.size).reshape(img.shape[0],img.shape[1],img.shape[2])
# 加上噪声
img = img + noise
img = np.clip(img,0,255)
img = img/255 # 中值滤波
img1 = np.transpose(img,(2,0,1)) #转换成[channel,H,W]形式
m = 3 #定义滤波核大小
n = 3
rec_img = np.zeros((img1.shape[0],img1.shape[1]-m+1,img1.shape[2]-n+1))
for channel in range(rec_img.shape[0]):for i in range(rec_img[channel].shape[0]):for j in range(rec_img[channel].shape[1]):rec_img[channel][i,j] = np.median(img1[channel][i:i+m,j:j+n])
rec_img = np.transpose(rec_img,(1,2,0))cv2.imshow('median',rec_img)
cv2.waitKey(0)
去噪效果:
或者直接使用cv2.medianBlur()函数
import cv2
import random
import numpy as np
img = cv2.imread('A.png')# 产生高斯随机数
noise = np.random.normal(0,50,size=img.size).reshape(img.shape[0],img.shape[1],img.shape[2])
# 加上噪声
img = img + noise
img = np.clip(img,0,255)
img = np.uint8(img)# 中值滤波
rec_img = cv2.medianBlur(img,3)cv2.imshow('median',rec_img)
cv2.waitKey(0)
2.2 最大值和最小值滤波
主要使用到:np.amax() 和 np.amin()两个函数
2.3 中点滤波
代码:
rec_img[channel][i,j] = (np.amax(img1[channel][i:i+m,j:j+n]) + np.amin(img1[channel][i:i+m,j:j+n]))/2
对高斯噪声处理的滤波效果:
2.4 修正阿尔法均值滤波
处理方法:在邻域 S x y S_{xy} Sxy 内删除 d / 2 d/2 d/2个最低灰度值和 d / 2 d/2 d/2个最高灰度值。 g R ( r , c ) g_{R}(r,c) gR(r,c)表示 S x y S_{xy} Sxy 中剩下的 m n − d mn-d mn−d个像素。
d = 0 d=0 d=0: 变成算术平均滤波
d = m n − 1 d=mn-1 d=mn−1:中值滤波
代码:
import cv2
import random
import numpy as np
img = cv2.imread('A.png')# 产生高斯随机数
noise = np.random.normal(0,50,size=img.size).reshape(img.shape[0],img.shape[1],img.shape[2])
# 加上噪声
img = img + noise
img = np.clip(img,0,255)
img = img/255 # 修正阿尔法均值滤波
img1 = np.transpose(img,(2,0,1)) #转换成[channel,H,W]形式
m = 3 #定义滤波核大小
n = 3
d = 4 #d取偶数
rec_img = np.zeros((img1.shape[0],img1.shape[1]-m+1,img1.shape[2]-n+1))
for channel in range(rec_img.shape[0]):for i in range(rec_img[channel].shape[0]):for j in range(rec_img[channel].shape[1]):img2 = np.sort(np.ravel(img1[channel][i:i+m,j:j+n])) #np.ravel():多维数组变成一维数组rec_img[channel][i,j] = (img2[int(d/2):-int(d/2)].sum())*(1/(m*n-d))
rec_img = np.transpose(rec_img,(1,2,0))cv2.imshow('alpha average',rec_img)
cv2.waitKey(0)
去噪效果:
总结
介绍的主要是一些非常基础的滤波器,滤波功能只能针对某一类噪声有作用,其滤波效果总的来说并不是很好,对于真实环境中纷繁复杂的噪声类型,需要采用更合适、更好的滤波方法,但是这些方法或多或少都是基于这些基本方法去不断优化和改善的。后面有时间再更新一些更强的去噪方法。
有些地方可能存在问题和不足,欢迎大家一起交流!
参考文献:
[1] 阮秋琦,阮宇智译;(美)拉斐尔·C.冈萨雷斯,理查德·E.伍兹.国外电子书与通信教材系列 数字图像处理 第4版[M].北京:电子工业出版社,2020
图像噪声、去噪基本方法合集(Python实现)相关推荐
- (小甲鱼python)集合笔记合集一 集合(上)总结 集合的简单用法 集合的各种方法合集:子、交、并、补、差、对称差集、超集
一.基础复习 集合与字典区别 集合中所有元素都是独一无二的,并且也是无序的. 集合具有唯一性.无序性.有限性 >>> type({}) #字典 <class 'dict'> ...
- 摸鱼方法合集(无需编程基础)
摸鱼方法合集(无需编程基础) 1.[摸鱼中国]抓鱼鸭(网页版) 2.伪装电脑升级界面 网页版(Windows&Mac) 软件版(Windows) 3.无意义活动生成器(Windows) 4.文 ...
- cookie和url参数获取的常规实用方法合集(ES6)
//获取某一个cookie的值 const getCookie = key => {var k = key, dc = document.cookie;if (dc.length > 0) ...
- 【PaddlePaddle系列】报错解决方法合集 (不定时更新)
[PaddlePaddle系列]报错解决方法合集 (不定时更新) 参考文章: (1)[PaddlePaddle系列]报错解决方法合集 (不定时更新) (2)https://www.cnblogs.co ...
- 前端表格导出为excel方法合集
前端表格导出为excel方法合集 近来遇到了前端表格保存为excel的需求,通过查阅多方资料,总结了3种方法,下面一一进行展示,有不正确的地方,望指正.主要包括两种导出方法--纯前端导出和前端接收后端 ...
- 2000-2020全要素生产率OP法+LP法+OLS和固定效应法三种方法合集含原始数据和计算过程Stata代码
2000-2020全要素生产率OP法+LP法+OLS和固定效应法三种方法合集含原始数据和计算过程Stata代码 1.时间:OP法:2008-2020年.LP法2000-2020年.OLS和固定效应法2 ...
- h5调用原生App的方法合集
h5调用原生App的方法合集 1.调用原生关闭函数 let u = navigator.userAgent let isAndroid = u.indexOf('Android') > -1 | ...
- python基础语法合集-Python基础语法合集.zip
[实例简介]精心整理的Python基础语法合集,变量,循环,输入输出等等都有,主要是知道概念和怎么用的 如果打开文件后有文字变成符号的,先把字体改为宋体就正常了 [实例截图] [核心代码] 目录 了解 ...
- unittest教程(2w字实例合集)——Python自动化测试一文入门
" 本文通过理论讲解+大量实例演示,全面介绍了unittest测试框架的使用方法,文章层层深入,环环相扣,建议按顺序阅读,如遇不清楚的地方可翻看上文注释部分,一般都会有详细标明,阅读过程中 ...
最新文章
- RocketMQ 基本概念
- Nginx 学习总结(2) —— 基本配置
- iOS中 HTTP/Socket/TCP/IP通信协议详解 韩俊强的博客
- 软件项目第一次Sprint评分表
- 【C语言练习】【指针】定义一个函数move,实现将长度为n、名为a的序列中,各元素依次顺序循环,右移m个位置
- 语法之知识点的改进(Func/Action)
- 连接数学和美学的--西奥多罗斯螺旋
- 怎样用bootsrapcol-md来实现四分屏_用会议平板提升会议效率,做好这两点
- CODE[VS] 1346 HelloWorld编译器
- windows进入mysql改user_mysql:Windows修改MySQL数据库密码(修改或忘记密码)
- 2021年中国电力线通信(PLC)市场趋势报告、技术动态创新及2027年市场预测
- 操作argc, argv的经典写法
- 周末计划-20171028
- VS code gopls requires a module at the root of your workspace
- 电商数据分析Excel案例
- jsp在校大学生助学贷款管理系统
- 前端新手小白必看--最全静态网页模板网站
- html js创建表格,javascript创建表格方式详解
- CPU 流水线的前世今生
- 408计算机考研后期规划-10月起
热门文章
- kernel: SLUB: Unable to allocate memory on node -1 (gfp=0x20)
- java日志框架详解
- C语言位运算的高级应用(尤其适合单片机和嵌入式编程)
- 汽车钥匙改装成手机蓝牙无钥匙进入一键启动 ,汽车无钥匙进入为何不能集成到手机?蓝牙无钥匙进入一键启动解决方案
- Latex使用本地字体
- C语言中 *x++ (*x)++ ++*x *++x的区别
- c语言输出漏斗图形7层,ECharts 教程 漏斗图属性与实例介绍 - 闪电教程JSRUN
- NDCG(归一化折损累计增益)
- MySQL 慢查询日志介绍
- Mac 硬件驱动(.kext)安装方法