一、简介(主要特点 + 适用场景 + 去噪方法)
噪声类型 | 类型属性 | 分布模型 | 主要特点 | 适用场景 | 去噪方法 |
---|---|---|---|---|---|
均匀噪声 | 加性噪声 | 均匀分布 | 灰度扰动在指定范围内均匀分布,模拟广义背景噪声 | 图像增强、噪声容忍测试、合成训练样本 | 线性滤波(如均值滤波、GaussianBlur) |
高斯噪声 | 加性噪声 | 正态分布 | 灰度值围绕均值上下波动,模拟传感器热噪声和读取误差 | 图像去噪、滤波算法验证(如高斯滤波、双边滤波) | 高斯滤波、双边滤波、非局部均值(NLM)、小波去噪 |
椒盐噪声 | 冲击噪声 | 二值随机分布 | 像素值被随机替换为极大值或极小值,呈现黑白散点 | 通信故障模拟、中值滤波、图像鲁棒性测试 | 中值滤波、自适应中值滤波、统计修复方法 中 |
泊松噪声 | 加性噪声 | 泊松分布 | 灰度值相关噪声,低亮度区域影响更明显,反映量子统计波动 | 医学成像 、天文成像、低照度图像增强 | 方差稳定变换(如Anscombe变换)+高斯滤波、小波域去噪 |
瑞利噪声 | 加性噪声 | 瑞利分布 | 单侧偏态分布,偏离高斯,常因散射引起亮度波动 | 雷达图像、超声波图像、声纳成像 | Wiener滤波、小波阈值去噪、自适应滤波器 |
伽马噪声 | 乘性噪声 | 伽马分布 | 与图像灰度值相关的乘性干扰,影响图像对比度 | 激光雷达、SAR图像、对比度自适应处理 | 对数变换 + 滤波、指数滤波器 |
斑点噪声 | 乘性噪声 | 高斯乘性扰动 | 图像值与扰动相乘,形成纹理状 " 麻点 " 干扰,非均匀噪声 | 相干成像系统(如B超、干涉图)、图像结构保持型降噪 | Lee滤波、Kuan滤波、Frost滤波、双边滤波、总变差(TV) |
脉冲噪声 | 冲击噪声 | 非固定概率分布 | 灰度值局部突变,位置与强度随机,可模拟传感器故障 | 鲁棒性降噪算法测试、异常检测模型训练 | 基于排序的滤波(如最大/最小滤波、α中值滤波)、鲁棒统计去噪 |
1. 加性噪声 + 乘性噪声 + 冲击噪声
加性噪声(Additive Noise)、乘性噪声(Multiplicative Noise)、冲击噪声(Impulse Noise)是图像处理中常见的三类噪声类型,各自具有不同的物理来源、数学建模方式和视觉表现。
类别 | 数学形式 | 噪声特征 |
---|---|---|
加性噪声 | I_noisy = I_clean + N(x,y) | 与原图像无关,直接加在像素值上,通常为零均值 |
乘性噪声 | I_noisy = I_clean × N(x,y) | 与图像强度有关,噪声值随图像灰度变化而变化 |
冲击噪声 | 个别像素被突变值替代 | 少量像素被替换为极大或极小值,呈现为" 亮点 “或” 暗点 " |
使用建议:
- 对图像增强类方法,建议以加性噪声为主;
- 对保持边缘结构敏感的算法,建议测试乘性斑点噪声;
- 对鲁棒性要求较高的去噪算法,冲击噪声是必要测试维度。
2. 椒盐噪声是脉冲噪声的一种特殊形式
- 1. 定义区别
- 脉冲噪声(Impulse Noise):指图像中部分像素的灰度值被随机替换为任意值,这些值可分布在整个灰度范围(如0~255)内,也可限制在某一区间。
- 椒盐噪声(Salt-and-Pepper Noise):脉冲噪声的一种特殊形式,其噪声值固定为两个极端值,通常是最小值0(黑)和最大值255(白)。
- 2. 表现形式
- 脉冲噪声:在图像中表现为亮度不一的随机点状干扰,可能是亮点,也可能是暗点,甚至呈灰阶中值。
- 椒盐噪声:在图像中表现为清晰的黑白点杂散分布,形如撒上“盐粒”和“胡椒粒”。
- 3. 噪声灰度分布
- 脉冲噪声:灰度值分布可以是均匀、正态或自定义分布,随机性强。
- 椒盐噪声:灰度值仅取两个固定值(0和255),呈二值分布。
- 4. 滤波难度与处理方式
- 脉冲噪声:由于灰度变化范围大,不易被常规滤波器完全去除,处理中等偏难。
- 椒盐噪声:由于噪点灰度固定,中值滤波器等方法处理效果良好,处理相对简单。
- 5. 应用场景
- 脉冲噪声:模拟复杂干扰环境,测试鲁棒性、开发自适应滤波器
- 椒盐噪声:教学演示、中值滤波验证、基础算法测试
二、原理详解
1. 均匀噪声(Uniform Noise)
均匀噪声(Uniform Noise)是一种常见的随机噪声,其核心特性在于噪声值在指定范围内服从均匀分布,即该范围内每个值出现的概率均相同。
- 特点
概率分布均匀
:噪声值在设定的区间内(例如 [−a,a])均匀分布,每个值出现的概率相同,没有集中趋势。噪声幅度控制
:通过设置噪声强度参数(如 intensity),可以直接控制噪声对图像亮度的扰动范围。数值越大,噪声所引入的亮度变化也越大,从而影响图像整体的视觉效果。噪声覆盖范围
:通过调整噪声覆盖率参数(如 noise ratio),可以灵活地控制图像中有多少比例的像素会受到噪声的影响。这可以用于模拟局部干扰(noise ratio <1)或全图噪声(noise ratio =1)的情况。- 加性噪声模型:在图像处理中,均匀噪声通常通过在每个像素上添加一个在固定范围内随机生成的值来实现。
- 应用
- 图像模拟:常用于模拟传感器中的随机噪声或数据采集中的误差,为图像降质测试和数据增强提供多样化的噪声模型。。
- 算法测试:由于均匀噪声在整个图像上均匀分布,它被广泛用于验证图像处理算法(如去噪、滤波等)的鲁棒性和适应性,帮助评估算法在不同噪声环境下的表现。
- 局限性:尽管均匀噪声易于实现且参数可控,但在实际应用中,很多自然噪声(例如感光元件产生的噪声)往往更符合正态分布(高斯噪声)的特性。因此,在某些需要更真实噪声模拟的场景下,均匀噪声可能不如其他噪声模型(如高斯噪声)贴合实际情况。
综上所述,均匀噪声作为一种基本的噪声模型,虽然在物理意义上可能不如高斯噪声等贴合真实情况,但其简单和均匀的特点使得它在模拟和测试各种图像处理算法时具有一定的应用价值。
2. 高斯噪声(Gaussian Noise)
高斯噪声(Gaussian Noise)是一种常见的随机噪声,其噪声值服从正态分布,即高斯分布。
高斯噪声的数学模型如下,概率密度函数:
P ( x ) = 1 2 π σ 2 exp ( − ( x − μ ) 2 2 σ 2 ) P(x) = \frac{1}{\sqrt{2\pi\sigma^2}} \exp\left(-\frac{(x-\mu)^2}{2\sigma^2}\right) P(x)=2πσ21exp(−2σ2(x−μ)2)
其中:
- x 表示噪声值
- μ 表示均值(期望值)
- σ 表示标准差(σ2 为方差),噪声以图像中心值为对称随机波动。
- 特点:
概率分布呈正态分布
:高斯噪声的分布呈现钟形曲线(Bell Curve),大部分噪声值集中在均值附近,离均值越远的噪声出现的概率越低。均值参数影响
:
- 均值为零:通常在图像处理中设定 μ 为零,使噪声在正负两个方向上均匀分布。这样添加噪声后,图像的整体亮度不会产生系统性偏移,仅引入随机波动。
- 均值不为零:如果 μ 取其他值,则噪声会引入一个固定的偏移。正的 μ 会使图像整体变亮,而负的 μ 会使图像整体变暗。这种偏移会改变图像的亮度特性,常用于模拟传感器的系统性误差或其他场景下的亮度偏移。
噪声强度可控
:
- σ 值越大,噪声值的分布越宽,图像中像素值的扰动越明显,噪声效果更强;
- σ 值较小,则噪声集中在均值附近,图像受到的干扰较弱。
- 加性噪声模型:在图像处理中,高斯噪声一般作为加性噪声添加到原始图像上,即每个像素值
I(x,y)
都会被一个从高斯分布中随机抽取的值n
所扰动,得到新的像素值I'(x,y)=I(x,y)+n,其中 n 服从 N(μ, σ²)
。- 应用
- 自然噪声模拟:高斯噪声常用于模拟自然界中电子设备产生的噪声,如相机传感器的热噪声或电路噪声,尤其是在低光照条件下,这些噪声往往近似服从正态分布。
- 算法测试:由于其数学特性和良好的统计特性,高斯噪声被广泛应用于图像降噪、滤波算法的测试以及数据增强,为算法评估提供标准噪声模型。
- 局限性:尽管高斯噪声模型具有数学简单、易于分析的优点,但在某些实际场景中,噪声可能不仅仅表现为单一的正态分布。例如,在某些传输或采集环境下,噪声可能混合了椒盐噪声、泊松噪声或其他类型的噪声。因此,实际应用时可能需要综合考虑多种噪声模型以更真实地模拟环境噪声。
综上所述,高斯噪声由于其数学性质和实际物理噪声的相似性,在图像和信号处理中占有重要地位,是模拟和研究噪声处理算法时常用的噪声模型。
3. 椒盐噪声(Salt-and-Pepper Noise)
4. 泊松噪声(Poisson Noise)
泊松噪声(Poisson Noise) 是一种随机噪声,通常在低光照、低信噪比环境中出现,其噪声值符合泊松分布(Poisson Distribution),这使得它在图像处理、医学成像、天文观测等领域有着广泛应用。泊松噪声的出现是由于光子或电子的离散性,常被称为量子噪声(Shot Noise)。
泊松噪声的概率质量函数(PMF)可表示为:
P ( X = k ) = λ k e − λ k ! P(X = k) = \frac{\lambda^k e^{-\lambda}}{k!} P(X=k)=k!λke−λ
其中
- X 表示服从泊松分布的随机变量;
- p(X=k) 表示某事件发生k次的概率;
- k 表示噪声值,表示事件发生的次数(例如,光子计数);
- λ 表示泊松分布的均值(同时也是方差 λ = σ2),表示单位时间内发生的平均事件数;
- 泊松分布是一种离散概率分布,这意味着它给出离散(即可数)结果的概率。对于泊松分布,离散结果是事件发生的次数,用 k 表示。
- 泊松分布可以直观地表示为概率质量函数图。概率质量函数是描述离散概率分布的函数。
- 当 λ 较低时,分布在峰值的右侧比左侧长得多(即,它严重右偏)。
- 随着 λ 的增加,分布看起来越来越类似于正态分布。事实上,当 λ 为 10 或更大时,正态分布可以很好地近似泊松分布。
泊松噪声的关键特性是其均值和方差相等,均为 λ。
(1)噪声的强度直接与图像的亮度值相等 —— 举个例子,如果一个像素的亮度为 λ=100,则其噪声的均值和方差也是100。
(2)噪声的强度与图像的亮度值(信号强度)成正比 —— 在低亮度区域,由于亮度较低,噪声的相对比例较高;而在高亮度区域,尽管噪声的绝对值较大,但由于亮度也相应增大,噪声在视觉上相对较弱。
(3)噪声在低亮度区域表现为较强的相对噪声,而在高亮度区域噪声则相对较弱。
- 低亮度区域:噪声虽然相对较小(绝对值低),但由于信号(亮度)较小,噪声的相对影响(信噪比)较大。这使得低亮度区域的噪声在人眼和计算机视觉算法中显得尤为突出。
- 高亮度区域:虽然噪声的绝对强度较大,但由于图像亮度的增加,噪声相对于信号的影响变小,因此在这些区域噪声的视觉效果和影响较为平缓。
像素强度 | 方差(泊松噪声) | 噪声相对比例 |
---|---|---|
10 | ≈10 | 高(相对波动大) |
100 | ≈100 | 中(波动可感) |
1000 | ≈1000 | 低(波动不明显) |
- 特点:
- 信号依赖性(乘性噪声:将图像的信号值成比例缩放)
- 例如,在夜间拍摄时,由于光子数较少(λ 小),噪声较小;而在强光环境下(λ 大),噪声反而更明显。
- 不可控性:泊松噪声的强度随信号本身变化,不能像高斯噪声那样通过直接设置标准差来调整噪声的幅度。
- 无负值噪声:由于泊松噪声源于光子计数,噪声不会导致像素值变为负数,所有像素值始终为非负整数。
- 加性噪声模型(噪声幅度随信号强度变化,但仍是加性):在图像处理中,泊松噪声通过将一个基于泊松分布的随机值添加到每个像素上来模拟。设原始图像的像素值为
I(x,y)
,则添加泊松噪声后的像素值I'(x,y)=I(x,y)+k, k∼Poisson(I(x,y))
。其中k
是一个从泊松分布中随机抽取的噪声值,均值为原像素值I(x,y)
。- 应用
- 医学影像 & 天文图像:数字相机和医学成像设备(如 X 光、CT 扫描或 MRI 图像)中,光子探测器的测量误差符合泊松分布,泊松噪声是光电传感器的主要噪声源之一,因为它们依赖于光子计数。
- 低光摄影:在低光或夜间环境下,摄像头传感器接收到的光子数量较少,信号较弱,导致泊松噪声显著。
- 图像去噪 & 计算摄影:由于泊松噪声的信号相关特性,许多去噪算法(如 Anscombe 变换、非局部均值滤波)会特别针对泊松噪声进行优化。
- 局限性
- 不适用于所有类型的噪声:在高光照环境下,泊松噪声可能不是唯一的主导噪声,其他噪声(如高斯噪声、量化噪声)可能也会对图像质量产生影响。
- 在高信号强度下趋近高斯分布:当信号强度较大时,泊松噪声的分布逐渐接近高斯分布,因此在高亮度场景中,泊松噪声有时可用高斯噪声来近似。
- 非线性处理难度较高:由于泊松噪声的非加性特征,标准的线性滤波(如均值滤波、高斯滤波)在去除泊松噪声时效果有限。
泊松噪声是一种信号相关的噪声,通常出现在低光照环境或光电成像系统中。它的特点是噪声强度随信号强度变化,亮部区域噪声较大,而暗部区域噪声较小。由于这一特性,它在图像处理、医学成像和天文摄影等领域有广泛应用,但去噪处理也更具挑战性。
5. 瑞利噪声(Rayleigh Noise)
6. 伽马噪声(Gamma Noise)
7. 斑点噪声(Speckle Noise)
8. 脉冲噪声(Impulse Noise)
二、模拟噪声的使用建议
在图像处理任务中,模拟噪声的目标并非单纯制造干扰,而是尽可能还原真实场景中的噪声特征,从而检验算法的健壮性、适应性与容错能力。以下为具体使用建议:
1. 以最终目标图像的噪声特性为依据
模拟加噪时,首要考虑的是目标场景下的实际噪声类型。应优先分析以下因素:
- 图像来源:如工业相机、医疗影像、夜间监控、遥感图像等。
- 噪声来源:感光元件噪声、传输损耗、压缩伪影、光照不足等。
- 噪声表现形式:是否为固定灰度值(如椒盐)、是否依赖图像亮度(如乘性斑点噪声)、是否强度较低但分布广泛(如高斯)。
2. 明确目标图像的真实噪声类型
任务类型 | 推荐噪声模型 | 原因说明 |
---|---|---|
图像去噪模型训练 | 高斯、椒盐、斑点、泊松 | 覆盖典型加性、乘性和离散性噪声 |
图像增强/超分辨率 | 高斯、泊松 | 常见于图像采集或缩放过程中的统计干扰 |
图像修复/补全 | 脉冲、椒盐 | 适用于模拟图像中像素缺失或突发错误 |
医疗影像算法 | 斑点、伽马、瑞利 | 模拟传感器不稳定性与结构纹理噪声 |
夜间/低光图像优化 | 高斯+斑点(乘性) | 近似真实噪声分布,提高模拟真实性 |
遥感与卫星图像处理 | 瑞利、伽马、脉冲 | 模拟信号衰减与远距离采集干扰 |
3. 复合加噪 + 加噪顺序
- 现实图像往往不是单一噪声类型,建议使用复合加噪机制。
- 不同类型的噪声具有不同的统计分布特性,如果先后顺序不合理,可能会掩盖前一类噪声的特征或放大其影响。
加噪顺序对结果的影响:
先加高斯噪声再加椒盐噪声
:图像中既包含连续分布的微弱噪声(模拟传感器误差),又包含突变性的点状噪声(模拟传输错误或采样故障)。这种顺序通常更贴近真实图像受噪声干扰的过程,有利于测试算法的整体稳健性。先加椒盐噪声再加高斯噪声
:高斯噪声会在椒盐噪声的黑白噪点周围引入额外扰动,使原本易于检测的极端值边缘模糊,从而增加检测与修复的难度,导致中值滤波等方法效果下降。不同应用领域的加噪建议:
- 若目的在于
测试基础鲁棒性
:建议单一噪声或低复杂度噪声先添加。- 若目的是测试算法极限性能或模拟复杂场景:应从基础噪声(如高斯)逐步叠加结构性更强的噪声(如椒盐、斑点),并保留中间过程图以支持分步评估。
真实场景的噪声产生流程(举例):
- 传感器采集(模拟噪声+量化误差)后传输(信道错误):
高斯/泊松 → 椒盐/脉冲
- 图像压缩后重建出现块状伪影和纹理失真,再叠加系统噪声:
块噪声或斑点 → 高斯
- 天文图像长时间曝光中的复合干扰:
泊松 → 斑点 → 高斯
3. 合理控制噪声强度与分布参数
模拟图像噪声时,参数选择对最终效果具有决定性影响。噪声强度(如标准差、比例、幅值范围)和分布形态(如均匀、高斯、瑞利等)应根据实验目标动态调整,以确保模拟结果具备多样性、可控性和广泛适用性。
为实现系统性与渐进性控制,建议采用以下策略:
渐进式强度控制
:优先从轻度噪声入手,逐步过渡至中等或重度噪声,便于分阶段测试算法性能边界。- 单位标准化处理:对高动态范围图像(如HDR、16位或float32格式),应统一噪声幅度的单位尺度。例如可将噪声标准差或最大振幅以归一化形式(如0~1范围)表示,确保参数含义一致,便于比较。
- 动态范围自适应调节:对16位整型或浮点型图像,应根据其动态范围灵活调整噪声幅度,避免因直接使用8位参数造成噪声过弱(无测试意义)或过强(饱和、剪切、失真等问题)。
- 边缘案例覆盖:推荐在关键实验阶段引入极端参数值(如极低比例的椒盐噪声或极高标准差的高斯噪声),以测试算法在恶劣条件下的稳定性和恢复能力。
三、项目实战(2D图像)
随机数生成:numpy.random()模块提供了各种函数
"""######################################################################
numpy.random 模块提供了各种随机数生成函数,可用于各种随机模拟、数据增强、机器学习。
1. 基本随机数生成
rand(): 生成 [0,1) 区间的均匀分布随机数(浮点数)。
randn(): 生成标准正态分布(均值 0,标准差 1)的随机数(浮点数)。
randint(low, high, size): 生成 [low, high) 范围内的随机数(整数)。
random(): 生成 [0,1) 之间的随机数(浮点数)。
choice(a, size, replace, p): 从数组 a 选择随机元素,可指定是否放回。
shuffle(x): 原地打乱数组 x。
permutation(x): 返回 x 的一个随机排列,但不会改变原数组。
2. 均匀分布 uniform(low, high, size): 生成 [low, high) 范围内符合均匀分布的随机数(浮点数)。
3. 正态分布 normal(loc, scale, size): 生成符合正态(高斯)分布的随机数,loc 为均值,scale 为标准差。
4. 泊松分布 poisson(): 生成符合泊松分布的随机数(整数)。
5. 指数分布 exponential(): 生成符合指数分布的随机数(浮点数)。
6. 伽马分布 gamma(): 生成符合伽马分布的随机数(浮点数)。
7. Beta 分布 beta(): 生成符合 Beta 分布的随机数(浮点数)。
8. 瑞利分布 rayleigh(): 生成符合瑞利分布的随机数(浮点数)。
9. 二项分布 binomial(): 生成符合二项分布的随机数(整数)。
10. 多项分布 multinomial(): 生成符合多项分布的随机数(整数)。
11. 卡方分布 chisquare(): 生成符合卡方分布的随机数(浮点数)。
######################################################################"""
1. 可视化噪声图像 + 噪声分布图(Hist)
import numpy as np
import matplotlib.pyplot as plt
# 初始化图像和总图
fig = plt.figure(figsize=(20, 6)) # 控制整图大小
index = 1 # 子图索引
# 函数封装绘图逻辑
def plot_noise(image, noise, noisy, title):
global index
plt.subplot(2, 8, index)
plt.imshow(noisy, cmap='gray')
plt.title(title)
plt.axis('off')
index += 1
plt.subplot(2, 8, index)
plt.hist(noise.ravel(), bins=100)
plt.title("Noise Dist")
plt.tight_layout()
index += 1
# 1. Uniform Noise
image = np.zeros((256, 256), dtype=np.uint8)
noise = np.random.uniform(-50, 50, image.shape)
noisy = np.clip(image + noise, 0, 255).astype(np.uint8)
plot_noise(image, noise, noisy, "Uniform Noise")
# 2. Gaussian Noise
image = np.zeros((256, 256), dtype=np.uint8)
noise = np.random.normal(0, 25, image.shape)
noisy = np.clip(image + noise, 0, 255).astype(np.uint8)
plot_noise(image, noise, noisy, "Gaussian Noise")
# 3. Salt-and-Pepper Noise
image = np.zeros((256, 256), dtype=np.uint8)
prob = 0.05
rnd = np.random.rand(*image.shape)
noisy = image.copy()
noisy[rnd < prob/2] = 0
noisy[rnd > 1 - prob/2] = 255
noise = rnd
plot_noise(image, noise, noisy, "Salt-Pepper Noise")
# 4. Poisson Noise
image = np.full((256, 256), 128, dtype=np.uint8)
noise = np.random.poisson(image / 255.0 * 10) / 10 * 255 - image
noisy = np.clip(image + noise, 0, 255).astype(np.uint8)
plot_noise(image, noise, noisy, "Poisson Noise")
# 5. Rayleigh Noise
image = np.zeros((256, 256), dtype=np.uint8)
noise = np.random.rayleigh(scale=25, size=image.shape)
noisy = np.clip(image + noise, 0, 255).astype(np.uint8)
plot_noise(image, noise, noisy, "Rayleigh Noise")
# 6. Gamma Noise
image = np.zeros((256, 256), dtype=np.uint8)
shape_k = 2.0
scale_theta = 20.0
noise = np.random.gamma(shape_k, scale_theta, image.shape)
noisy = np.clip(image + noise, 0, 255).astype(np.uint8)
plot_noise(image, noise, noisy, "Gamma Noise")
# 7. Speckle Noise
image = np.full((256, 256), 128, dtype=np.uint8)
noise = np.random.normal(0, 0.1, image.shape)
noisy = np.clip(image + image * noise, 0, 255).astype(np.uint8)
plot_noise(image, noise, noisy, "Speckle Noise")
# 8. Impulse Noise
image = np.zeros((256, 256), dtype=np.uint8)
prob = 0.01
noisy = image.copy()
mask = np.random.rand(*image.shape) < prob
noisy[mask] = 255
noise = mask.astype(np.uint8)
plot_noise(image, noise, noisy, "Impulse Noise")
plt.show()
# import numpy as np
# import matplotlib.pyplot as plt
#
# # 1. 均匀噪声(Uniform Noise)
# image = np.zeros((256,256),dtype=np.uint8)
# noise = np.random.uniform(-50,50,image.shape)
# noisy = np.clip(image + noise,0,255).astype(np.uint8)
#
# plt.subplot(1,2,1); plt.imshow(noisy,cmap='gray'); plt.title("Uniform Noise")
# plt.subplot(1,2,2); plt.hist(noise.ravel(),bins=100); plt.title("Noise Dist"); plt.tight_layout()
# plt.show()
# ##################################################################################################
#
# import numpy as np
# import matplotlib.pyplot as plt
#
# # 2. 高斯噪声(Gaussian Noise)
# image = np.zeros((256,256),dtype=np.uint8)
# noise = np.random.normal(0,25,image.shape)
# noisy = np.clip(image + noise,0,255).astype(np.uint8)
#
# plt.subplot(1,2,1); plt.imshow(noisy,cmap='gray'); plt.title("Gaussian Noise")
# plt.subplot(1,2,2); plt.hist(noise.ravel(),bins=100); plt.title("Noise Dist"); plt.tight_layout()
# plt.show()
# ##################################################################################################
#
# import numpy as np
# import matplotlib.pyplot as plt
#
# # 3. 椒盐噪声(Salt-and-Pepper Noise)
# image = np.zeros((256,256),dtype=np.uint8)
# prob = 0.05
# rnd = np.random.rand(*image.shape)
# noisy = image.copy()
# noisy[rnd < prob/2] = 0 # pepper
# noisy[rnd > 1-prob/2] = 255 # salt
# noise = rnd # 用rnd展示分布
#
# plt.subplot(1,2,1); plt.imshow(noisy,cmap='gray'); plt.title("Salt-Pepper Noise")
# plt.subplot(1,2,2); plt.hist(noise.ravel(),bins=100); plt.title("Noise Dist"); plt.tight_layout()
# plt.show()
# ##################################################################################################
#
# import numpy as np
# import matplotlib.pyplot as plt
#
# # 4. 泊松噪声(Poisson Noise)
# # 信号依赖,需要先有非零图像;这里以128灰度常量图为例
# image = np.full((256,256),128,dtype=np.uint8)
# noise = np.random.poisson(image/255.0*10)/10*255 - image
# noisy = np.clip(image + noise,0,255).astype(np.uint8)
#
# plt.subplot(1,2,1); plt.imshow(noisy,cmap='gray'); plt.title("Poisson Noise")
# plt.subplot(1,2,2); plt.hist(noise.ravel(),bins=100); plt.title("Noise Dist"); plt.tight_layout()
# plt.show()
# ##################################################################################################
#
# import numpy as np
# import matplotlib.pyplot as plt
#
# # 5. 瑞利噪声(Rayleigh Noise)
# image = np.zeros((256,256),dtype=np.uint8)
# noise = np.random.rayleigh(scale=25, size=image.shape)
# noisy = np.clip(image + noise,0,255).astype(np.uint8)
#
# plt.subplot(1,2,1); plt.imshow(noisy,cmap='gray'); plt.title("Rayleigh Noise")
# plt.subplot(1,2,2); plt.hist(noise.ravel(),bins=100); plt.title("Noise Dist"); plt.tight_layout()
# plt.show()
# ##################################################################################################
#
# import numpy as np
# import matplotlib.pyplot as plt
#
# # 6. 伽马噪声(Gamma Noise)
# image = np.zeros((256,256),dtype=np.uint8)
# shape_k = 2.0
# scale_theta = 20.0
# noise = np.random.gamma(shape_k,scale_theta,image.shape)
# noisy = np.clip(image + noise,0,255).astype(np.uint8)
#
# plt.subplot(1,2,1); plt.imshow(noisy,cmap='gray'); plt.title("Gamma Noise")
# plt.subplot(1,2,2); plt.hist(noise.ravel(),bins=100); plt.title("Noise Dist"); plt.tight_layout()
# plt.show()
# ##################################################################################################
#
# import numpy as np
# import matplotlib.pyplot as plt
#
# # 7. 斑点噪声(Speckle Noise)
# # 乘性噪声:img + img*noise,noise服从正态分布
# image = np.zeros((256,256),dtype=np.uint8)+128
# noise = np.random.normal(0,0.1,image.shape)
# noisy = np.clip(image + image*noise,0,255).astype(np.uint8)
#
# plt.subplot(1,2,1); plt.imshow(noisy,cmap='gray'); plt.title("Speckle Noise")
# plt.subplot(1,2,2); plt.hist(noise.ravel(),bins=100); plt.title("Noise Dist"); plt.tight_layout()
# plt.show()
# ##################################################################################################
#
# import numpy as np
# import matplotlib.pyplot as plt
#
# # 8. 脉冲噪声(Impulse Noise)
# # 随机脉冲(仅白点)
# image = np.zeros((256,256),dtype=np.uint8)
# prob = 0.01
# noisy = image.copy()
# mask = np.random.rand(*image.shape) < prob
# noisy[mask] = 255
# noise = mask.astype(np.uint8)
#
# plt.subplot(1,2,1); plt.imshow(noisy,cmap='gray'); plt.title("Impulse Noise")
# plt.subplot(1,2,2); plt.hist(noise.ravel(),bins=2); plt.title("Noise Dist"); plt.tight_layout()
# plt.show()
# ##################################################################################################
2. (单帧)添加噪声(支持uint8、uint16、float32)
import os
import cv2
import tifffile
import numpy as np
def add_uniform_noise(image, intensity=50, noise_ratio=1.0):
"""
添加均匀随机噪声(Uniform Noise),并控制受影响像素的比例。
支持 uint8, uint16 和 float32 图像。
参数:
image (numpy.ndarray): 输入的灰度图像。
intensity (int): 噪声强度,取值范围为 [0, max_val // 2],其中 max_val 为图像数据类型最大值。
noise_ratio (float): 噪声覆盖率,取值范围为 (0, 1]。
返回:
numpy.ndarray: 添加均匀随机噪声后的图像,数据类型与输入保持一致。
"""
if image.ndim != 2:
raise ValueError("只支持灰度图像")
if not (0 < noise_ratio <= 1.0):
raise ValueError("噪声覆盖率必须在 (0, 1] 之间")
if np.issubdtype(image.dtype, np.integer): # uint8 图像
max_val = np.iinfo(image.dtype).max # 获取图像数据类型最大值
elif np.issubdtype(image.dtype, np.floating): # float32 图像
max_val = 1.0 # 获取图像数据类型最大值
else:
raise TypeError("不支持的图像数据类型")
assert 0 < intensity <= max_val // 2 if isinstance(max_val, int) else intensity <= 0.5 # 噪声强度不能超过最大值的一半
noisy_image = image.copy() # 复制原始图像,避免修改原图
h, w = image.shape # 获取图像尺寸
total_pixels = h * w # 计算图像总像素数
num_noisy_pixels = int(total_pixels * noise_ratio) # 计算受影响的像素数
indices = np.random.choice(total_pixels, num_noisy_pixels, replace=False) # 随机选择受影响的像素
coords = np.unravel_index(indices, (h, w)) # 获取受影响的像素坐标
noise = np.random.uniform(-intensity, intensity, num_noisy_pixels) # 生成符合均匀分布的随机噪声(数值可能为负数)
if np.issubdtype(image.dtype, np.integer): # uint8 图像
noise = noise.astype(np.int32) # 将噪声转换为 int32 避免数据溢出
temp = noisy_image[coords].astype(np.int32) + noise # 将图像转换为 int32 避免数据溢出 + 噪声
noisy_image[coords] = np.clip(temp, 0, max_val).astype(image.dtype) # 限制像素值范围并转换回原数据类型
else: # float32 图像
temp = noisy_image[coords] + noise # 将图像转换为 float32 避免数据溢出 + 噪声
noisy_image[coords] = np.clip(temp, 0.0, max_val).astype(image.dtype) # 限制像素值范围并转换回原数据类型
return noisy_image
def add_gaussian_noise(image, mean=0.0, sigma=25.0):
"""
添加高斯噪声(Gaussian Noise) — 遵循正态分布,用于模拟感光元件噪声。
支持 uint8、uint16、float32 的灰度图像。
参数:
image (numpy.ndarray): 输入的灰度图像。
mean (float): 均值,决定噪声分布的中心位置(默认 0.0)。推荐取值范围为 (-100, 100)(默认 0.0)。
sigma (float): 标准差,决定噪声分布的离散程度(默认 25.0)。推荐取值范围为 (0, 100)(默认 25.0)。
返回:
numpy.ndarray: 添加高斯噪声后的图像,数据类型与输入保持一致。
"""
if image.ndim != 2:
raise ValueError("只支持灰度图像")
if sigma < 0:
raise ValueError("sigma 必须为非负数")
if np.issubdtype(image.dtype, np.integer): # uint8 图像
max_val = np.iinfo(image.dtype).max # 获取图像数据类型最大值
elif np.issubdtype(image.dtype, np.floating): # float32 图像
max_val = 1.0
else:
raise TypeError("不支持的图像数据类型")
noise = np.random.normal(mean, sigma, image.shape) # 生成符合高斯分布的随机噪声(数值可能为负数)
if np.issubdtype(image.dtype, np.integer): # uint8 图像
temp = image.astype(np.int32) + noise.astype(np.int32) # 将图像转换为 int32 避免数据溢出 + 噪声
noisy_image = np.clip(temp, 0, max_val).astype(image.dtype) # 限制像素值范围并转换回原数据类型
else: # float32 图像
temp = image + noise # 将图像转换为 float32 避免数据溢出 + 噪声
noisy_image = np.clip(temp, 0.0, max_val).astype(image.dtype) # 限制像素值范围并转换回原数据类型
return noisy_image
def add_salt_pepper_noise(image, salt_prob=0.02, pepper_prob=0.02):
"""
添加椒盐噪声(Salt-and-Pepper Noise)——随机选择部分像素,将其值设为最大值或最小值。设为白(盐)或黑(胡椒)。
支持 uint8、uint16、float32 灰度图。
参数:
image (numpy.ndarray): 输入的灰度图像。
salt_prob (float): 椒噪声概率,推荐取值范围为 (0, 1](默认 0.02)。
pepper_prob (float): 胡椒噪声概率,推荐取值范围为 (0, 1](默认 0.02)。
返回:
numpy.ndarray: 添加椒盐噪声后的图像,数据类型与输入保持一致。
"""
if image.ndim != 2:
raise ValueError("只支持灰度图像")
if not (0 <= salt_prob <= 1) or not (0 <= pepper_prob <= 1): # 检查概率值
raise ValueError("salt_prob 和 pepper_prob 应在 [0,1] 范围内")
if salt_prob + pepper_prob > 1: # 检查概率值
raise ValueError("salt_prob 与 pepper_prob 总和不能超过 1")
if np.issubdtype(image.dtype, np.integer): # uint8 图像
max_val = np.iinfo(image.dtype).max # 获取图像数据类型最大值
elif np.issubdtype(image.dtype, np.floating): # float32 图像
max_val = 1.0
else:
raise TypeError("不支持的图像数据类型")
noisy_image = image.copy() # 复制原始图像,避免修改原图
total_pixels = image.size # 计算图像总像素数
num_salt = int(total_pixels * salt_prob) # 计算椒噪声像素数
num_pepper = int(total_pixels * pepper_prob) # 计算胡椒噪声像素数
coords = np.random.choice(total_pixels, num_salt + num_pepper, replace=False) # 随机选择受影响的像素
coords = np.unravel_index(coords, image.shape) # 获取受影响的像素坐标
salt_coords = (coords[0][:num_salt], coords[1][:num_salt]) # 椒噪声坐标
pepper_coords = (coords[0][num_salt:], coords[1][num_salt:]) # 胡椒噪声坐标
max_value = np.max(image) # 获取图像最大值
noisy_image[salt_coords] = max_value # 椒噪声像素值设为最大值
noisy_image[pepper_coords] = 0 # 胡椒噪声像素值设为0
return noisy_image
def add_poisson_noise(image):
"""添加泊松噪声(Poisson Noise)——模拟基于光子统计的成像噪声。
支持 uint8、uint16、float32 灰度图。
参数:
image (numpy.ndarray): 输入的灰度图像。
返回:
numpy.ndarray: 添加泊松噪声后的图像,数据类型与输入保持一致。
###################################################################################
泊松噪声常用于模拟光电计数过程(如感光元件每像素接收到的光子数量),假设曝光量为λ,则接收到的光子数服从:
P(x) = λ^x * exp(-λ) / x!
其中 x 为接收到的光子数,λ 为曝光量。
因此,泊松噪声最关键的是输入λ的物理含义是否合理。本实现通过归一化后乘以一个虚拟曝光因子(255)来模拟λ。
"""
if np.issubdtype(image.dtype, np.integer): # uint8 图像
max_val = np.iinfo(image.dtype).max # 获取图像数据类型最大值
elif np.issubdtype(image.dtype, np.floating): # float32 图像
max_val = 1.0
else:
raise TypeError("不支持的图像数据类型")
max_value = np.max(image) # 获取图像最大值
image_float = image.astype(np.float64) # 将图像转换为 float64 避免数据溢出
# 为避免大灰度值下泊松函数性能退化,缩放到 [0, 1] 范围再乘一个虚拟曝光因子(如 255)
scale_factor = 255.0 # 将图像缩放到 [0, 255] 范围
scaled = image_float / max_value * scale_factor # 缩放到 [0, 1] 范围
noisy = np.random.poisson(scaled) # 生成符合泊松分布的随机噪声(数值可能为负数)
rescaled = noisy / scale_factor * max_value # 将噪声乘以虚拟曝光因子并缩放到 [0, max_value] 范围
noisy_image = np.clip(rescaled, 0, max_value).astype(image.dtype) # 限制像素值范围并转换回原数据类型
return noisy_image
def add_rayleigh_noise(image, scale=30, mode='multiplicative'):
"""添加瑞利噪声(Rayleigh Noise) ———— 常用于通信模拟,默认使用乘性噪声建模。
参数:
image (numpy.ndarray): 输入灰度图像。
scale (float): 瑞利分布的尺度参数,推荐范围为 10 ~ 50。
mode (str): 模式选择,可选 'additive' 或 'multiplicative'。
返回:
numpy.ndarray: 添加瑞利噪声后的图像。
###################################################################################
瑞利分布的数学形式为:f(x) = x * exp(-x^2 / (2 * scale^2)) / (scale^2 * sqrt(2 * pi))
本实现使用乘性噪声建模,即 f(x) = x * noise,其中 noise 为符合瑞利分布的随机噪声(数值可能为负数)。
"""
if np.issubdtype(image.dtype, np.integer): # uint8 图像
max_val = np.iinfo(image.dtype).max # 获取图像数据类型最大值
elif np.issubdtype(image.dtype, np.floating): # float32 图像
max_val = 1.0
else:
raise TypeError("不支持的图像数据类型")
noise = np.random.rayleigh(scale, image.shape) # 生成符合瑞利分布的随机噪声(数值可能为负数)
image_float = image.astype(np.float64) # 将图像转换为 float64 避免数据溢出
if mode == 'additive': # 加性噪声
noisy = image_float + noise
elif mode == 'multiplicative': # 乘性噪声
noisy = image_float * noise
else:
raise ValueError("mode 参数应为 'additive' 或 'multiplicative'")
noisy_image = np.clip(noisy, 0, max_val).astype(image.dtype) # 限制像素值范围并转换回原数据类型
return noisy_image
def add_gamma_noise(image, shape=2.0, scale=30, mode='multiplicative'):
"""添加伽马噪声(Gamma Noise) ———— 可选择加性或乘性噪声,常用于放射性图像建模。
参数:
image (numpy.ndarray): 输入的灰度图像。
shape (float): 伽马分布的形状参数,推荐范围为 0.5 ~ 2.0。
scale (float): 伽马分布的尺度参数,推荐范围为 10 ~ 50。
mode (str): 'additive' 或 'multiplicative',控制噪声叠加方式。
返回:
numpy.ndarray: 添加伽马噪声后的图像。
###################################################################################
伽马分布的数学形式为:f(x) = x^shape * exp(-x / scale) / (scale^shape * gamma(shape))
本实现使用乘性噪声建模,即 f(x) = x * noise,其中 noise 为符合伽马分布的随机噪声(数值可能为负数)。
"""
if np.issubdtype(image.dtype, np.integer): # uint8 图像
max_val = np.iinfo(image.dtype).max # 获取图像数据类型最大值
elif np.issubdtype(image.dtype, np.floating): # float32 图像
max_val = 1.0
else:
raise TypeError("不支持的图像数据类型")
gamma_noise = np.random.gamma(shape, scale, image.shape) # 生成符合伽马分布的随机噪声(数值可能为负数)
image_float = image.astype(np.float64) # 将图像转换为 float64 避免数据溢出
if mode == 'additive': # 加性噪声
noisy = image_float + gamma_noise
elif mode == 'multiplicative': # 乘性噪声
noisy = image_float * gamma_noise
else:
raise ValueError("mode参数仅支持 'additive' 或 'multiplicative'")
noisy_image = np.clip(noisy, 0, max_val).astype(image.dtype) # 限制像素值范围并转换回原数据类型
return noisy_image
def add_speckle_noise(image, scale=0.2):
"""添加斑点噪声(Speckle Noise) ———— 数学形式为 f(x) = x + x·n,其中 n 为高斯分布噪声项。
参数:
image (numpy.ndarray): 输入的灰度图像。
scale (float): 噪声强度的标准差(默认0.2),推荐范围为 0.05 ~ 0.3。
返回:
numpy.ndarray: 添加斑点噪声后的图像,数据类型与输入保持一致。
###################################################################################
本实现使用乘性噪声建模,即 f(x) = x * noise,其中 noise 为符合高斯分布的随机噪声(数值可能为负数)。
"""
if np.issubdtype(image.dtype, np.integer): # uint8 图像
max_val = np.iinfo(image.dtype).max # 获取图像数据类型最大值
elif np.issubdtype(image.dtype, np.floating): # float32 图像
max_val = 1.0
else:
raise TypeError("不支持的图像数据类型")
image_float = image.astype(np.float32) # 将图像转换为 float32 避免数据溢出
noise = np.random.randn(*image.shape) * scale # 生成符合高斯分布的随机噪声(数值可能为负数)
noisy = image_float + image_float * noise # N(0, scale²)
noisy_image = np.clip(noisy, 0, max_val).astype(image.dtype) # 限制像素值范围并转换回原数据类型
return noisy_image
def add_impulse_noise(image, prob=0.02):
"""添加脉冲噪声(Impulse Noise) ———— 以一定概率将像素值替换为最大值或最小值,模拟传感器失真。
参数:
image (numpy.ndarray): 输入的灰度图像。
prob (float): 每个像素被替换为噪声值(0或最大值)的概率(默认0.02)。推荐范围为 0.001 ~ 0.1。
返回:
numpy.ndarray: 添加脉冲噪声后的图像,数据类型与输入保持一致。
###################################################################################
本实现使用乘性噪声建模,即 f(x) = x * noise,其中 noise 为符合高斯分布的随机噪声(数值可能为负数)。
"""
if np.issubdtype(image.dtype, np.integer): # uint8 图像
max_val = np.iinfo(image.dtype).max # 获取图像数据类型最大值
elif np.issubdtype(image.dtype, np.floating): # float32 图像
max_val = 1.0
else:
raise TypeError("不支持的图像数据类型")
noisy_image = image.copy() # 复制原始图像,避免修改原图
h, w = image.shape # 获取图像尺寸
total_pixels = h * w # 计算图像总像素数
num_impulse = int(total_pixels * prob) # 计算脉冲噪声像素数
indices = np.random.choice(total_pixels, num_impulse, replace=False) # 随机选择受影响的像素
coords = np.unravel_index(indices, (h, w)) # 获取受影响的像素坐标
# 随机决定这些像素设为 0 还是 max_value
max_value = np.max(image) # 获取图像最大值
salt_or_pepper = np.random.randint(0, 2, num_impulse) # 0 或 1
noisy_image[coords] = salt_or_pepper * max_value # 将像素值设为 0 或 max_value
return noisy_image.astype(image.dtype)
def add_noise(image, mode='gaussian', **kwargs):
if mode == 'uniform':
return add_uniform_noise(image, **kwargs)
elif mode == 'gaussian':
return add_gaussian_noise(image, **kwargs)
elif mode == 'salt_pepper':
return add_salt_pepper_noise(image, **kwargs)
elif mode == 'poisson':
return add_poisson_noise(image, **kwargs)
elif mode == 'rayleigh':
return add_rayleigh_noise(image, **kwargs)
elif mode == 'gamma':
return add_gamma_noise(image, **kwargs)
elif mode == 'speckle':
return add_speckle_noise(image, **kwargs)
elif mode == 'impulse':
return add_impulse_noise(image, **kwargs)
else:
raise ValueError("不支持的噪声类型")
def read_image(image_path):
if not os.path.exists(image_path):
raise ValueError("文件不存在,请检查文件路径")
if not os.path.isfile(image_path):
raise ValueError("路径不是文件,请检查文件路径")
if not os.path.splitext(image_path)[1] in ['.tif', '.tiff', '.bmp', '.jpg', '.jpeg', '.png']:
raise ValueError("不支持的文件格式,请检查文件路径")
if image_path.endswith('.tif') or image_path.endswith('.tiff'):
image = tifffile.imread(image_path)
elif image_path.endswith('.bmp') or image_path.endswith('.jpg') or image_path.endswith('.jpeg') or image_path.endswith('.png'):
image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
else:
raise ValueError("不支持的文件格式,请检查文件路径")
return image
if __name__ == '__main__':
import random
random.seed(0)
np.random.seed(0)
# (1)读取图像
image_path = r"image.tif"
image = read_image(image_path)
# (2)添加噪声
uniform_noise = add_uniform_noise(image, intensity=50, noise_ratio=0.1)
gaussian_noise = add_gaussian_noise(image, mean=0.0, sigma=25.0)
salt_pepper_noise = add_salt_pepper_noise(image, salt_prob=0.02, pepper_prob=0.02)
poisson_noise = add_poisson_noise(image)
rayleigh_noise = add_rayleigh_noise(image, scale=30, mode='multiplicative')
gamma_noise = add_gamma_noise(image, shape=2.0, scale=30, mode='multiplicative')
speckle_noise = add_speckle_noise(image, scale=0.2)
impulse_noise = add_impulse_noise(image, prob=0.02)
# (3)保存图像
path = os.path.dirname(image_path) # 获取图像路径
name = os.path.splitext(os.path.basename(image_path))[0] # 获取图像名
print(os.path.join(path, name))
# if image_path.endswith('.tif') or image_path.endswith('.tiff'):
# tifffile.imwrite(os.path.join(path, name + r"_uniform.tif"), uniform_noise)
# tifffile.imwrite(os.path.join(path, name + r"_gaussian.tif"), gaussian_noise)
# tifffile.imwrite(os.path.join(path, name + r"_salt_pepper.tif"), salt_pepper_noise)
# tifffile.imwrite(os.path.join(path, name + r"_poisson.tif"), poisson_noise)
# tifffile.imwrite(os.path.join(path, name + r"_rayleigh.tif"), rayleigh_noise)
# tifffile.imwrite(os.path.join(path, name + r"_gamma.tif"), gamma_noise)
# tifffile.imwrite(os.path.join(path, name + r"_speckle.tif"), speckle_noise)
# tifffile.imwrite(os.path.join(path, name + r"_impulse.tif"), impulse_noise)
# elif image_path.endswith('.bmp') or image_path.endswith('.jpg') or image_path.endswith('.jpeg') or image_path.endswith('.png'):
# cv2.imwrite(os.path.join(path, name + r"_uniform.png"), uniform_noise)
# cv2.imwrite(os.path.join(path, name + r"_gaussian.png"), gaussian_noise)
# cv2.imwrite(os.path.join(path, name + r"_salt_pepper.png"), salt_pepper_noise)
# cv2.imwrite(os.path.join(path, name + r"_poisson.png"), poisson_noise)
# cv2.imwrite(os.path.join(path, name + r"_rayleigh.png"), rayleigh_noise)
# cv2.imwrite(os.path.join(path, name + r"_gamma.png"), gamma_noise)
# cv2.imwrite(os.path.join(path, name + r"_speckle.png"), speckle_noise)
# cv2.imwrite(os.path.join(path, name + r"_impulse.png"), impulse_noise)
# (4)显示图像
import matplotlib.pyplot as plt
plt.subplot(251), plt.imshow(image, cmap='gray'), plt.title('Original Image'), plt.axis('off')
plt.subplot(252), plt.imshow(uniform_noise, cmap='gray'), plt.title('Uniform Noise'), plt.axis('off')
plt.subplot(253), plt.imshow(gaussian_noise, cmap='gray'), plt.title('Gaussian Noise'), plt.axis('off')
plt.subplot(254), plt.imshow(salt_pepper_noise, cmap='gray'), plt.title('Salt & Pepper Noise'), plt.axis('off')
plt.subplot(255), plt.imshow(poisson_noise, cmap='gray'), plt.title('Poisson Noise'), plt.axis('off')
plt.subplot(257), plt.imshow(rayleigh_noise, cmap='gray'), plt.title('Rayleigh Noise'), plt.axis('off')
plt.subplot(258), plt.imshow(gamma_noise, cmap='gray'), plt.title('Gamma Noise'), plt.axis('off')
plt.subplot(259), plt.imshow(speckle_noise, cmap='gray'), plt.title('Speckle Noise'), plt.axis('off')
plt.subplot(2,5,10), plt.imshow(impulse_noise, cmap='gray'), plt.title('Impulse Noise'), plt.axis('off')
plt.show()
3. (多帧)索引文件夹下的所有图像,并添加噪声
import os
import cv2
import tifffile
import numpy as np
def add_gaussian_noise(image, mean=0, std=25):
noise = np.random.normal(mean, std, image.shape).astype(np.float32)
noisy_img = image.astype(np.float32) + noise
noisy_img = np.clip(noisy_img, 0, 255)
return noisy_img.astype(image.dtype)
def process_images_with_noise(src_dir, dst_dir, noise_func, **kwargs):
if not os.path.exists(dst_dir):
os.makedirs(dst_dir)
for filename in os.listdir(src_dir):
src_path = os.path.join(src_dir, filename)
if not os.path.isfile(src_path):
continue
# 读取图像(支持彩色或灰度)
img = tifffile.imread(src_path)
# img = cv2.imread(src_path, cv2.IMREAD_UNCHANGED)
if img is None:
continue
# 添加噪声
noisy_img = noise_func(img, **kwargs)
# 构建目标路径并保存
dst_path = os.path.join(dst_dir, filename)
# cv2.imwrite(dst_path, noisy_img)
tifffile.imwrite(dst_path, noisy_img)
print("处理完成。")
if __name__ == '__main__':
source_folder = r"input_images" # 源图像文件夹
target_folder = r'noisy_images' # 保存加噪图像的文件夹
process_images_with_noise(
src_dir=source_folder,
dst_dir=target_folder,
noise_func=add_gaussian_noise, # 更换加噪函数(需同步更换参数)
mean=0,
std=20
)