第一章:计算机视觉中图像的基础认知
第二章:计算机视觉:卷积神经网络(CNN)基本概念(一)
第三章:计算机视觉:卷积神经网络(CNN)基本概念(二)
第四章:搭建一个经典的LeNet5神经网络(附代码)
第五章:计算机视觉:神经网络实战之手势识别(附代码)
第六章:计算机视觉:目标检测从简单到容易(附代码)
第七章:MTCNN 人脸检测技术揭秘:原理、实现与实战(附代码)
第八章:探索YOLO技术:目标检测的高效解决方案
第九章:计算机视觉:主流数据集整理
第十章:生成对抗网络(GAN):从概念到代码实践(附代码)
第十一章:计算机视觉:经典数据格式(VOC、YOLO、COCO)解析与转换(附代码)
第十二章:计算机视觉:YOLOv11遥感图像目标检测(附代码)
在计算机视觉领域,目标检测是一项核心任务,它旨在从图像或视频中同时检测出多个目标物体,并确定它们的类别和位置。
一、目标检测与图像分类的关系
1.1 图像分类(Image Classification)
图像分类是计算机视觉中最基础的任务之一,上一篇《第五章:计算机视觉:神经网络实战之手势识别(附代码)》,比较详细的分析过图像分类的实现过程,其输入是一张图像,输出是一个类别标签。
例如,对于输入图像 abc.jpeg,

输出可能是 dog(狗)。图像分类是对整张图像进行样本级分类,任务相对较为粗糙,难度较低。不关心物体位置或数量。
下面这段代码展示如何使用预训练的深度学习模型对图像进行分类。用torchvision 库中的 ResNet-18 模型来对一张名为 abc.jpeg 的图片进行分类,并输出该图片最有可能的类别标签。
还是使用上面这种图片作为输入,
# 使用预训练的ResNet模型进行图像分类
import torchvision.models as models
import torchvision.transforms as transforms
from PIL import Image
# 加载预训练模型
model = models.resnet18(pretrained=True)
model.eval()
# 图像预处理
img = Image.open("abc.jpeg")
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_t = transform(img).unsqueeze(0)
# 预测
output = model(img_t)
# 输出最可能的类别标签,输出为153
print("Image Classification Output:", output.argmax(dim=1).item())
代码解释:
torchvision.models:包含了多种预训练的深度学习模型,如 ResNet、VGG 等。torchvision.transforms:提供了一系列用于图像预处理的变换方法,比如调整大小、裁剪、归一化等。PIL.Image:来自 Python Imaging Library (PIL),用于打开和操作图像。models.resnet18(pretrained=True):加载了在 ImageNet 数据集上预训练的 ResNet-18 模型。pretrained=True 表示加载预训练权重。model.eval():将模型设置为评估模式。这一步很重要,因为在评估模式下,模型的行为会有所不同(例如,Dropout 层和 BatchNorm 层的行为会发生变化),这对于获得正确的预测结果是必要的。transforms.Compose([...]):定义了一系列图像转换操作,这些操作将按顺序应用于输入图像:Resize(256):将图像的短边调整为 256 像素,长宽比保持不变。CenterCrop(224):从中心裁剪出一个 224x224 像素的正方形区域。ToTensor():将 PIL 图像或 NumPy 数组转换为 PyTorch 张量,并将像素值从 [0, 255] 缩放到 [0, 1]。Normalize(...):对每个通道应用均值和标准差进行标准化处理,使数据分布接近正态分布。这里的参数是基于 ImageNet 数据集计算得到的。
transform(img).unsqueeze(0):将上述转换应用到图像上,并通过 .unsqueeze(0) 在维度 0 处添加一个新的维度,以适应模型输入的要求(即模拟一个批次的输入)。即使只有一个样本也需要指定批次大小。model(img_t):将预处理后的图像张量输入到模型中,执行前向传播,获取模型输出。对于 ResNet-18 模型,输出是一个形状为 [batch_size, num_classes] 的张量,其中 num_classes 是 ImageNet 数据集中的类别数量(通常是 1000)。output.argmax(dim=1).item():找到输出张量中最大值的索引(对应于预测的类别),并将其转换为整数。这里假设我们只处理一个图像(因此 dim=1),.item() 方法用于将单个元素的张量转换为 Python 标量。
上面这段代码演示如何使用预训练的 ResNet-18 模型对单张图像进行分类。包括图像的加载、预处理以及模型预测的过程。通过这种方式,可以快速地利用现有的深度学习模型对新图像进行分类,而无需从头开始训练模型。
输出结果为:Image Classification Output: 153
这 153 代表什么意思?
要理解 ResNet-18 模型输出的数字代表什么类别,你需要知道这些数字对应的是 ImageNet 数据集中的具体类别。ImageNet 是一个非常大的数据集,包含了 1000 个不同类别的物体图像。每个类别都有一个对应的索引(从 0 到 999),而模型的输出就是这些索引
找到一个博主的分享链接,可以根据索引 153,去这个文件中找对应的分类。
1.2 目标检测(Object Detection)
与图像分类不同,目标检测的输入是一张图像,输出是多个目标的类别和位置信息。每个目标不仅需要识别出是什么(类别概率),还需要确定其在图像中的位置(边界框),是什么?+ 在哪里?

目标检测的本质是同时完成分类和定位任务,且需要处理多个目标,任务更加精细,难度较大。
下面这段代码展示如何使用预训练的 Faster R-CNN 模型进行目标检测。Faster R-CNN 是一种目标检测算法,它不仅能够识别图像中的物体是什么(分类),还能确定这些物体的具体位置(通过边界框)。使用下面这张图作为输入:

# 使用Faster R-CNN进行目标检测
import torchvision.models.detection as detection_models
from torchvision.utils import draw_bounding_boxes
# 加载预训练模型
model = detection_models.fasterrcnn_resnet50_fpn(pretrained=True)
model.eval()
# 定义图像预处理步骤
# 将PIL图像或numpy数组转换为tensor,并调整像素值范围到[0, 1]
transform = transforms.Compose([
transforms.ToTensor()
])
# 确保图像为 RGB 格式
img = Image.open("234.jpeg").convert('RGB')
# 图像预处理
img_t = transform(img).unsqueeze(0)
# 预测
predictions = model(img_t)
# 这段代码打印了第一个图像的预测结果,包括所有检测到的对象的边界框、类别标签和置信度分数。
print("Object Detection Output:", predictions[0])
代码解释:
torchvision.models.detection:包含了多种用于目标检测的模型架构,如 Faster R-CNN、Mask R-CNN 等。torchvision.utils.draw_bounding_boxes:一个实用工具函数,用于在图像上绘制边界框。detection_models.fasterrcnn_resnet50_fpn(...):加载了基于 ResNet-50 和特征金字塔网络(FPN)的 Faster R-CNN 预训练模型。pretrained=True 表示加载在 COCO 数据集上预训练的权重。model.eval():将模型设置为评估模式,确保在推理时的行为与训练时不同(例如,关闭 Dropout 层)。model(img_t):将预处理后的图像张量输入到模型中,执行前向传播以获取预测结果。Faster R-CNN 的输出是一个字典列表,每个字典对应于批次中的一个图像。对于每个图像,字典包含如下键:boxes: 边界框坐标,形状为 [num_objects, 4],其中每一行表示 [x_min, y_min, x_max, y_max]。labels: 对应每个边界框的类别标签,形状为 [num_objects]。scores: 对应每个边界框的置信度分数,形状为 [num_objects]。
以上代码输出:
Object Detection Output: {'boxes': tensor([[ 192.0583, 332.6462, 568.7687, 937.6382],
[ 545.7770, 377.5865, 1487.1511, 957.2280],
[ 521.1418, 371.4620, 1489.0027, 954.8814],
[1205.2445, 465.5862, 1463.3578, 944.3210]],
grad_fn=<StackBackward0>), 'labels': tensor([ 1, 19, 21, 19]), 'scores': tensor([0.9999, 0.9853, 0.1622, 0.0502], grad_fn=<IndexBackward0>)}
绘制边界框
如果想在原始图像上可视化检测结果,可以使用 draw_bounding_boxes 函数。
import torch
# 假设我们只对置信度大于0.5的结果感兴趣
threshold = 0.5
filtered_predictions = [(pred['boxes'][pred['scores'] > threshold],
pred['labels'][pred['scores'] > threshold]) for pred in predictions]
# 获取类别名称(COCO数据集的80个类别)
COCO_INSTANCE_CATEGORY_NAMES = [
'__background__', 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',
'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'N/A', 'stop sign',
'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
'elephant', 'bear', 'zebra', 'giraffe', 'N/A', 'backpack', 'umbrella', 'N/A', 'N/A',
'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball',
'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket',
'bottle', 'N/A', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana',
'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut',
'cake', 'chair', 'couch', 'potted plant', 'bed', 'N/A', 'dining table', 'N/A',
'N/A', 'toilet', 'N/A', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'N/A', 'book',
'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'
]
# 转换预测结果以便绘图
boxes, labels = filtered_predictions[0]
labels = [COCO_INSTANCE_CATEGORY_NAMES[i] for i in labels]
# 将张量转回图像并绘制边界框
img_with_boxes = draw_bounding_boxes(
img_t.squeeze(0), boxes, labels=labels, colors="red", width=3
)
# 显示结果
from torchvision.transforms.functional import to_pil_image
display(to_pil_image(img_with_boxes))

上面这段代码过滤出高置信度的检测结果,并在原始图像上绘制相应的边界框和类别标签。这样可以更直观地理解模型的预测结果。
二、目标检测策略
目标检测需要同时识别多个类别,并为每个类别实例提供概率和定位信息。通常我们解决一个复杂的问题,都是凭借我们对知识迁移的能力来解决!
- 利用已知的知识来解决未知的问题!
- 把未知的问题转换到已知的领域中!
- 把一个很难的问题拆解为一系列简单的问题的叠加!
- 把一些不懂得问题转换为自己懂的领域!
前面的章节《计算机视觉:神经网络实战之手势识别(附代码)》,对图像分类技术进行了详细分析,为了破解目标检测这一复杂任务,通过将目标检测问题转化为已知的图像分类问题,利用已有的知识和技术来解决未知的问题。
具体来说,可以将目标检测拆解为一系列简单问题的叠加,例如:
- 1、切图策略:将原图切割成多个小块,针对每个小块进行图像分类。
- 2、特征提取与分类:先对原图提取特征,然后在特征图上进行切割和分类。
典型方法
MTCNN:采用级联结构,先切割原图,再针对每个片段提取特征并进行分类。
SSD、YOLO:先对原图提取特征,然后在特征图上进行切割和分类。
特征提取是目标检测中的关键步骤,在前面的章节中,已经详细分析了如何使用卷积操作来抽取特征。
- 原始图像:原始图像通常分辨率较高,图像很大,特征具体且详细。
- 卷一下:图变小,特征变抽象
- 再卷一下:图又变小,特征又变抽象
- 继续卷下去:图像很小,特征很抽象
特征演化过程:
原始图像 → 卷积层1 → 卷积层2 → ... → 卷积层N
(具体细节) (边缘特征) (部件特征) (语义特征)
随着卷积层数的增加,图像尺寸逐渐减小,特征变得更加抽象,其过程可以理解为将人眼可理解的信息转化为计算机可理解的向量表示。
# 卷积操作示例
import torch
import torch.nn as nn
# 定义一个简单的卷积层
conv_layer = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1)
# 输入图像张量
input_tensor = torch.randn(1, 3, 224, 224)
# 卷积操作
output_tensor = conv_layer(input_tensor)
# 输出结果 torch.Size([1, 16, 224, 224])
print("Output Tensor Shape:", output_tensor.shape)
下一篇文章接着介绍MTCNN,即多任务级联卷积神经网络(Multi-task Cascaded Convolutional Networks),一种用于人脸检测和对齐的深度学习方法。

11万+

被折叠的 条评论
为什么被折叠?



