第三章 实战准备:Python环境搭建与图像处理基础

说实话,每次带新人入门手机摄影算法,我最怕听到的就是「环境装好了,但跑不起来」。我自己也踩过不少坑,所以这一章咱们把基础打扎实。你想想看,如果连图像都读不进来、噪声都模拟不对,后面那些高级去噪算法根本没法验证。

3.1 Python环境搭建:三件套的安装

我个人习惯用 Anaconda 管理环境,省心。你直接用 pip 也行,但记得别把包装乱了。

# 创建一个干净的环境
conda create -n denoise python=3.9
conda activate denoise

# 安装核心三件套
pip install numpy==1.24.3
pip install opencv-python==4.8.0
pip install scikit-image==0.21.0
⚠️ 版本坑提醒: 我曾经因为 NumPy 版本太高,导致 OpenCV 的某些函数报错。建议锁定我上面给的版本号,兼容性最好。

为什么要这三样?

  • NumPy:图像本质就是多维数组,没有它寸步难行
  • OpenCV:读取、显示、基础处理,效率极高
  • Scikit-image:算法丰富,PSNR/SSIM 直接调用,省得自己写

3.2 图像读取与显示:别被坑了

图像读取看似简单,其实暗藏玄机。OpenCV 默认读进来是 BGR 格式,而 Scikit-image 是 RGB。这个差异我当年调试了整整一个下午才发现。

import cv2
import matplotlib.pyplot as plt
from skimage import io

# OpenCV 读取(BGR)
img_cv = cv2.imread('photo.jpg')
print(f"OpenCV 读取形状: {img_cv.shape}")  # (H, W, 3)

# Scikit-image 读取(RGB)
img_sk = io.imread('photo.jpg')
print(f"Scikit-image 读取形状: {img_sk.shape}")

# 正确显示:OpenCV 需要转换
img_rgb = cv2.cvtColor(img_cv, cv2.COLOR_BGR2RGB)
plt.imshow(img_rgb)
plt.title('正确显示')
plt.show()
💡 我的习惯: 统一用 Scikit-image 读取,省去颜色转换的麻烦。除非你需要用 OpenCV 的快速处理功能。

3.3 噪声模拟:造出真实感

做去噪算法,你得先有噪声数据。手机摄影中最常见的是高斯噪声和椒盐噪声。我在项目中遇到过一个问题:模拟的噪声太「干净」,导致算法在真实场景下表现很差。

import numpy as np
import cv2

def add_gaussian_noise(image, mean=0, sigma=25):
    """添加高斯噪声"""
    noise = np.random.normal(mean, sigma, image.shape)
    noisy = image + noise
    return np.clip(noisy, 0, 255).astype(np.uint8)

def add_salt_pepper_noise(image, prob=0.02):
    """添加椒盐噪声"""
    output = image.copy()
    # 椒噪声(黑点)
    salt_mask = np.random.random(image.shape[:2]) < prob/2
    output[salt_mask] = 0
    # 盐噪声(白点)
    pepper_mask = np.random.random(image.shape[:2]) < prob/2
    output[pepper_mask] = 255
    return output

# 测试
img = cv2.imread('photo.jpg', cv2.IMREAD_GRAYSCALE)
noisy_gauss = add_gaussian_noise(img, sigma=30)
noisy_sp = add_salt_pepper_noise(img, prob=0.05)

关键参数说明:

  • sigma:高斯噪声的标准差,手机摄影中通常 10-50
  • prob:椒盐噪声概率,0.01-0.05 比较真实
  • 记得 np.clip 防止像素值溢出

3.4 评估指标:PSNR 和 SSIM

算法好不好,得用数据说话。PSNR 看像素级差异,SSIM 看结构相似度。我个人的经验是:PSNR 高不一定视觉好,但 SSIM 高通常意味着人眼看着舒服。

from skimage.metrics import peak_signal_noise_ratio as psnr
from skimage.metrics import structural_similarity as ssim

# 计算指标
psnr_value = psnr(img, noisy_gauss, data_range=255)
ssim_value = ssim(img, noisy_gauss, data_range=255)

print(f"PSNR: {psnr_value:.2f} dB")
print(f"SSIM: {ssim_value:.4f}")

# 批量评估
def evaluate_denoising(original, denoised):
    psnr_val = psnr(original, denoised, data_range=255)
    ssim_val = ssim(original, denoised, data_range=255)
    return {'PSNR': psnr_val, 'SSIM': ssim_val}
指标 范围 含义 手机摄影参考值
PSNR 0~∞ dB 像素级误差 >30 dB 可接受,>40 dB 优秀
SSIM -1~1 结构相似度 >0.9 视觉上几乎无差异
⚠️ 评估陷阱: 我曾经用 PSNR 优化算法,结果图像被过度平滑,细节全没了。记住:SSIM 更贴近人眼感知,两者要结合看。

3.5 知识体系总览

下面这张图是我自己整理的,把本章的核心逻辑串起来了。你照着这个流程走,基本不会出错。

实战准备知识体系 环境搭建 NumPy + OpenCV + Scikit-image 图像读写 BGR vs RGB 格式转换 噪声模拟 高斯 + 椒盐噪声 评估指标 PSNR(像素级) + SSIM(结构级) 核心流程:环境 → 读写 → 模拟噪声 → 评估效果 注意:每一步都有坑,建议按顺序验证通过后再往下走

3.6 完整实战脚本

最后,我把上面所有内容整合成一个脚本。你直接跑一遍,就能验证环境是否正常。

import numpy as np
import cv2
import matplotlib.pyplot as plt
from skimage import io
from skimage.metrics import peak_signal_noise_ratio as psnr
from skimage.metrics import structural_similarity as ssim

def main():
    # 1. 读取图像
    img = io.imread('test_photo.jpg')
    print(f"原始图像: {img.shape}, 范围: {img.min()}-{img.max()}")
    
    # 2. 添加噪声
    noise = np.random.normal(0, 25, img.shape)
    noisy = np.clip(img + noise, 0, 255).astype(np.uint8)
    
    # 3. 评估
    psnr_val = psnr(img, noisy, data_range=255)
    ssim_val = ssim(img, noisy, data_range=255, channel_axis=-1)
    
    print(f"PSNR: {psnr_val:.2f} dB")
    print(f"SSIM: {ssim_val:.4f}")
    
    # 4. 显示
    plt.figure(figsize=(10, 5))
    plt.subplot(1, 2, 1)
    plt.imshow(img)
    plt.title('原始图像')
    plt.subplot(1, 2, 2)
    plt.imshow(noisy)
    plt.title(f'噪声图像 (PSNR={psnr_val:.1f}dB)')
    plt.show()

if __name__ == '__main__':
    main()
💡 调试技巧: 如果图像显示偏色,99% 是颜色通道顺序问题。用 cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 转换一下就好。

嗯,这一章的内容就这些。环境搭好了、图像能读了、噪声会模拟了、评估指标也掌握了——后面的去噪算法实战,你就能放开手脚去试了。


公众号:蓝海资料掘金营,微信deep3321