引言

计算机视觉(CV)是 AI 最成熟的落地领域之一:

  • 手机人脸解锁
  • 自动驾驶识别行人和车辆
  • 医学影像辅助诊断
  • 电商以图搜图
  • 短视频滤镜和特效

所有这些技术的底层都是图像处理。这篇文章从像素开始,带你走完”传统图像处理 → 深度学习特征提取 → CV 任务全景”的完整路径。


前置知识

看完 CNN 那篇再来,效果好一倍。


一、图像在计算机中的表示

1.1 一张图片 = 一个三维数组

1
2
3
灰度图 (Grayscale):    [H×W]         — 每个像素 0-255 的亮度值
彩色图 (RGB): [H×W×3] — 三个通道:红/绿/蓝
RGBA 图: [H×W×4] — 多一个 Alpha(透明度)

像素值范围通常是 0-255(8 位),深度学习会归一化到 0-1 或 -1~1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import cv2
import matplotlib.pyplot as plt
import numpy as np

# 读取图片
img = cv2.imread('example.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # OpenCV 默认 BGR,转成 RGB

print(f"图片形状: {img_rgb.shape}") # (height, width, channels)
print(f"数据类型: {img_rgb.dtype}") # uint8
print(f"像素范围: [{img_rgb.min()}, {img_rgb.max()}]")

plt.imshow(img_rgb)
plt.axis('off')
plt.show()

1.2 颜色空间

1
2
3
4
5
6
7
8
# 转灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# HSV(色调/饱和度/亮度 — 更符合人眼感知)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# LAB(亮度 + 两个颜色通道 — 色彩差异更均匀)
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)

为什么需要多种颜色空间?

  • RGB:显示器友好,但对光照敏感
  • HSV:做颜色分割最好用(比如检测红色物体)
  • LAB:计算颜色差异时最准确

二、传统图像处理操作

虽然深度学习已经替代了很多传统方法,但这些基础操作用来预处理数据、理解原理仍然很重要。

2.1 滤波与去噪

1
2
3
4
5
6
7
8
9
10
11
# 均值滤波(模糊)
blurred = cv2.blur(img, (5, 5))

# 高斯滤波(权重更自然)
gaussian = cv2.GaussianBlur(img, (5, 5), sigmaX=1.0)

# 中值滤波(对椒盐噪声特别有效)
median = cv2.medianBlur(img, 5)

# 双边滤波(保留边缘的平滑)
bilateral = cv2.bilateralFilter(img, 9, 75, 75)

2.2 边缘检测

1
2
3
4
5
6
7
# Canny 边缘检测(最经典)
edges = cv2.Canny(img, threshold1=100, threshold2=200)

# Sobel 梯度(分别计算 x 和 y 方向)
sobel_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
sobel_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
sobel_mag = np.sqrt(sobel_x**2 + sobel_y**2)

Canny 边缘检测的效果:(想象一下一张图片变成线稿的效果)

1
2
3
4
5
6
原图           →       Canny 边缘
┌─────────┐ ┌─────────────────┐
│ 一只猫 │ │ ╱╲ ╱╲ │
│ 坐在窗台 │ → │ ╱ ╲ ╱ ╲ │
│ 上晒太阳 │ ││ ████ │ │
└─────────┘ └─────────────────┘

2.3 形态学操作

1
2
3
4
5
6
7
8
9
10
11
12
13
kernel = np.ones((5, 5), np.uint8)

# 腐蚀(消除边界点,缩小白色区域)
eroded = cv2.erode(binary, kernel, iterations=1)

# 膨胀(扩大白色区域)
dilated = cv2.dilate(binary, kernel, iterations=1)

# 开运算(先腐蚀后膨胀 = 去除小噪点)
opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)

# 闭运算(先膨胀后腐蚀 = 填补小洞)
closing = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)

2.4 图像变换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 缩放
resized = cv2.resize(img, (224, 224))

# 旋转
(h, w) = img.shape[:2]
center = (w // 2, h // 2)
matrix = cv2.getRotationMatrix2D(center, 45, 1.0) # 旋转 45 度
rotated = cv2.warpAffine(img, matrix, (w, h))

# 仿射变换(通用矩阵变换)
matrix = np.float32([[1, 0.2, 0], [0.2, 1, 0]])
affined = cv2.warpAffine(img, matrix, (w, h))

# 透视变换(校正倾斜拍摄的文档)
pts1 = np.float32([[50,50], [200,50], [50,200], [200,200]])
pts2 = np.float32([[0,0], [300,0], [0,300], [300,300]])
matrix = cv2.getPerspectiveTransform(pts1, pts2)
warped = cv2.warpPerspective(img, matrix, (300, 300))

三、特征提取:从手工特征到深度学习

3.1 传统特征(深度学习之前)

1
2
3
4
5
6
7
8
9
10
# SIFT 关键点检测(尺度不变特征变换)
sift = cv2.SIFT_create()
keypoints, descriptors = sift.detectAndCompute(gray, None)

# ORB(更快但不那么鲁棒)
orb = cv2.ORB_create()
keypoints_orb, descriptors_orb = orb.detectAndCompute(gray, None)

# 在图像上画关键点
img_kp = cv2.drawKeypoints(img, keypoints, None)

SIFT 能检测出对旋转、缩放、光照都不敏感的关键点——这也正是 CNN 卷积核在做的事,只不过 CNN 用学习的方式找出了更好的特征。

3.2 深度学习特征

CNN 的每一层都在提取不同层次的”特征”:

卷积层 学到的特征 可视化
Layer 1 边缘、颜色、纹理 ▓ ▒ ░
Layer 2 角点、弧线、简单形状 ⬡ ◇ ○
Layer 3 眼睛、轮子、窗口(物体部件) 👁 ⚙ 🪟
Layer 4+ 人脸、汽车、建筑(完整物体) 🚗 🏠 👤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 用预训练 ResNet 提取特征
import torch
import torch.nn as nn
from torchvision import models, transforms
from PIL import Image

# 加载预训练模型(去掉最后的分类层)
resnet = models.resnet50(pretrained=True)
feature_extractor = nn.Sequential(*list(resnet.children())[:-1]) # 去掉全连接层
feature_extractor.eval()

# 预处理
transform = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])

img = Image.open('example.jpg')
input_tensor = transform(img).unsqueeze(0) # [1, 3, 224, 224]

# 提取特征
with torch.no_grad():
features = feature_extractor(input_tensor) # [1, 2048, 1, 1]

feature_vector = features.squeeze().numpy()
print(f"特征向量维度: {feature_vector.shape}") # (2048,)

这个 2048 维的向量就是 ResNet 对这张图片的”理解”——两张内容相似的图片,特征向量的距离应该很近。


四、CV 任务全景

4.1 六大核心任务

1
2
3
4
5
6
7
8
9
10
11
12
13
计算机视觉
├── 图像分类 ─── "这是什么?"
│ └── ResNet、EfficientNet、ViT
├── 目标检测 ─── "东西在哪?"
│ └── YOLO、Faster R-CNN、DETR
├── 语义分割 ─── "每个像素属于什么?"
│ └── U-Net、DeepLab
├── 实例分割 ─── "每个物体的轮廓?"
│ └── Mask R-CNN
├── 关键点检测 ─── "关节在哪?"
│ └── OpenPose、HRNet
└── 图像生成 ─── "画一张图"
└── GAN、Stable Diffusion、DALL·E

4.2 常用数据集

数据集 任务 规模 指标
ImageNet 分类 1400万张,1000类 Top-1 / Top-5
COCO 检测+分割 33万张,80类 mAP
CIFAR-10/100 分类 6万张,10/100类 Accuracy
MNIST 分类 7万张,10类 Accuracy
Cityscapes 语义分割 5000张街景 mIoU

4.3 CV 领域的”ImageNet 时刻”

1
2
3
4
5
6
7
8
9
AlexNet (2012) → 超越传统方法,深度学习时代开启
VGG (2014) → 更深的网络,模块化设计
ResNet (2015) → 残差连接,152 层也训得动
YOLO (2016) → 实时目标检测
GAN (2014-2018) → 图像生成
ViT (2020) → Transformer 打败 CNN
CLIP (2021) → 图文多模态
SAM (2023) → 通用分割模型
Stable Diffusion (2022-2026) → 文生图主流

五、数据增强

数据增强是 CV 项目中最有效的”免费午餐”——不需要新数据,通过变换现有数据来提升泛化能力。

1
2
3
4
5
6
7
8
9
10
11
12
from torchvision import transforms

train_transform = transforms.Compose([
transforms.RandomResizedCrop(224), # 随机裁剪和缩放
transforms.RandomHorizontalFlip(), # 随机水平翻转
transforms.ColorJitter(0.2, 0.2, 0.2), # 随机颜色变化
transforms.RandomAffine(degrees=10, # 随机旋转+平移
translate=(0.1, 0.1)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]),
])

常用增强策略:

  • 几何变换:翻转、旋转、裁剪、缩放
  • 颜色变换:亮度、对比度、饱和度
  • 噪声:高斯噪声、椒盐噪声
  • 高级:Cutout(随机遮挡)、MixUp(混合两张图)、CutMix

六、总结

知识点 掌握
图像在计算机中的表示(RGB/灰度/H×W×C)
OpenCV 基础操作(滤波/边缘/形态学)
传统特征 vs 深度学习特征
用预训练 CNN 提取特征向量
CV 六大任务与经典模型
数据增强方法与策略

下一步推荐: