08. 计算机视觉进阶

计算机视觉深度解析:YOLO 系列、图像分割、OCR 文字识别与生成模型 GAN/Diffusion

计算机视觉让机器"看懂"世界,涵盖目标检测、图像分割、文字识别与图像生成。本文深入讲解 YOLO 系列演进、实例分割、OCR 全栈方案与生成对抗网络。

1. 目标检测:YOLO 系列

1.1 YOLOv8 使用

YOLO (You Only Look Once) 是实时目标检测的代表,将检测视为回归问题。

from ultralytics import YOLO

# 加载预训练模型
model = YOLO('yolov8n.pt')  # nano 版本,轻量快速

# 目标检测
results = model('image.jpg')
for r in results:
    boxes = r.boxes  # 边界框
    for box in boxes:
        cls = int(box.cls)          # 类别
        conf = float(box.conf)       # 置信度
        xyxy = box.xyxy[0].tolist()  # [x1, y1, x2, y2]
        print(f"类别: {model.names[cls]}, 置信度: {conf:.3f}, 位置: {xyxy}")

# 训练自定义数据集
model = YOLO('yolov8n.pt')
model.train(data='custom_data.yaml', epochs=100, imgsz=640)

# 导出 ONNX
model.export(format='onnx')

1.2 YOLO 系列演进

版本年份核心改进mAPFPS
YOLOv12016单阶段检测开创63.445
YOLOv32018多尺度预测、Darknet-5357.945
YOLOv52020PyTorch 实现、AutoAnchor50.7140
YOLOv82023Anchor-Free、解耦头53.9150
YOLOv102024NMS-Free、一致性分配54.4200+

1.3 检测输出格式

# COCO 格式
{
    "image_id": 1,
    "category_id": 1,  # person=1
    "bbox": [x, y, width, height],  # 左上角 + 宽高
    "score": 0.95,
    "area": width * height
}

# Pascal VOC 格式
# xmin, ymin, xmax, ymax

1.4 评估指标

指标定义
IoU交并比 = 预测框 ∩ 真实框 / 预测框 ∪ 真实框
mAP@0.5IoU=0.5 时的平均精度
mAP@0.5:0.95IoU 从 0.5 到 0.95 步进 0.05 的平均
AP50/AP75IoU=0.5/0.75 时的 AP
from ultralytics.utils.metrics import bbox_iou

iou = bbox_iou(pred_box, true_box, xywh=True, CIoU=True)

2. 图像分割

2.1 语义分割

为每个像素分配类别标签。

from torchvision.models.segmentation import fcn_resnet50, deeplabv3_resnet50

# DeepLabV3+
model = deeplabv3_resnet50(pretrained=True)
model.eval()

# 输入图像
from torchvision import transforms
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], 
                        std=[0.229, 0.224, 0.225])
])

input_tensor = transform(image).unsqueeze(0)
output = model(input_tensor)['out']  # (1, 21, H, W)
predictions = output.argmax(1)       # 每个像素的类别

2.2 实例分割

区分同类别的不同实例。

from torchvision.models.detection import maskrcnn_resnet50_fpn

model = maskrcnn_resnet50_fpn(pretrained=True)
model.eval()

predictions = model([transform(image)])
# predictions[0]['boxes']: 边界框
# predictions[0]['labels']: 类别
# predictions[0]['scores']: 置信度
# predictions[0]['masks']: 分割掩膜 (N, 1, H, W)

2.3 U-Net 详解

import torch.nn as nn

class UNet(nn.Module):
    def __init__(self, in_channels=3, out_channels=1):
        super().__init__()
        
        # 编码器
        self.enc1 = self.conv_block(in_channels, 64)
        self.enc2 = self.conv_block(64, 128)
        self.enc3 = self.conv_block(128, 256)
        self.enc4 = self.conv_block(256, 512)
        self.pool = nn.MaxPool2d(2)
        
        # 瓶颈
        self.bottleneck = self.conv_block(512, 1024)
        
        # 解码器
        self.up4 = nn.ConvTranspose2d(1024, 512, 2, stride=2)
        self.dec4 = self.conv_block(1024, 512)
        self.up3 = nn.ConvTranspose2d(512, 256, 2, stride=2)
        self.dec3 = self.conv_block(512, 256)
        self.up2 = nn.ConvTranspose2d(256, 128, 2, stride=2)
        self.dec2 = self.conv_block(256, 128)
        self.up1 = nn.ConvTranspose2d(128, 64, 2, stride=2)
        self.dec1 = self.conv_block(128, 64)
        
        self.final = nn.Conv2d(64, out_channels, 1)
    
    def conv_block(self, in_ch, out_ch):
        return nn.Sequential(
            nn.Conv2d(in_ch, out_ch, 3, padding=1),
            nn.BatchNorm2d(out_ch),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_ch, out_ch, 3, padding=1),
            nn.BatchNorm2d(out_ch),
            nn.ReLU(inplace=True)
        )
    
    def forward(self, x):
        # 编码
        e1 = self.enc1(x)
        e2 = self.enc2(self.pool(e1))
        e3 = self.enc3(self.pool(e2))
        e4 = self.enc4(self.pool(e3))
        
        # 瓶颈
        b = self.bottleneck(self.pool(e4))
        
        # 解码 + Skip Connection
        d4 = self.up4(b)
        d4 = torch.cat([d4, e4], dim=1)
        d4 = self.dec4(d4)
        
        d3 = self.up3(d4)
        d3 = torch.cat([d3, e3], dim=1)
        d3 = self.dec3(d3)
        
        d2 = self.up2(d3)
        d2 = torch.cat([d2, e2], dim=1)
        d2 = self.dec2(d2)
        
        d1 = self.up1(d2)
        d1 = torch.cat([d1, e1], dim=1)
        d1 = self.dec1(d1)
        
        return self.final(d1)

3. OCR 文字识别

3.1 OCR Pipeline

图像 → 文字检测 → 文字识别 → 后处理 → 结构化输出
        ↑_____ PaddleOCR/EasyOCR ____↑
from paddleocr import PaddleOCR

# 初始化
ocr = PaddleOCR(use_angle_cls=True, lang='ch', 
                det_model_dir='./models/det',
                rec_model_dir='./models/rec')

# 识别
result = ocr.ocr('document.jpg', cls=True)

for line in result[0]:
    box = line[0]      # 文字框坐标
    text = line[1][0]  # 识别文本
    confidence = line[1][1]
    print(f"文本: {text}, 置信度: {confidence:.3f}")

3.2 EasyOCR

import easyocr

reader = easyocr.Reader(['ch_sim', 'en'])
results = reader.readtext('image.jpg')

for (bbox, text, conf) in results:
    print(f"{text} ({conf:.2f})")

3.3 自定义 OCR 训练

# 使用 PaddleOCR 训练自定义数据集
# 数据格式:
# image_path\t[{transcription: "文字", points: [[x1,y1],...]}]

# 检测模型训练
!python tools/train.py -c configs/det/ch_PP-OCRv4/ch_PP-OCRv4_det_student.yml

# 识别模型训练
!python tools/train.py -c configs/rec/PP-OCRv4/ch_PP-OCRv4_rec.yml

4. 生成模型

4.1 GAN:生成对抗网络

生成器 G 和判别器 D 的对抗博弈:

$$\min_G \max_D V(D, G) = E[\log D(x)] + E[\log(1 - D(G(z)))]$$

import torch.nn as nn

# 生成器
class Generator(nn.Module):
    def __init__(self, latent_dim=100, img_size=28):
        super().__init__()
        self.model = nn.Sequential(
            nn.Linear(latent_dim, 256),
            nn.LeakyReLU(0.2),
            nn.BatchNorm1d(256),
            nn.Linear(256, 512),
            nn.LeakyReLU(0.2),
            nn.BatchNorm1d(512),
            nn.Linear(512, 1024),
            nn.LeakyReLU(0.2),
            nn.BatchNorm1d(1024),
            nn.Linear(1024, img_size * img_size),
            nn.Tanh()
        )
    
    def forward(self, z):
        img = self.model(z)
        return img.view(img.size(0), 1, 28, 28)

# 判别器
class Discriminator(nn.Module):
    def __init__(self, img_size=28):
        super().__init__()
        self.model = nn.Sequential(
            nn.Linear(img_size * img_size, 512),
            nn.LeakyReLU(0.2),
            nn.Linear(512, 256),
            nn.LeakyReLU(0.2),
            nn.Linear(256, 1),
            nn.Sigmoid()
        )
    
    def forward(self, img):
        flat = img.view(img.size(0), -1)
        return self.model(flat)

# 训练循环
def train_gan(generator, discriminator, dataloader, epochs=50):
    g_optimizer = torch.optim.Adam(generator.parameters(), lr=0.0002)
    d_optimizer = torch.optim.Adam(discriminator.parameters(), lr=0.0002)
    criterion = nn.BCELoss()
    
    for epoch in range(epochs):
        for real_imgs, _ in dataloader:
            batch_size = real_imgs.size(0)
            
            # 标签
            real = torch.ones(batch_size, 1)
            fake = torch.zeros(batch_size, 1)
            
            # 训练判别器
            d_optimizer.zero_grad()
            real_loss = criterion(discriminator(real_imgs), real)
            
            z = torch.randn(batch_size, 100)
            fake_imgs = generator(z)
            fake_loss = criterion(discriminator(fake_imgs.detach()), fake)
            
            d_loss = (real_loss + fake_loss) / 2
            d_loss.backward()
            d_optimizer.step()
            
            # 训练生成器
            g_optimizer.zero_grad()
            g_loss = criterion(discriminator(fake_imgs), real)
            g_loss.backward()
            g_optimizer.step()

4.2 条件 GAN (CGAN)

# 将类别标签作为输入条件
class ConditionalGenerator(nn.Module):
    def __init__(self, latent_dim, num_classes, img_size):
        super().__init__()
        self.label_emb = nn.Embedding(num_classes, num_classes)
        self.model = nn.Sequential(
            nn.Linear(latent_dim + num_classes, 256),
            # ...
        )
    
    def forward(self, z, labels):
        label_input = self.label_emb(labels)
        x = torch.cat([z, label_input], dim=1)
        return self.model(x)

4.3 Diffusion Models

扩散模型通过逐步去噪从随机噪声生成图像,是当前最高质量的生成方法。

from diffusers import StableDiffusionPipeline
import torch

# 加载 Stable Diffusion
pipe = StableDiffusionPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    torch_dtype=torch.float16
).to("cuda")

# 文生图
prompt = "A beautiful sunset over mountains, digital art"
image = pipe(prompt, num_inference_steps=50, guidance_scale=7.5).images[0]
image.save("output.png")

# 图生图
from diffusers import StableDiffusionImg2ImgPipeline

pipe_img2img = StableDiffusionImg2ImgPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5",
    torch_dtype=torch.float16
).to("cuda")

init_image = Image.open("input.jpg").convert("RGB").resize((512, 512))
image = pipe_img2img(prompt="turn this into anime style", 
                     image=init_image, strength=0.7).images[0]

4.4 扩散模型原理

前向扩散:逐步向图像添加高斯噪声

$$q(x_t | x_{t-1}) = \mathcal{N}(x_t; \sqrt{1-\beta_t}x_{t-1}, \beta_t I)$$

反向去噪:学习神经网络预测噪声,逐步去噪

$$p_\theta(x_{t-1}|x_t) = \mathcal{N}(x_{t-1}; \mu_\theta(x_t, t), \Sigma_\theta(x_t, t))$$

5. 视频理解

5.1 视频动作识别

from torchvision.models.video import r3d_18, mc3_18

model = r3d_18(pretrained=True)
# 输入: (batch, channels, frames, height, width)
# r3d_18: (N, 3, 16, 112, 112)

5.2 目标跟踪

from ultralytics import YOLO

model = YOLO('yolov8n.pt')
results = model.track(source='video.mp4', show=True, tracker="bytetrack.yaml")

6. 模型部署优化

优化方案方法加速比
量化INT8/FP162-4x
剪枝移除不重要的权重2-10x
知识蒸馏大模型 → 小模型保持精度
TensorRTNVIDIA 专用优化5-10x
ONNX Runtime跨平台推理2-3x
# TensorRT 导出
import torch
from torch2trt import torch2trt

model = YOLO('yolov8n.pt').model
x = torch.ones((1, 3, 640, 640)).cuda()
model_trt = torch2trt(model, [x])
torch.save(model_trt.state_dict(), "yolov8n_trt.pth")

总结

计算机视觉任务速查:

任务推荐方案关键模型
目标检测YOLOv8 / RT-DETRYOLOv8n/s/m/l/x
语义分割DeepLabV3+ / U-NetResNet + ASPP
实例分割Mask R-CNNFaster R-CNN + Mask Head
OCRPaddleOCR / EasyOCRPP-OCRv4
图像生成Stable DiffusionU-Net + CLIP
视频分析SlowFast / X3D3D CNN

工程实践:

  • 检测任务优先考虑实时性,选 YOLO;高精度需求选两阶段检测器
  • 分割任务 U-Net 是基线,DeepLabV3+ 是 SOTA 选择
  • OCR 直接使用 PaddleOCR,支持中英文且可自定义训练
  • 生成模型 Stable Diffusion 是开源首选,ControlNet 提供可控生成
  • 部署时用 TensorRT/OpenVINO 加速,INT8 量化减少显存占用

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「ai-ml」更多文章

  1. 13. 大语言模型应用开发
  2. 12. MLOps 与实验管理
  3. 11. 模型部署与推理优化