目标检测
1. 什么是目标检测?
1.1.定义
目标检测是计算机视觉任务,旨在图像或视频中定位和识别感兴趣的目标。定位指找到目标的位置(如用边界框表示),识别指确定目标的类别。
- 其关键要素:
- 定位:用边界框(如矩形框)表示位置,坐标包括左上角
和右下角
- 识别:分类目标内容,目标可以是常规物体(如人、车)或抽象概念。
- 任务目标:根据应用需求定义感兴趣目标。
- 定位:用边界框(如矩形框)表示位置,坐标包括左上角
2. 目标检测常见数据集
数据集包括输入(图片)和输出(标注),评估标准包括数据量、场景覆盖度和标注质量。
- 主要数据集介绍:
- VOC数据集:
- 结构:包含 Annotations(XML标注文件)和 JPEGImages(图片文件夹)。
- 标注格式:重点关注 object 标签,包括 name(类别)和 bndbox(边界框坐标)。
- 坐标系:图像坐标系原点在左上角,x轴向右,y轴向下。
- COCO数据集:
- 结构:使用 JSON 文件存储标注。
- 标注格式:bbox 字段表示
,
。
- YOLO标注格式:
- 结构:TXT 文件存储标注。
- 标注格式:每行表示一个目标,格式为 class_id center_x center_y width height,其中坐标归一化到 [0,1]。
- VOC数据集:
这些数据集各有其特点,VOC、COCO和YOLO格式都是计算机视觉领域常用的数据集标注格式。其中VOC格式采用XML文件存储标注信息,结构清晰且支持多任务标注,但文件体积较大且解析效率较低,适合小规模研究项目或需要详细标注的场景。COCO格式使用JSON文件组织数据,支持丰富的标注类型和层次化结构,兼容性强且被多数现代框架支持,但文件解析复杂度较高,适用于中大规模数据集和需要复杂标注的任务。YOLO格式以纯文本存储标注,每行对应一个目标的归一化坐标和类别,文件紧凑且加载高效,但缺乏元信息和多任务支持,适合实时性要求高的目标检测任务(如YOLO系列模型)。选择时需权衡标注需求、数据规模及模型兼容性——VOC适合精细化标注,COCO适合多任务研究,YOLO格式则侧重轻量化和检测效率。
3. 目标检测数据集代码实战
- 环境配置:
- 安装 Python、Anaconda(可选)、PyCharm 和深度学习库(如 PyTorch、OpenCV)。
- 设置虚拟环境,确保依赖兼容。
- 加载VOC数据集: import os
import xml.etree.ElementTree as ET
import cv2
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from typing import List, Dict, Tupleclass VOCDatasetLoader:
\”\”\”VOC数据集加载器,用于加载和解析VOC格式的数据集\”\”\”def __init__(self, voc_root: str, split: str = \’train\’):
\”\”\”
初始化VOC数据集加载器Args:
voc_root: VOC数据集根目录,如 \’./VOCdevkit/VOC2007\’
split: 数据集划分,可选 \’train\’, \’val\’, \’trainval\’, \’test\’
\”\”\”
self.voc_root = voc_root
self.split = split# 定义VOC数据集的标准路径
self.annotations_dir = os.path.join(voc_root, \’Annotations\’)
self.images_dir = os.path.join(voc_root, \’JPEGImages\’)
self.image_sets_dir = os.path.join(voc_root, \’ImageSets\’, \’Main\’)# 获取指定划分的图片ID列表
self.image_ids = self._get_image_ids()# VOC数据集的20个类别(PASCAL VOC 2007/2012)
self.class_names = [
\’aeroplane\’, \’bicycle\’, \’bird\’, \’boat\’, \’bottle\’,
\’bus\’, \’car\’, \’cat\’, \’chair\’, \’cow\’,
\’diningtable\’, \’dog\’, \’horse\’, \’motorbike\’, \’person\’,
\’pottedplant\’, \’sheep\’, \’sofa\’, \’train\’, \’tvmonitor\’
]
self.class2id = {name: idx for idx, name in enumerate(self.class_names)}def _get_image_ids(self) -> List[str]:
\”\”\”获取指定划分的图片ID列表\”\”\”
split_file = os.path.join(self.image_sets_dir, f\'{self.split}.txt\’)if not os.path.exists(split_file):
raise FileNotFoundError(f\”划分文件不存在: {split_file}\”)with open(split_file, \’r\’) as f:
image_ids = [line.strip() for line in f if line.strip()]return image_ids
def parse_annotation(self, image_id: str) -> Dict:
\”\”\”
解析单个图片的标注文件Args:
image_id: 图片ID(不含扩展名)Returns:
包含标注信息的字典
\”\”\”
xml_path = os.path.join(self.annotations_dir, f\'{image_id}.xml\’)if not os.path.exists(xml_path):
raise FileNotFoundError(f\”标注文件不存在: {xml_path}\”)tree = ET.parse(xml_path)
root = tree.getroot()# 初始化标注信息
annotation = {
\’image_path\’: os.path.join(self.images_dir, f\'{image_id}.jpg\’),
\’width\’: int(root.find(\’size/width\’).text),
\’height\’: int(root.find(\’size/height\’).text),
\’depth\’: int(root.find(\’size/depth\’).text),
\’objects\’: []
}# 解析每个目标对象
for obj in root.findall(\’object\’):
obj_info = {
\’name\’: obj.find(\’name\’).text,
\’class_id\’: self.class2id[obj.find(\’name\’).text],
\’difficult\’: int(obj.find(\’difficult\’).text),
\’bndbox\’: {
\’xmin\’: int(obj.find(\’bndbox/xmin\’).text),
\’ymin\’: int(obj.find(\’bndbox/ymin\’).text),
\’xmax\’: int(obj.find(\’bndbox/xmax\’).text),
\’ymax\’: int(obj.find(\’bndbox/ymax\’).text)
}
}
annotation[\’objects\’].append(obj_info)return annotation
def load_image(self, image_id: str) -> Tuple[cv2.Mat, Dict]:
\”\”\”
加载单个图片及其标注信息Args:
image_id: 图片IDReturns:
(图片数组, 标注信息字典)
\”\”\”
annotation = self.parse_annotation(image_id)
image = cv2.imread(annotation[\’image_path\’])
# 转换为RGB格式(OpenCV默认是BGR)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)return image, annotation
def __len__(self) -> int:
\”\”\”返回数据集大小\”\”\”
return len(self.image_ids)def __getitem__(self, idx: int) -> Tuple[cv2.Mat, Dict]:
\”\”\”通过索引获取数据\”\”\”
if idx < 0 or idx >= len(self.image_ids):
raise IndexError(\”索引超出范围\”)image_id = self.image_ids[idx]
return self.load_image(image_id)def visualize_sample(self, idx: int):
\”\”\”可视化单个样本\”\”\”
image, annotation = self[idx]# 创建绘图对象
fig, ax = plt.subplots(1, figsize=(10, 8))
ax.imshow(image)# 绘制每个目标的边界框
for obj in annotation[\’objects\’]:
bbox = obj[\’bndbox\’]
# 创建矩形框
rect = patches.Rectangle(
(bbox[\’xmin\’], bbox[\’ymin\’]),
bbox[\’xmax\’] – bbox[\’xmin\’],
bbox[\’ymax\’] – bbox[\’ymin\’],
linewidth=2,
edgecolor=\’red\’,
facecolor=\’none\’
)
ax.add_patch(rect)
# 添加类




