计算机视觉(CV)基础任务介绍
1. 计算机视觉概述
计算机视觉(Computer Vision,简称CV)是人工智能的一个重要分支,旨在使计算机能够理解和处理图像和视频数据。通过模仿人类视觉系统的功能,计算机视觉技术使机器能够识别、检测、分割和理解图像中的内容。本节将介绍计算机视觉的发展历程、基本原理以及主要应用领域。
1.1 计算机视觉的发展历程
计算机视觉的发展经历了以下几个重要阶段:
| 阶段 | 时间 | 技术特点 | 代表技术 |
|---|---|---|---|
| 早期发展 | 1960s-1980s | 基于规则和几何的方法 | 边缘检测、特征提取 |
| 统计学习时代 | 1990s-2000s | 基于机器学习的方法 | SVM、Adaboost、HOG特征 |
| 深度学习时代 | 2010s至今 | 基于深度神经网络的方法 | CNN、R-CNN系列、YOLO系列 |
| 大模型时代 | 2020s至今 | 基于大规模预训练模型 | ViT、CLIP、SAM |
1.2 计算机视觉的基本原理
计算机视觉的基本原理可以概括为以下几个步骤:
- 图像获取:通过摄像头、传感器等设备获取图像数据
- 预处理:对图像进行去噪、增强、缩放等处理
- 特征提取:从图像中提取有意义的特征信息
- 特征分析:对提取的特征进行分析和理解
- 高层理解:基于特征分析结果,实现对图像内容的理解和推理
1.3 计算机视觉的应用领域
计算机视觉技术广泛应用于以下领域:
- 安防监控:人脸识别、行为识别、异常检测
- 自动驾驶:车道线检测、目标检测、场景理解
- 医疗健康:医学影像分析、疾病诊断、手术辅助
- 零售电商:商品识别、视觉搜索、库存管理
- 工业制造:缺陷检测、质量控制、机器人视觉
- 娱乐媒体:图像编辑、视频特效、AR/VR
- 农业:作物监测、病虫害识别、产量预测
- 交通管理:车辆识别、交通流量分析、违章检测
2. 基础任务详解
2.1 图像分类(Image Classification)
图像分类是计算机视觉中最基础的任务,目标是将输入图像分配到预定义的类别中。
2.1.1 图像分类的基本原理
图像分类的基本流程:
- 数据预处理:调整图像大小、归一化、数据增强等
- 特征提取:使用卷积神经网络(CNN)等模型提取图像特征
- 分类决策:使用全连接层或分类器对特征进行分类
- 模型评估:使用准确率、精确率、召回率等指标评估模型性能
2.1.2 经典图像分类模型
| 模型 | 年份 | 特点 | 代表网络 |
|---|---|---|---|
| 早期模型 | 2012年前 | 手工特征 + 分类器 | SIFT + SVM |
| AlexNet | 2012 | 深度CNN,ReLU激活函数 | 8层网络 |
| VGG | 2014 | 更深的网络结构,小卷积核 | VGG-16, VGG-19 |
| GoogLeNet | 2014 | inception模块,多尺度特征 | Inception v1-v4 |
| ResNet | 2015 | 残差连接,解决梯度消失问题 | ResNet-18, ResNet-50, ResNet-152 |
| DenseNet | 2017 | 密集连接,特征重用 | DenseNet-121 |
| EfficientNet | 2019 | 模型缩放,计算效率高 | EfficientNet-B0到B7 |
| Vision Transformer | 2020 | 基于自注意力机制 | ViT |
2.1.3 代码示例:图像分类
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
# 1. 数据预处理
transform = transforms.Compose([
transforms.Resize((32, 32)),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
# 2. 加载数据集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)
testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2)
classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
# 3. 定义模型
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5) # 输入通道3,输出通道6,卷积核5x5
self.pool = nn.MaxPool2d(2, 2) # 池化核2x2,步长2
self.conv2 = nn.Conv2d(6, 16, 5) # 输入通道6,输出通道16,卷积核5x5
self.fc1 = nn.Linear(16 * 5 * 5, 120) # 全连接层
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10) # 输出10类
def forward(self, x):
x = self.pool(torch.relu(self.conv1(x)))
x = self.pool(torch.relu(self.conv2(x)))
x = x.view(-1, 16 * 5 * 5) # 展平
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
# 4. 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
# 5. 训练模型
for epoch in range(2): # 只训练2个epoch以节省时间
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
inputs, labels = data
# 清零梯度
optimizer.zero_grad()
# 前向传播
outputs = net(inputs)
loss = criterion(outputs, labels)
# 反向传播和优化
loss.backward()
optimizer.step()
# 打印统计信息
running_loss += loss.item()
if i % 2000 == 1999: # 每2000个mini-batch打印一次
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 2000))
running_loss = 0.0
print('Finished Training')
# 6. 测试模型
dataiter = iter(testloader)
images, labels = dataiter.next()
# 打印真实标签
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))
# 预测
outputs = net(images)
_, predicted = torch.max(outputs, 1)
# 打印预测结果
print('Predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))
# 计算整体准确率
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))
# 计算每个类的准确率
class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs, 1)
c = (predicted == labels).squeeze()
for i in range(4):
label = labels[i]
class_correct[label] += c[i].item()
class_total[label] += 1
for i in range(10):
print('Accuracy of %5s : %2d %%' % (classes[i], 100 * class_correct[i] / class_total[i]))2.2 目标检测(Object Detection)
目标检测是计算机视觉中的核心任务,目标是在图像中定位并识别多个目标对象。
2.2.1 目标检测的基本原理
目标检测的基本流程:
- 区域生成:生成可能包含目标的候选区域
- 特征提取:对每个候选区域提取特征
- 分类与回归:对候选区域进行分类,并回归目标的精确边界框
- 后处理:使用非极大值抑制(NMS)等方法过滤重叠检测结果
2.2.2 目标检测算法分类
目标检测算法主要分为以下几类:
两阶段检测器:先生成候选区域,再进行分类和回归
- R-CNN系列(R-CNN, Fast R-CNN, Faster R-CNN)
- Mask R-CNN(同时支持实例分割)
单阶段检测器:直接预测目标的类别和边界框
- YOLO系列(YOLOv1-v8)
- SSD(Single Shot MultiBox Detector)
- RetinaNet
锚框-free检测器:不使用预定义的锚框
- CornerNet
- CenterNet
- FCOS(Fully Convolutional One-Stage Object Detection)
2.2.3 代码示例:使用YOLOv5进行目标检测
import torch
from PIL import Image
import cv2
import numpy as np
# 加载YOLOv5模型
model = torch.hub.load('ultralytics/yolov5', 'yolov5s') # 加载轻量级模型
# 加载图像
img = Image.open('test.jpg') # 替换为你的测试图像路径
# 进行目标检测
results = model(img)
# 显示检测结果
results.show()
# 打印检测结果
print(results.pandas().xyxy[0]) # 以pandas DataFrame形式显示结果
# 使用OpenCV加载图像并绘制检测结果
img_cv = cv2.imread('test.jpg')
detections = results.pandas().xyxy[0]
for _, detection in detections.iterrows():
x1, y1, x2, y2, confidence, class_id, class_name = detection.values
# 绘制边界框
cv2.rectangle(img_cv, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
# 绘制类别和置信度
label = f'{class_name}: {confidence:.2f}'
cv2.putText(img_cv, label, (int(x1), int(y1) - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
# 保存结果
cv2.imwrite('result.jpg', img_cv)
print('检测结果已保存到result.jpg')
# 实时目标检测(使用摄像头)
cap = cv2.VideoCapture(0) # 0表示默认摄像头
while True:
ret, frame = cap.read()
if not ret:
break
# 进行目标检测
results = model(frame)
# 绘制检测结果
detections = results.pandas().xyxy[0]
for _, detection in detections.iterrows():
x1, y1, x2, y2, confidence, class_id, class_name = detection.values
cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
label = f'{class_name}: {confidence:.2f}'
cv2.putText(frame, label, (int(x1), int(y1) - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
# 显示结果
cv2.imshow('YOLOv5 Real-time Detection', frame)
# 按'q'退出
if cv2.waitKey(1) == ord('q'):
break
cap.release()
cv2.destroyAllWindows()2.3 图像分割(Image Segmentation)
图像分割是将图像分割成不同区域或像素组的任务,根据分割粒度的不同,可分为语义分割、实例分割和全景分割。
2.3.1 语义分割(Semantic Segmentation)
语义分割的目标是为图像中的每个像素分配一个语义类别标签,不区分同一类别的不同实例。
2.3.1.1 语义分割的基本原理
语义分割的基本流程:
- 编码器-解码器架构:使用编码器提取特征,解码器恢复空间信息
- 跳跃连接:融合不同层次的特征信息
- 上采样:使用转置卷积、双线性插值等方法恢复图像分辨率
- 像素级分类:对每个像素进行分类
2.3.1.2 经典语义分割模型
- FCN(Fully Convolutional Networks)
- U-Net
- SegNet
- DeepLab系列(DeepLabv1-v3+)
- Mask R-CNN(同时支持实例分割)
2.3.2 实例分割(Instance Segmentation)
实例分割的目标是为图像中的每个像素分配一个语义类别标签,并区分同一类别的不同实例。
2.3.2.1 实例分割的基本原理
实例分割的基本流程:
- 目标检测:检测图像中的目标实例
- 实例掩码生成:为每个检测到的目标生成像素级掩码
- 后处理:合并检测结果和掩码
2.3.2.2 经典实例分割模型
- Mask R-CNN
- YOLACT
- SOLO
- Detectron2系列
2.3.3 全景分割(Panoptic Segmentation)
全景分割是语义分割和实例分割的结合,同时处理"事物"(可数的目标,如人、车)和"东西"(不可数的区域,如天空、道路)。
2.3.4 代码示例:使用U-Net进行语义分割
import torch
import torch.nn as nn
import torch.nn.functional as F
from PIL import Image
import numpy as np
import cv2
# 定义U-Net模型
class UNet(nn.Module):
def __init__(self, in_channels=3, out_channels=2):
super(UNet, self).__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.bottleneck = self.conv_block(512, 1024)
# 解码器
self.up4 = nn.ConvTranspose2d(1024, 512, kernel_size=2, stride=2)
self.dec4 = self.conv_block(1024, 512) # 512 + 512
self.up3 = nn.ConvTranspose2d(512, 256, kernel_size=2, stride=2)
self.dec3 = self.conv_block(512, 256) # 256 + 256
self.up2 = nn.ConvTranspose2d(256, 128, kernel_size=2, stride=2)
self.dec2 = self.conv_block(256, 128) # 128 + 128
self.up1 = nn.ConvTranspose2d(128, 64, kernel_size=2, stride=2)
self.dec1 = self.conv_block(128, 64) # 64 + 64
# 输出层
self.out = nn.Conv2d(64, out_channels, kernel_size=1)
def conv_block(self, in_channels, out_channels):
return nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1),
nn.ReLU(inplace=True)
)
def forward(self, x):
# 编码器
e1 = self.enc1(x)
e2 = self.enc2(F.max_pool2d(e1, kernel_size=2, stride=2))
e3 = self.enc3(F.max_pool2d(e2, kernel_size=2, stride=2))
e4 = self.enc4(F.max_pool2d(e3, kernel_size=2, stride=2))
# 瓶颈
b = self.bottleneck(F.max_pool2d(e4, kernel_size=2, stride=2))
# 解码器
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)
# 输出
out = self.out(d1)
return out
# 加载模型
model = UNet(in_channels=3, out_channels=2) # 假设我们分割为2类
# 加载图像
img = Image.open('test.jpg')
img = img.resize((256, 256)) # 调整为256x256
img_tensor = torch.from_numpy(np.array(img)).permute(2, 0, 1).float() / 255.0
img_tensor = img_tensor.unsqueeze(0) # 添加批次维度
# 进行分割
with torch.no_grad():
output = model(img_tensor)
pred = torch.argmax(output, dim=1).squeeze().numpy()
# 可视化分割结果
seg_mask = np.zeros((256, 256, 3), dtype=np.uint8)
seg_mask[pred == 1] = [0, 255, 0] # 类别1用绿色表示
# 叠加原始图像和分割结果
img_np = np.array(img)
alpha = 0.5
result = cv2.addWeighted(img_np, alpha, seg_mask, 1-alpha, 0)
# 保存结果
cv2.imwrite('segmentation_result.jpg', cv2.cvtColor(result, cv2.COLOR_RGB2BGR))
print('分割结果已保存到segmentation_result.jpg')
# 显示结果
cv2.imshow('Segmentation Result', cv2.cvtColor(result, cv2.COLOR_RGB2BGR))
cv2.waitKey(0)
cv2.destroyAllWindows()2.4 人脸识别(Face Recognition)
人脸识别是计算机视觉中的一个重要任务,目标是识别图像或视频中的人脸身份。
2.4.1 人脸识别的基本原理
人脸识别的基本流程:
- 人脸检测:定位图像中的人脸位置
- 人脸对齐:对检测到的人脸进行对齐和规范化
- 特征提取:从对齐后的人脸中提取特征
- 特征匹配:将提取的特征与数据库中的特征进行匹配
- 身份识别:根据匹配结果确定人脸身份
2.4.2 人脸识别的关键技术
人脸检测:
- Haar特征 + Adaboost
- HOG + SVM
- CNN-based方法(如MTCNN, RetinaFace)
人脸对齐:
- 基于关键点的仿射变换
- 3D人脸建模
特征提取:
- 手工特征(LBP, HOG)
- 深度学习特征(FaceNet, ArcFace, CosFace)
特征匹配:
- 欧氏距离
- 余弦相似度
- 曼哈顿距离
2.4.3 代码示例:使用dlib进行人脸识别
import dlib
import cv2
import numpy as np
# 加载dlib的人脸检测器和特征点检测器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat') # 需要下载此文件
# 加载人脸识别模型
face_rec_model = dlib.face_recognition_model_v1('dlib_face_recognition_resnet_model_v1.dat') # 需要下载此文件
# 加载图像
img = cv2.imread('group_photo.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 检测人脸
faces = detector(gray)
print(f'检测到 {len(faces)} 个人脸')
# 对每个人脸进行处理
for i, face in enumerate(faces):
# 绘制边界框
x1, y1, x2, y2 = face.left(), face.top(), face.right(), face.bottom()
cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
# 检测特征点
landmarks = predictor(gray, face)
# 绘制特征点
for n in range(0, 68):
x = landmarks.part(n).x
y = landmarks.part(n).y
cv2.circle(img, (x, y), 2, (0, 0, 255), -1)
# 提取人脸特征
face_descriptor = face_rec_model.compute_face_descriptor(img, landmarks)
face_descriptor = np.array(face_descriptor)
# 打印特征向量(前10个元素)
print(f'人脸 {i+1} 的特征向量(前10个元素): {face_descriptor[:10]}')
# 保存结果
cv2.imwrite('face_recognition_result.jpg', img)
print('人脸识别结果已保存到face_recognition_result.jpg')
# 显示结果
cv2.imshow('Face Recognition Result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 实时人脸识别(使用摄像头)
cap = cv2.VideoCapture(0) # 0表示默认摄像头
while True:
ret, frame = cap.read()
if not ret:
break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = detector(gray)
for face in faces:
x1, y1, x2, y2 = face.left(), face.top(), face.right(), face.bottom()
cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
landmarks = predictor(gray, face)
for n in range(0, 68):
x = landmarks.part(n).x
y = landmarks.part(n).y
cv2.circle(frame, (x, y), 1, (0, 0, 255), -1)
cv2.imshow('Real-time Face Detection', frame)
if cv2.waitKey(1) == ord('q'):
break
cap.release()
cv2.destroyAllWindows()2.5 其他基础任务
2.5.1 图像超分辨率(Image Super-Resolution)
图像超分辨率的目标是从低分辨率图像生成高分辨率图像。
2.5.1.1 图像超分辨率的基本原理
图像超分辨率的基本流程:
- 特征提取:从低分辨率图像中提取特征
- 特征映射:将低分辨率特征映射到高分辨率特征空间
- 图像重建:基于高分辨率特征重建图像
2.5.1.2 经典超分辨率模型
- SRCNN(Super-Resolution Convolutional Neural Network)
- EDSR(Enhanced Deep Super-Resolution Network)
- SRGAN(Super-Resolution Generative Adversarial Network)
- ESRGAN(Enhanced Super-Resolution Generative Adversarial Network)
2.5.2 图像风格迁移(Style Transfer)
图像风格迁移的目标是将一幅图像的风格应用到另一幅图像上,同时保留内容。
2.5.2.1 图像风格迁移的基本原理
图像风格迁移的基本流程:
- 特征提取:使用预训练的CNN提取内容图像和风格图像的特征
- 损失计算:计算内容损失和风格损失
- 优化:通过优化生成图像的像素值,最小化总损失
2.5.2.2 经典风格迁移方法
- Gatys等人的方法(基于优化)
- Fast Style Transfer(基于前向网络)
- CycleGAN(无配对数据的风格迁移)
- AdaIN(自适应实例归一化)
3. 技术挑战与发展趋势
3.1 技术挑战
计算机视觉技术面临以下主要挑战:
数据挑战:
- 数据标注成本高
- 数据分布不均
- 低资源场景数据稀缺
模型挑战:
- 计算资源需求大
- 模型部署困难
- 可解释性差
场景挑战:
- 光照变化
- 视角变化
- 遮挡
- 背景复杂
- 目标变形
泛化挑战:
- 跨域泛化能力弱
- 对未见场景适应性差
- 鲁棒性不足
3.2 发展趋势
计算机视觉技术的发展趋势包括:
大模型时代:
- 预训练视觉模型(如ViT, CLIP)
- 自监督和无监督学习
- 多任务学习
多模态融合:
- 视觉-语言融合(如Vision-Language Pre-training)
- 视觉-语音融合
- 多模态表示学习
高效模型设计:
- 轻量级模型
- 模型压缩和量化
- 知识蒸馏
- 神经架构搜索
自监督学习:
- 对比学习
- 掩码图像建模
- 自监督预训练
3D视觉:
- 单目3D目标检测
- 点云处理
- 立体视觉
- 3D重建
可解释性:
- 视觉解释方法
- 透明模型设计
- 因果推理
鲁棒性:
- 对抗训练
- 域适应
- 开放世界识别
实时处理:
- 边缘计算
- 硬件加速
- 实时算法优化
4. 实践案例
4.1 案例一:使用ResNet进行图像分类
背景:某电商平台需要自动识别用户上传的商品图片,将其分类到正确的商品类别中。
解决方案:使用预训练的ResNet模型进行商品图像分类。
代码示例:
import torch
import torchvision.models as models
import torchvision.transforms as transforms
from PIL import Image
# 1. 加载预训练的ResNet模型
model = models.resnet18(pretrained=True)
model.eval() # 设置为评估模式
# 2. 定义图像预处理
preprocess = 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]),
])
# 3. 加载并预处理图像
img = Image.open('product.jpg')
img_t = preprocess(img)
batch_t = torch.unsqueeze(img_t, 0)
# 4. 进行预测
with torch.no_grad():
outputs = model(batch_t)
_, predicted = torch.max(outputs, 1)
# 5. 加载ImageNet类别标签
with open('imagenet_classes.txt') as f: # 需要下载此文件
classes = [line.strip() for line in f.readlines()]
# 6. 打印预测结果
print(f'预测类别: {classes[predicted[0]]}')
# 7. 打印前5个预测结果
probabilities = torch.nn.functional.softmax(outputs, dim=1)[0]
top5_prob, top5_catid = torch.topk(probabilities, 5)
for i in range(top5_prob.size(0)):
print(f'{classes[top5_catid[i]]}: {top5_prob[i].item():.4f}')4.2 案例二:使用YOLOv5进行目标检测
背景:某安防公司需要开发一个监控系统,能够实时检测监控视频中的人员、车辆等目标。
解决方案:使用YOLOv5模型进行实时目标检测。
代码示例:
import torch
import cv2
import numpy as np
# 1. 加载YOLOv5模型
model = torch.hub.load('ultralytics/yolov5', 'yolov5s')
# 2. 打开视频文件
video_path = 'surveillance.mp4'
cap = cv2.VideoCapture(video_path)
# 3. 获取视频属性
fps = cap.get(cv2.CAP_PROP_FPS)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# 4. 创建输出视频写入器
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi', fourcc, fps, (width, height))
# 5. 处理视频帧
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# 6. 进行目标检测
results = model(frame)
# 7. 绘制检测结果
detections = results.pandas().xyxy[0]
for _, detection in detections.iterrows():
x1, y1, x2, y2, confidence, class_id, class_name = detection.values
# 只显示人员和车辆
if class_name in ['person', 'car', 'truck', 'bus']:
# 绘制边界框
cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
# 绘制类别和置信度
label = f'{class_name}: {confidence:.2f}'
cv2.putText(frame, label, (int(x1), int(y1) - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
# 8. 写入输出视频
out.write(frame)
# 9. 显示结果
cv2.imshow('Surveillance Detection', frame)
if cv2.waitKey(1) == ord('q'):
break
# 10. 释放资源
cap.release()
out.release()
cv2.destroyAllWindows()
print('处理完成,结果已保存到output.avi')4.3 案例三:使用U-Net进行医学图像分割
背景:某医院需要开发一个医学影像分析系统,能够自动分割CT扫描中的病变区域。
解决方案:使用U-Net模型进行医学图像分割。
代码示例:
import torch
import torch.nn as nn
import numpy as np
import cv2
from PIL import Image
# 1. 定义U-Net模型(与前面相同)
class UNet(nn.Module):
def __init__(self, in_channels=1, out_channels=2):
super(UNet, self).__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.bottleneck = self.conv_block(512, 1024)
# 解码器
self.up4 = nn.ConvTranspose2d(1024, 512, kernel_size=2, stride=2)
self.dec4 = self.conv_block(1024, 512) # 512 + 512
self.up3 = nn.ConvTranspose2d(512, 256, kernel_size=2, stride=2)
self.dec3 = self.conv_block(512, 256) # 256 + 256
self.up2 = nn.ConvTranspose2d(256, 128, kernel_size=2, stride=2)
self.dec2 = self.conv_block(256, 128) # 128 + 128
self.up1 = nn.ConvTranspose2d(128, 64, kernel_size=2, stride=2)
self.dec1 = self.conv_block(128, 64) # 64 + 64
# 输出层
self.out = nn.Conv2d(64, out_channels, kernel_size=1)
def conv_block(self, in_channels, out_channels):
return nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1),
nn.ReLU(inplace=True)
)
def forward(self, x):
# 编码器
e1 = self.enc1(x)
e2 = self.enc2(nn.functional.max_pool2d(e1, kernel_size=2, stride=2))
e3 = self.enc3(nn.functional.max_pool2d(e2, kernel_size=2, stride=2))
e4 = self.enc4(nn.functional.max_pool2d(e3, kernel_size=2, stride=2))
# 瓶颈
b = self.bottleneck(nn.functional.max_pool2d(e4, kernel_size=2, stride=2))
# 解码器
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)
# 输出
out = self.out(d1)
return out
# 2. 加载模型
model = UNet(in_channels=1, out_channels=2) # 输入为灰度图像,输出为2类分割
# 假设我们已经训练好了模型并保存
# model.load_state_dict(torch.load('unet_medical.pth'))
model.eval()
# 3. 加载医学图像
img = Image.open('ct_scan.jpg').convert('L') # 转换为灰度图像
img = img.resize((256, 256))
img_np = np.array(img)
img_tensor = torch.from_numpy(img_np).unsqueeze(0).unsqueeze(0).float() / 255.0
# 4. 进行分割
with torch.no_grad():
output = model(img_tensor)
pred = torch.argmax(output, dim=1).squeeze().numpy()
# 5. 可视化分割结果
# 创建彩色掩码
mask = np.zeros((256, 256, 3), dtype=np.uint8)
mask[pred == 1] = [255, 0, 0] # 病变区域用红色表示
# 叠加原始图像和分割结果
img_color = cv2.cvtColor(img_np, cv2.COLOR_GRAY2BGR)
alpha = 0.5
result = cv2.addWeighted(img_color, alpha, mask, 1-alpha, 0)
# 6. 计算病变区域面积
lesion_area = np.sum(pred == 1)
total_area = pred.size
lesion_percentage = (lesion_area / total_area) * 100
print(f'病变区域面积: {lesion_area} 像素')
print(f'病变区域占比: {lesion_percentage:.2f}%')
# 7. 保存结果
cv2.imwrite('medical_segmentation_result.jpg', result)
print('分割结果已保存到medical_segmentation_result.jpg')
# 8. 显示结果
cv2.imshow('Original CT Scan', img_color)
cv2.imshow('Lesion Segmentation', mask)
cv2.imshow('Overlay Result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()5. 总结与建议
5.1 学习建议
- 掌握基础理论:了解计算机视觉的基本概念和原理
- 实践项目:通过实际项目练习巩固所学知识
- 模型选择:根据具体任务选择合适的模型
- 数据处理:学习数据预处理、增强和标注技术
- 性能优化:了解模型压缩、量化等优化技术
- 关注前沿:跟踪计算机视觉的最新研究和发展
5.2 最佳实践
任务适配:
- 图像分类:使用ResNet、EfficientNet等模型
- 目标检测:使用YOLO系列、Faster R-CNN等模型
- 图像分割:使用U-Net、DeepLab等模型
- 人脸识别:使用FaceNet、ArcFace等模型
数据处理:
- 数据增强:随机翻转、缩放、裁剪、颜色变换等
- 数据标准化:对输入图像进行归一化
- 数据标注:使用专业标注工具,确保标注质量
模型训练:
- 迁移学习:使用预训练模型加速训练
- 学习率调度:使用学习率衰减、warmup等策略
- 正则化:使用dropout、权重衰减等防止过拟合
- 批次大小:根据硬件资源选择合适的批次大小
模型评估:
- 图像分类:准确率、精确率、召回率、F1分数
- 目标检测:mAP(mean Average Precision)
- 图像分割:IoU(Intersection over Union)、Dice系数
- 人脸识别:准确率、FRR(False Rejection Rate)、FAR(False Acceptance Rate)
5.3 未来展望
计算机视觉技术正在快速发展,未来将在以下方向取得突破:
- 大模型时代:预训练视觉模型将成为主流,模型能力将进一步提升
- 多模态融合:视觉与语言、语音等模态的融合将更加紧密
- 高效智能:模型将更加高效,适用于边缘设备和实时场景
- 自监督学习:减少对标注数据的依赖,提高模型泛化能力
- 3D视觉:从2D到3D的演进,提供更丰富的场景理解
- 可解释性:模型决策过程将更加透明,增强用户信任
- 鲁棒性:模型将更加鲁棒,能够应对复杂的真实场景
作为人工智能训练师,掌握计算机视觉的基础任务和技术,将有助于我们更好地理解和应用这一强大技术,为各种视觉相关任务开发更有效的解决方案。同时,我们也需要关注计算机视觉的伦理问题,确保技术的负责任使用。