文章目錄
- 一、基本定義
- 二、判斷圖像信噪比是否過低(經驗值,僅供參考)
- 三、SNR與圖像質量指標關系
- 四、評估方法 + 代碼復現 —— 評估一張圖像的信噪比
- (1)有參考圖像(推薦)
- (2)無參考圖像(自參考法)
- 方法1:均值與標準差比值法(Mean-to-Std) —— 適用于背景均勻圖像
- 方法2:局部平滑圖作為參考(弱參考) —— 適用于結構復雜圖像
一、基本定義
圖像信噪比(SNR)是一種衡量圖像質量的重要指標,用于評價圖像中有用信號(結構/圖像內容)與噪聲成分(失真/隨機干擾)之間的相對強度。它在圖像增強、重建、去噪等場景中廣泛用于質量評估與調優依據。
信噪比定義:
SNR=10?log?10(∑S2∑(S?T)2)\mathrm{SNR} = 10 \cdot \log_{10} \left( \frac{\sum S^2}{\sum (S - T)^2} \right) SNR=10?log10?(∑(S?T)2∑S2?)
𝑆:參考圖像(ground truth)
,即理想無噪圖像𝑇:測試圖像
,含噪或待評估圖像- 分子:信號能量(原圖灰度值平方和)
- 分母:噪聲能量(參考圖與測試圖差異的平方和)
單位為分貝(dB),值越大表示圖像中信號越強、噪聲越小,圖像質量越高
二、判斷圖像信噪比是否過低(經驗值,僅供參考)
圖像SNR越高,視覺質量越好。根據經驗或視覺評估,常采用如下分界:
SNR值(dB) | 質量等級 | 說明 |
---|---|---|
> 40 dB | 極佳 | 噪聲幾乎不可見 |
30–40 dB | 良好 | 噪聲極小,不影響觀察 |
20–30 dB | 一般可用 | 有一定噪聲,圖像細節仍可接受 |
10–20 dB | 差 | 噪聲明顯,圖像結構受干擾 |
< 10 dB | 極差(過低) | 噪聲嚴重遮蔽圖像內容,常需重采/去噪 |
?? 注:SNR判斷應結合具體應用,例如醫學圖像要求更高,而工業場景容忍度可放寬。
圖像信噪比低時的表現:
- 對比度低,輪廓模糊;
- 紋理缺失,圖像邊緣噪聲明顯;
- 清晰度指標(如方差、Laplacian、熵)均偏低。
三、SNR與圖像質量指標關系
指標 | 有參考 | 無參考 | 特征 |
---|---|---|---|
SNR | ? | 估算版 ? | 強調灰度能量 |
PSNR | ? | ? | 最大像素值主導 |
SSIM | ? | ? | 更關注結構相似度 |
信息熵 | ?/? | ? | 衡量信息復雜度或保真度 |
方差 | ? | ? | 間接反映紋理與對比度 |
- 有參考圖像時,優先使用SNR或PSNR;
- 無參考圖像時,結合熵+方差+估算SNR三指標綜合判斷;
- 圖像過于模糊時,SNR 常低于 15 dB,可作為模糊圖識別依據;
- 可將 SNR 與對比度增強算法結合,實現自動圖像質量篩選與增強優化。
四、評估方法 + 代碼復現 —— 評估一張圖像的信噪比
(1)有參考圖像(推薦)
適用于圖像去噪或增強場景,有“原始圖像”作為基準。
若存在“無噪聲”參考圖,可以使用如下指標判斷:
指標 | 判斷標準 | 說明 |
---|---|---|
SNR (dB) | < 20dB → 認為信噪比低 | 典型圖像處理任務中,SNR 低于20dB 可能影響細節分析 |
PSNR (dB) | < 30dB → 質量較差 | 盡管PSNR主要用于壓縮圖像質量,但也適用于噪聲干擾情況 |
MSE | 趨近于0越好 | 噪聲能量越大,MSE越高;與SNR成反比 |
信噪比、峰值信噪比、均方根誤差、平均絕對誤差
ImageJ 的插件用于評估圖像質量(定義與安裝 + 使用教程)
https://bigwww.epfl.ch/sage/soft/snr/
import cv2
import numpy as npdef compute_snr(r, t):"""計算信號對噪聲比(SNR),公式 SNR = 10 * log10(P_signal / P_noise)其中 P_signal = mean(r^2),噪聲 = t - r。"""noise = t.astype(np.float64) - r.astype(np.float64)psignal = np.mean(r.astype(np.float64) ** 2)pnoise = np.mean(noise ** 2)if pnoise == 0:return float('inf')return 10 * np.log10(psignal / pnoise)def compute_psnr(r, t, max_pixel=255.0):"""計算峰值信號對噪聲比(PSNR),公式 PSNR = 20*log10(MAX_I) - 10*log10(MSE)"""mse = np.mean((r.astype(np.float64) - t.astype(np.float64)) ** 2)if mse == 0:return float('inf')return 20 * np.log10(max_pixel / np.sqrt(mse))def compute_rmse(r, t):"""計算均方根誤差(RMSE)"""return np.sqrt(np.mean((r.astype(np.float64) - t.astype(np.float64)) ** 2))def compute_mae(r, t):"""計算平均絕對誤差(MAE)"""return np.mean(np.abs(r.astype(np.float64) - t.astype(np.float64)))def evaluate_image_quality(ref_path, test_path):# 讀取為灰度圖r = cv2.imread(ref_path, cv2.IMREAD_GRAYSCALE)t = cv2.imread(test_path, cv2.IMREAD_GRAYSCALE)assert r.shape == t.shape, "圖像尺寸不一致!"snr = compute_snr(r, t)psnr = compute_psnr(r, t)rmse = compute_rmse(r, t)mae = compute_mae(r, t)return {'SNR_dB': snr, 'PSNR_dB': psnr, 'RMSE': rmse, 'MAE': mae}if __name__ == "__main__":reference_image = "1-04.tif"test_image = "1-04-1.tif"metrics = evaluate_image_quality(reference_image, test_image)for k, v in metrics.items():print(f"{k}: {v:.8f}")
"""
SNR_dB: 11.92441281
PSNR_dB: 17.78177464
RMSE: 32.91936492
MAE: 23.56512515
"""
(2)無參考圖像(自參考法)
常見場景:顯微圖像、X光圖像、SEM圖像。此時可考慮:
方法 | 原理 | 是否支持自動評估 |
---|---|---|
方差/標準差 | 圖像整體灰度變化程度,方差越小表示圖像越平 | ? |
灰度熵 | 熵低表示像素分布集中,圖像信息少 | ? |
頻域分析(如FFT能譜) | 高頻衰減嚴重,圖像模糊,可能是低SNR表現 | ? |
邊緣響應 | 用Sobel等算子檢測邊緣,邊緣弱說明細節低 | ? |
方法1:均值與標準差比值法(Mean-to-Std) —— 適用于背景均勻圖像
import cv2
import numpy as npdef estimate_snr_single_image(img):img = img.astype(np.float64)mean = np.mean(img)std = np.std(img)if std == 0:return float('inf')return 20 * np.log10(mean / std) # 分貝單位if __name__ == "__main__":path = "1-04-1.tif"image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)metrics = estimate_snr_single_image(image)print(f"SNR: {metrics:.8f}") # SNR: 4.87419592
方法2:局部平滑圖作為參考(弱參考) —— 適用于結構復雜圖像
思路:把圖像自身當作“信號+噪聲”的混合體,利用局部平滑圖像估計出“信號”,殘差視為“噪聲”。
import cv2
import numpy as npdef estimate_snr_single_image(img, kernel_size=3):"""評估單張圖像的 SNR:以平滑圖像為信號,殘差為噪聲"""img = img.astype(np.float64)blurred = cv2.GaussianBlur(img, (kernel_size, kernel_size), 0)signal_power = np.mean(blurred ** 2)noise_power = np.mean((img - blurred) ** 2)if noise_power == 0:return float('inf')return 10 * np.log10(signal_power / noise_power)if __name__ == "__main__":path = "1-04-1.tif"image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)metrics = estimate_snr_single_image(image)print(f"SNR: {metrics:.8f}") # SNR: 13.77251702