4. 图像基础增强:几何变换、色彩抖动与噪声注入
图像增强,说白了就是给训练数据“化妆”。你想想看,真实世界里的照片,角度会偏、光线会变、摄像头还会有点噪点。如果模型只在“素颜”的干净数据上训练,一到真实场景立马就崩。
我个人习惯把图像增强分成三大类:几何变换、色彩抖动和噪声注入。这三板斧用好了,模型的泛化性至少能提 5-10 个点。下面我一个个拆开讲。
4.1 几何变换:让模型学会“换个角度看世界”
几何变换是最直观的增强手段。你拍一张猫的照片,换个角度它还是猫。模型必须学会这种不变性。
4.1.1 旋转与翻转
旋转一般取 ±10° 到 ±30°。翻转分水平翻转和垂直翻转。水平翻转很常用,垂直翻转在自然图像里要慎用——你想想,谁会倒着看人脸?
4.1.2 随机裁剪与缩放
随机裁剪是“暴力但有效”的方法。从原图上随机抠一块,再缩放到固定尺寸。这相当于让模型看到物体的局部也能识别。
我记得有一次做细粒度分类,鸟类数据集里每张图都拍得很正。模型在测试集上遇到稍微偏一点的图就崩。加了随机裁剪后,准确率直接从 72% 跳到 81%。
import torchvision.transforms as T
# 常用几何变换组合
geo_transform = T.Compose([
T.RandomResizedCrop(size=224, scale=(0.8, 1.0)),
T.RandomHorizontalFlip(p=0.5),
T.RandomRotation(degrees=15),
T.Resize((224, 224))
])
| 变换类型 | 常用参数 | 适用场景 | 注意事项 |
|---|---|---|---|
| 水平翻转 | p=0.5 | 通用(自然图像) | 文字、车牌等有方向性任务慎用 |
| 旋转 | ±10° ~ ±30° | 通用 | 角度过大可能改变语义 |
| 随机裁剪 | scale=(0.08, 1.0) | 分类、检测 | 裁剪比例不要太小 |
| 仿射变换 | translate=(0.1, 0.1) | 文本、文档图像 | 保持文字可读性 |
4.2 色彩抖动:模拟真实世界的光照变化
同一个物体,早上和傍晚拍出来颜色完全不一样。色彩抖动就是模拟这种变化。
4.2.1 亮度、对比度、饱和度调整
这三个参数是色彩抖动的“三件套”。亮度调暗一点,对比度拉高一点,饱和度降一点,模型就能适应不同光照条件。
我个人习惯用 ColorJitter,参数范围设得比较保守:亮度 ±0.2,对比度 ±0.2,饱和度 ±0.2。太猛了会失真,模型反而学坏。
4.2.2 HSV 空间扰动
在 HSV 空间做扰动比 RGB 更自然。因为 HSV 把色调、饱和度、亮度分开了,你单独调亮度不会影响颜色。
# 色彩抖动示例
color_transform = T.Compose([
T.ColorJitter(
brightness=0.2,
contrast=0.2,
saturation=0.2,
hue=0.1
),
T.ToTensor(),
T.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
4.3 噪声注入:让模型学会“抗干扰”
真实摄像头拍出来的图,多少都有噪声。模型如果没见过噪声,遇到一点噪点就崩了。
4.3.1 高斯噪声与椒盐噪声
高斯噪声是加性噪声,每个像素加一个高斯分布的值。椒盐噪声是随机把像素变成纯白或纯黑。
我记得在安防场景的项目里,摄像头在低光照下全是噪点。一开始模型在白天数据上跑得很好,晚上直接废了。加了高斯噪声训练后,夜间准确率从 55% 提到了 78%。
4.3.2 模糊与遮挡
模糊模拟运动或失焦,遮挡模拟物体被挡住一部分。这两种增强对检测和分割任务特别有用。
import random
import torch
def add_gaussian_noise(img, mean=0., std=0.05):
noise = torch.randn_like(img) * std + mean
return torch.clamp(img + noise, 0., 1.)
def random_erasing(img, p=0.5, scale=(0.02, 0.1)):
if random.random() < p:
# 随机遮挡一块区域
h, w = img.shape[1:]
eh = int(random.uniform(*scale) * h)
ew = int(random.uniform(*scale) * w)
x = random.randint(0, w - ew)
y = random.randint(0, h - eh)
img[:, y:y+eh, x:x+ew] = 0
return img
| 噪声类型 | 强度范围 | 适用场景 | 副作用 |
|---|---|---|---|
| 高斯噪声 | std=0.01~0.1 | 低光照、传感器噪声 | 过强会掩盖细节 |
| 椒盐噪声 | prob=0.01~0.05 | 传输丢包、老旧摄像头 | 密度过高破坏结构 |
| 高斯模糊 | kernel=3~7 | 运动模糊、失焦 | 过度模糊丢失纹理 |
| 随机遮挡 | scale=0.02~0.3 | 遮挡检测、鲁棒性训练 | 遮挡比例过大导致语义丢失 |
4.4 增强策略组合:别一股脑全上
很多人以为增强越多越好,其实不是。增强组合不当,反而会降低模型性能。
我一般遵循三个原则:
- 先几何后色彩:先做旋转裁剪,再做颜色调整。顺序反了会导致颜色信息被几何变换插值破坏。
- 噪声放最后:噪声注入放在所有变换之后,避免噪声被后续的缩放或裁剪放大。
- 强度递进:训练初期用弱增强,后期逐渐加强。让模型先学干净特征,再学抗干扰。
# 推荐的增强组合顺序
full_transform = T.Compose([
# 1. 几何变换
T.RandomResizedCrop(224, scale=(0.8, 1.0)),
T.RandomHorizontalFlip(p=0.5),
T.RandomRotation(degrees=10),
# 2. 色彩抖动
T.ColorJitter(brightness=0.2, contrast=0.2,
saturation=0.2, hue=0.05),
# 3. 噪声注入(自定义函数)
T.Lambda(lambda x: add_gaussian_noise(x, std=0.02)),
# 4. 归一化
T.ToTensor(),
T.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])