计算机视觉完整学习路径:从CNN到Transformer的实战指南

最近在辅导一些刚入门计算机视觉的同学时,发现大家普遍面临一个困境:网上资料零散不成体系,从CNN基础到Transformer进阶缺少一条清晰的学习路径。本文基于2026年最新技术趋势,系统梳理从CNN图像分类到U-Net分割,再到ResNet迁移学习与Transformer主流网络的完整知识体系,包含大量可运行的代码示例和项目实战。

无论你是零基础初学者,还是有一定经验想系统提升的开发者,都能通过本文建立完整的计算机视觉知识框架,掌握各主流网络的实现原理和实战技巧。

1. 计算机视觉基础与核心概念

1.1 什么是计算机视觉

计算机视觉是让机器"看懂"图像和视频的科学。从简单的图像分类到复杂的自动驾驶场景理解,计算机视觉技术已经深入到我们生活的方方面面。传统的图像处理方法依赖手工设计的特征提取器,而现代计算机视觉则主要基于深度学习技术。

深度学习在计算机视觉中的优势在于能够自动从数据中学习特征表示,无需人工设计特征提取器。这种端到端的学习方式大大提升了模型的性能和泛化能力。

1.2 计算机视觉的主要任务

图像分类是计算机视觉中最基础的任务,目标是将图像划分到预定义的类别中。比如识别一张图片中是猫还是狗。图像分类为后续更复杂的任务奠定了基础。

目标检测不仅要识别图像中的物体类别,还要定位物体的位置,通常用边界框表示。常见的应用包括人脸检测、车辆检测等。

语义分割需要对图像中的每个像素进行分类,将图像分割成具有语义意义的区域。这在医疗影像分析、自动驾驶等领域有重要应用。

实例分割是目标检测和语义分割的结合,既要检测出每个物体实例,又要对每个实例进行像素级分割。

1.3 深度学习在计算机视觉中的发展历程

2012年AlexNet在ImageNet竞赛中的突破性表现标志着深度学习在计算机视觉领域的崛起。随后,VGG、GoogLeNet、ResNet等网络架构不断推陈出新,在准确率和效率方面都取得了显著提升。

2020年后,Transformer架构从自然语言处理领域迁移到计算机视觉领域,出现了Vision Transformer等模型,开启了视觉领域的新篇章。如今,卷积神经网络与Transformer的融合成为主流趋势。

2. 环境准备与工具配置

2.1 基础环境搭建

进行计算机视觉开发,首先需要配置合适的编程环境。推荐使用Python 3.8+版本,配合PyTorch或TensorFlow深度学习框架。

# 创建conda环境 conda create -n cv-tutorial python=3.8 conda activate cv-tutorial # 安装PyTorch(根据CUDA版本选择) pip install torch torchvision torchaudio # 或者安装TensorFlow pip install tensorflow # 安装计算机视觉相关库 pip install opencv-python pillow matplotlib numpy scikit-learn

2.2 开发工具配置

Jupyter Notebook适合进行实验和可视化,PyCharm或VS Code适合大型项目开发。建议配置GPU环境以加速模型训练,对于初学者,可以使用Google Colab提供的免费GPU资源。

# 检查GPU是否可用 import torch print(f"PyTorch版本: {torch.__version__}") print(f"CUDA是否可用: {torch.cuda.is_available()}") if torch.cuda.is_available(): print(f"GPU设备: {torch.cuda.get_device_name(0)}")

2.3 数据集准备

计算机视觉项目需要大量的图像数据。常用的公开数据集包括:

  • MNIST:手写数字识别
  • CIFAR-10/100:物体分类
  • ImageNet:大规模图像分类
  • COCO:目标检测和分割

3. CNN卷积神经网络详解

3.1 卷积操作基本原理

卷积是CNN的核心操作,它通过滑动窗口的方式在图像上提取特征。每个卷积核负责检测一种特定的特征模式,如边缘、纹理等。

import torch import torch.nn as nn import torch.nn.functional as F # 简单的卷积操作示例 class SimpleCNN(nn.Module): def __init__(self): super(SimpleCNN, self).__init__() # 输入通道1,输出通道32,卷积核3x3 self.conv1 = nn.Conv2d(1, 32, 3, padding=1) self.conv2 = nn.Conv2d(32, 64, 3, padding=1) self.pool = nn.MaxPool2d(2, 2) self.fc1 = nn.Linear(64 * 7 * 7, 128) self.fc2 = nn.Linear(128, 10) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) # 28x28 -> 14x14 x = self.pool(F.relu(self.conv2(x))) # 14x14 -> 7x7 x = x.view(-1, 64 * 7 * 7) # 展平 x = F.relu(self.fc1(x)) x = self.fc2(x) return x # 测试网络 model = SimpleCNN() print(model)

3.2 池化层与激活函数

池化层主要用于降维和保持平移不变性,常见的池化操作包括最大池化和平均池化。激活函数引入非线性,使网络能够学习复杂模式,ReLU是目前最常用的激活函数。

3.3 经典CNN架构分析

LeNet-5是早期的CNN成功案例,用于手写数字识别。AlexNet首次在现代GPU上成功训练深度网络,VGGNet通过使用小卷积核堆叠深层次网络,GoogleNet引入Inception模块提高参数效率。

# VGG风格网络实现 class VGGStyle(nn.Module): def __init__(self, num_classes=10): super(VGGStyle, self).__init__() self.features = nn.Sequential( # 第一个卷积块 nn.Conv2d(3, 64, 3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(64, 64, 3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2), # 第二个卷积块 nn.Conv2d(64, 128, 3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(128, 128, 3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(2, 2), ) self.classifier = nn.Sequential( nn.Linear(128 * 8 * 8, 512), nn.ReLU(inplace=True), nn.Dropout(0.5), nn.Linear(512, num_classes) ) def forward(self, x): x = self.features(x) x = x.view(x.size(0), -1) x = self.classifier(x) return x

4. ResNet残差网络与迁移学习

4.1 残差连接原理

随着网络深度增加,梯度消失和梯度爆炸问题变得严重。ResNet通过引入残差连接(skip connection)解决了深层网络训练困难的问题。

残差块的基本思想是学习输入与输出之间的残差(差值),而不是直接学习目标映射。这样即使深层网络的权重很小,信息也能通过快捷连接直接传递。

4.2 ResNet架构实现

import torch import torch.nn as nn class BasicBlock(nn.Module): expansion = 1 def __init__(self, in_planes, planes, stride=1): super(BasicBlock, self).__init__() self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) self.bn1 = nn.BatchNorm2d(planes) self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) self.bn2 = nn.BatchNorm2d(planes) self.shortcut = nn.Sequential() if stride != 1 or in_planes != self.expansion * planes: self.shortcut = nn.Sequential( nn.Conv2d(in_planes, self.expansion * planes, kernel_size=1, stride=stride, bias=False), nn.BatchNorm2d(self.expansion * planes) ) def forward(self, x): out = F.relu(self.bn1(self.conv1(x))) out = self.bn2(self.conv2(out)) out += self.shortcut(x) # 残差连接 out = F.relu(out) return out class ResNet(nn.Module): def __init__(self, block, num_blocks, num_classes=10): super(ResNet, self).__init__() self.in_planes = 64 self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False) self.bn1 = nn.BatchNorm2d(64) self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1) self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) self.linear = nn.Linear(512 * block.expansion, num_classes) def _make_layer(self, block, planes, num_blocks, stride): strides = [stride] + [1] * (num_blocks - 1) layers = [] for stride in strides: layers.append(block(self.in_planes, planes, stride)) self.in_planes = planes * block.expansion return nn.Sequential(*layers) def forward(self, x): out = F.relu(self.bn1(self.conv1(x))) out = self.layer1(out) out = self.layer2(out) out = self.layer3(out) out = self.layer4(out) out = F.avg_pool2d(out, 4) out = out.view(out.size(0), -1) out = self.linear(out) return out def ResNet18(): return ResNet(BasicBlock, [2, 2, 2, 2])

4.3 迁移学习实战

迁移学习允许我们利用在大型数据集上预训练的模型,将其知识迁移到新的任务中。这种方法特别适合数据量较小的场景。

import torchvision.models as models import torch.optim as optim from torch.optim import lr_scheduler def setup_transfer_learning(num_classes, feature_extract=True): # 加载预训练模型 model = models.resnet18(pretrained=True) if feature_extract: # 冻结所有参数 for param in model.parameters(): param.requires_grad = False # 修改最后一层全连接层 num_features = model.fc.in_features model.fc = nn.Linear(num_features, num_classes) return model # 训练函数 def train_model(model, dataloaders, criterion, optimizer, scheduler, num_epochs=25): best_model_wts = copy.deepcopy(model.state_dict()) best_acc = 0.0 for epoch in range(num_epochs): print(f'Epoch {epoch}/{num_epochs - 1}') print('-' * 10) # 每个epoch都有训练和验证阶段 for phase in ['train', 'val']: if phase == 'train': model.train() # 训练模式 else: model.eval() # 评估模式 running_loss = 0.0 running_corrects = 0 # 迭代数据 for inputs, labels in dataloaders[phase]: inputs = inputs.to(device) labels = labels.to(device) # 梯度清零 optimizer.zero_grad() # 前向传播 with torch.set_grad_enabled(phase == 'train'): outputs = model(inputs) _, preds = torch.max(outputs, 1) loss = criterion(outputs, labels) # 反向传播+优化只在训练阶段进行 if phase == 'train': loss.backward() optimizer.step() # 统计 running_loss += loss.item() * inputs.size(0) running_corrects += torch.sum(preds == labels.data) if phase == 'train': scheduler.step() epoch_loss = running_loss / len(dataloaders[phase].dataset) epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset) print(f'{phase} Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}') # 深度拷贝模型 if phase == 'val' and epoch_acc > best_acc: best_acc = epoch_acc best_model_wts = copy.deepcopy(model.state_dict()) print() # 加载最佳模型权重 model.load_state_dict(best_model_wts) return model

5. U-Net图像分割网络

5.1 U-Net架构原理

U-Net是医学图像分割领域的经典网络,采用编码器-解码器结构,通过跳跃连接将底层细节信息与高层语义信息融合。

编码器部分通过卷积和池化逐步提取特征,减少空间维度同时增加通道数。解码器部分通过上采样恢复空间分辨率,跳跃连接帮助保留细节信息。

5.2 U-Net完整实现

import torch import torch.nn as nn class DoubleConv(nn.Module): """(卷积 => [BN] => ReLU) * 2""" def __init__(self, in_channels, out_channels): super().__init__() self.double_conv = nn.Sequential( nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1), nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True), nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1), nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True) ) def forward(self, x): return self.double_conv(x) class Down(nn.Module): """下采样模块:最大池化 + 双卷积""" def __init__(self, in_channels, out_channels): super().__init__() self.maxpool_conv = nn.Sequential( nn.MaxPool2d(2), DoubleConv(in_channels, out_channels) ) def forward(self, x): return self.maxpool_conv(x) class Up(nn.Module): """上采样模块""" def __init__(self, in_channels, out_channels, bilinear=True): super().__init__() if bilinear: self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True) self.conv = DoubleConv(in_channels, out_channels) else: self.up = nn.ConvTranspose2d(in_channels, in_channels // 2, kernel_size=2, stride=2) self.conv = DoubleConv(in_channels, out_channels) def forward(self, x1, x2): x1 = self.up(x1) # 输入是CHW diffY = x2.size()[2] - x1.size()[2] diffX = x2.size()[3] - x1.size()[3] x1 = F.pad(x1, [diffX // 2, diffX - diffX // 2, diffY // 2, diffY - diffY // 2]) x = torch.cat([x2, x1], dim=1) return self.conv(x) class OutConv(nn.Module): def __init__(self, in_channels, out_channels): super(OutConv, self).__init__() self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=1) def forward(self, x): return self.conv(x) class UNet(nn.Module): def __init__(self, n_channels, n_classes, bilinear=True): super(UNet, self).__init__() self.n_channels = n_channels self.n_classes = n_classes self.bilinear = bilinear self.inc = DoubleConv(n_channels, 64) self.down1 = Down(64, 128) self.down2 = Down(128, 256) self.down3 = Down(256, 512) factor = 2 if bilinear else 1 self.down4 = Down(512, 1024 // factor) self.up1 = Up(1024, 512 // factor, bilinear) self.up2 = Up(512, 256 // factor, bilinear) self.up3 = Up(256, 128 // factor, bilinear) self.up4 = Up(128, 64, bilinear) self.outc = OutConv(64, n_classes) def forward(self, x): x1 = self.inc(x) x2 = self.down1(x1) x3 = self.down2(x2) x4 = self.down3(x3) x5 = self.down4(x4) x = self.up1(x5, x4) x = self.up2(x, x3) x = self.up3(x, x2) x = self.up4(x, x1) logits = self.outc(x) return logits # 使用示例 model = UNet(n_channels=3, n_classes=1) print(f"模型参数量: {sum(p.numel() for p in model.parameters())}")

5.3 医学图像分割实战

U-Net在医学影像分割中表现优异,下面展示一个细胞核分割的完整流程:

import numpy as np from torch.utils.data import Dataset, DataLoader from sklearn.model_selection import train_test_split class MedicalDataset(Dataset): def __init__(self, images, masks, transform=None): self.images = images self.masks = masks self.transform = transform def __len__(self): return len(self.images) def __getitem__(self, idx): image = self.images[idx] mask = self.masks[idx] if self.transform: augmented = self.transform(image=image, mask=mask) image = augmented['image'] mask = augmented['mask'] return image, mask def train_unet(): # 数据准备 # 这里假设已经有预处理好的图像和掩码数据 # images, masks = load_medical_data() # 分割训练集和测试集 # train_images, val_images, train_masks, val_masks = train_test_split( # images, masks, test_size=0.2, random_state=42) # 创建数据集和数据加载器 # train_dataset = MedicalDataset(train_images, train_masks, transform=train_transform) # val_dataset = MedicalDataset(val_images, val_masks, transform=val_transform) # train_loader = DataLoader(train_dataset, batch_size=8, shuffle=True) # val_loader = DataLoader(val_dataset, batch_size=8, shuffle=False) model = UNet(n_channels=3, n_classes=1) criterion = nn.BCEWithLogitsLoss() optimizer = torch.optim.Adam(model.parameters(), lr=1e-4) # 训练循环 for epoch in range(100): model.train() epoch_loss = 0 for batch_idx, (data, target) in enumerate(train_loader): optimizer.zero_grad() output = model(data) loss = criterion(output, target) loss.backward() optimizer.step() epoch_loss += loss.item() # 验证阶段 model.eval() val_loss = 0 with torch.no_grad(): for data, target in val_loader: output = model(data) val_loss += criterion(output, target).item() print(f'Epoch {epoch}, Train Loss: {epoch_loss/len(train_loader):.4f}, ' f'Val Loss: {val_loss/len(val_loader):.4f}')

6. Transformer在计算机视觉中的应用

6.1 Vision Transformer原理

Vision Transformer将图像分割成固定大小的patch,将每个patch线性映射为向量序列,然后输入到标准的Transformer编码器中。这种架构能够捕捉长距离依赖关系,在图像分类任务中表现出色。

import torch import torch.nn as nn import math class PatchEmbedding(nn.Module): """将图像分割成patch并嵌入""" def __init__(self, img_size=224, patch_size=16, in_chans=3, embed_dim=768): super().__init__() self.img_size = img_size self.patch_size = patch_size self.n_patches = (img_size // patch_size) ** 2 self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_size, stride=patch_size) def forward(self, x): x = self.proj(x) # (B, E, H/P, W/P) x = x.flatten(2) # (B, E, N) x = x.transpose(1, 2) # (B, N, E) return x class MultiHeadAttention(nn.Module): """多头自注意力机制""" def __init__(self, dim, num_heads=8, qkv_bias=False, attn_drop=0., proj_drop=0.): super().__init__() self.num_heads = num_heads head_dim = dim // num_heads self.scale = head_dim ** -0.5 self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias) self.attn_drop = nn.Dropout(attn_drop) self.proj = nn.Linear(dim, dim) self.proj_drop = nn.Dropout(proj_drop) def forward(self, x): B, N, C = x.shape qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4) q, k, v = qkv[0], qkv[1], qkv[2] attn = (q @ k.transpose(-2, -1)) * self.scale attn = attn.softmax(dim=-1) attn = self.attn_drop(attn) x = (attn @ v).transpose(1, 2).reshape(B, N, C) x = self.proj(x) x = self.proj_drop(x) return x class MLP(nn.Module): """多层感知机""" def __init__(self, in_features, hidden_features=None, out_features=None, drop=0.): super().__init__() out_features = out_features or in_features hidden_features = hidden_features or in_features self.fc1 = nn.Linear(in_features, hidden_features) self.act = nn.GELU() self.fc2 = nn.Linear(hidden_features, out_features) self.drop = nn.Dropout(drop) def forward(self, x): x = self.fc1(x) x = self.act(x) x = self.drop(x) x = self.fc2(x) x = self.drop(x) return x class TransformerBlock(nn.Module): """Transformer块""" def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, drop=0., attn_drop=0.): super().__init__() self.norm1 = nn.LayerNorm(dim) self.attn = MultiHeadAttention(dim, num_heads=num_heads, qkv_bias=qkv_bias, attn_drop=attn_drop, proj_drop=drop) self.norm2 = nn.LayerNorm(dim) mlp_hidden_dim = int(dim * mlp_ratio) self.mlp = MLP(in_features=dim, hidden_features=mlp_hidden_dim, drop=drop) def forward(self, x): x = x + self.attn(self.norm1(x)) x = x + self.mlp(self.norm2(x)) return x class VisionTransformer(nn.Module): """完整的Vision Transformer模型""" def __init__(self, img_size=224, patch_size=16, in_chans=3, num_classes=1000, embed_dim=768, depth=12, num_heads=12, mlp_ratio=4., qkv_bias=True, drop_rate=0., attn_drop_rate=0.): super().__init__() self.num_classes = num_classes self.num_features = self.embed_dim = embed_dim self.patch_embed = PatchEmbedding(img_size, patch_size, in_chans, embed_dim) num_patches = self.patch_embed.n_patches self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim)) self.pos_embed = nn.Parameter(torch.zeros(1, num_patches + 1, embed_dim)) self.pos_drop = nn.Dropout(p=drop_rate) self.blocks = nn.ModuleList([ TransformerBlock(dim=embed_dim, num_heads=num_heads, mlp_ratio=mlp_ratio, qkv_bias=qkv_bias, drop=drop_rate, attn_drop=attn_drop_rate) for i in range(depth)]) self.norm = nn.LayerNorm(embed_dim) self.head = nn.Linear(embed_dim, num_classes) if num_classes > 0 else nn.Identity() # 初始化权重 nn.init.trunc_normal_(self.pos_embed, std=0.02) nn.init.trunc_normal_(self.cls_token, std=0.02) self.apply(self._init_weights) def _init_weights(self, m): if isinstance(m, nn.Linear): nn.init.trunc_normal_(m.weight, std=0.02) if m.bias is not None: nn.init.constant_(m.bias, 0) elif isinstance(m, nn.LayerNorm): nn.init.constant_(m.bias, 0) nn.init.constant_(m.weight, 1.0) def forward(self, x): B = x.shape[0] x = self.patch_embed(x) cls_tokens = self.cls_token.expand(B, -1, -1) x = torch.cat((cls_tokens, x), dim=1) x = x + self.pos_embed x = self.pos_drop(x) for blk in self.blocks: x = blk(x) x = self.norm(x) x = x[:, 0] # 取cls token对应的输出 x = self.head(x) return x # 使用示例 vit = VisionTransformer(img_size=224, patch_size=16, num_classes=10, embed_dim=768, depth=12, num_heads=12) print(f"ViT参数量: {sum(p.numel() for p in vit.parameters())}")

6.2 Swin Transformer架构

Swin Transformer通过引入分层设计和滑动窗口注意力,解决了ViT计算复杂度高和缺乏平移不变性的问题,在各类视觉任务中表现出色。

class SwinTransformerBlock(nn.Module): """Swin Transformer块""" def __init__(self, dim, input_resolution, num_heads, window_size=7, shift_size=0): super().__init__() self.dim = dim self.input_resolution = input_resolution self.num_heads = num_heads self.window_size = window_size self.shift_size = shift_size if min(self.input_resolution) <= self.window_size: self.shift_size = 0 self.window_size = min(self.input_resolution) self.attn = WindowAttention(dim, window_size, num_heads) self.norm1 = nn.LayerNorm(dim) self.mlp = MLP(dim, int(dim * 4)) self.norm2 = nn.LayerNorm(dim) def forward(self, x): H, W = self.input_resolution B, L, C = x.shape shortcut = x x = self.norm1(x) x = x.view(B, H, W, C) # 滑动窗口分割 if self.shift_size > 0: shifted_x = torch.roll(x, shifts=(-self.shift_size, -self.shift_size), dims=(1, 2)) else: shifted_x = x # 窗口注意力 x_windows = window_partition(shifted_x, self.window_size) attn_windows = self.attn(x_windows) shifted_x = window_reverse(attn_windows, self.window_size, H, W) if self.shift_size > 0: x = torch.roll(shifted_x, shifts=(self.shift_size, self.shift_size), dims=(1, 2)) else: x = shifted_x x = x.view(B, H * W, C) x = shortcut + x # MLP x = x + self.mlp(self.norm2(x)) return x

7. 混合架构与最新进展

7.1 ConvNeXt与ACC-UNet

ConvNeXt通过将现代Transformer的设计理念应用到CNN中,证明了纯卷积网络仍然具有竞争力。ACC-UNet在此基础上进一步优化,在医学图像分割任务中超越了基于Transformer的模型。

class ACCUNetBlock(nn.Module): """ACC-UNet中的改进卷积块""" def __init__(self, in_channels, out_channels, k=3): super().__init__() # 倒残差结构 self.conv1 = nn.Conv2d(in_channels, out_channels * 4, 1) self.dwconv = nn.Conv2d(out_channels * 4, out_channels * 4, k, padding=k//2, groups=out_channels * 4) self.conv2 = nn.Conv2d(out_channels * 4, out_channels, 1) self.norm = nn.BatchNorm2d(out_channels) self.act = nn.GELU() def forward(self, x): identity = x # 倒残差结构 x = self.conv1(x) x = self.dwconv(x) x = self.conv2(x) x = self.norm(x) x = self.act(x) # 残差连接 if identity.shape == x.shape: x = x + identity return x

7.2 模型选择指南

在选择计算机视觉模型时,需要考虑多个因素:

数据量大小:小数据集适合使用预训练模型进行迁移学习,大数据集可以训练更复杂的模型。

计算资源:Transformer模型通常需要更多计算资源,CNN在资源受限环境下更有优势。

任务类型:分类任务ViT表现优异,分割任务U-Net系列仍是首选,检测任务YOLO、Faster R-CNN等各具特色。

实时性要求:移动端部署需要考虑模型大小和推理速度,轻量级CNN架构更适合。

8. 实战项目:综合图像处理系统

8.1 项目架构设计

下面实现一个综合的图像处理系统,集成分类、检测和分割功能:

import torch import torch.nn as nn from torchvision import transforms from PIL import Image import cv2 import numpy as np class ComprehensiveVisionSystem: def __init__(self): # 初始化各任务模型 self.classification_model = self.load_classification_model() self.detection_model = self.load_detection_model() self.segmentation_model = self.load_segmentation_model() self.transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) def load_classification_model(self): """加载图像分类模型""" model = models.resnet50(pretrained=True) model.eval() return model def load_detection_model(self): """加载目标检测模型""" # 这里可以使用YOLO、Faster R-CNN等 model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True) return model def load_segmentation_model(self): """加载图像分割模型""" model = UNet(n_channels=3, n_classes=21) # 假设21个类别 # 加载预训练权重 # model.load_state_dict(torch.load('unet_weights.pth')) model.eval() return model def classify_image(self, image_path): """图像分类""" image = Image.open(image_path).convert('RGB') input_tensor = self.transform(image).unsqueeze(0) with torch.no_grad(): output = self.classification_model(input_tensor) probabilities = torch.nn.functional.softmax(output[0], dim=0) # 获取top-5预测结果 top5_prob, top5_catid = torch.topk(probabilities, 5) return top5_prob, top5_catid def detect_objects(self, image_path): """目标检测""" results = self.detection_model(image_path) return results.pandas().xyxy[0] # 返回检测结果 def segment_image(self, image_path): """图像分割""" image = Image.open(image_path).convert('RGB') original_size = image.size # 预处理 image_tensor = self.transform(image).unsqueeze(0) with torch.no_grad(): output = self.segmentation_model(image_tensor) mask = torch.argmax(output, dim=1).squeeze().cpu().numpy() # 将mask调整回原图大小 mask = cv2.resize(mask, original_size, interpolation=cv2.INTER_NEAREST) return mask def process_comprehensive(self, image_path): """综合处理:分类+检测+分割""" print("开始综合图像分析...") # 分类 print("1. 图像分类分析:") probs