第4章:目标检测基础
目标检测,说白了就是让机器在图像里找到「什么东西在哪儿」。我刚开始接触这个领域时,觉得这问题挺简单——不就是找东西嘛。后来自己动手写代码才发现,这里面的门道比想象中深得多。
这一章,我们聊聊目标检测的两条技术路线:传统方法和深度学习方法。两条路各有千秋,我建议你都了解一下。
4.1 传统方法:阈值分割与边缘检测
先说说传统方法。嗯,这里要注意,虽然现在深度学习很火,但传统方法在某些场景下依然好用。比如在工业质检中,光照可控、背景单一,传统方法反而更稳定、更省资源。
4.1.1 阈值分割
阈值分割的原理很简单:设定一个阈值,把像素分成两类。高于阈值的算一类,低于阈值的算另一类。
核心思想:图像中目标与背景的灰度值有明显差异时,用阈值就能把它们分开。
我做过一个项目,要在传送带上检测金属零件。当时背景是黑色传送带,零件是亮银色。用阈值分割,一行代码就搞定了。你想想看,如果用深度学习,还得标注几千张图,训练半天,何必呢?
import cv2
import numpy as np
# 读取灰度图
img = cv2.imread('part.jpg', 0)
# 简单阈值分割
ret, thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# 自适应阈值(应对光照不均)
adaptive_thresh = cv2.adaptiveThreshold(
img, 255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2
)
我的经验:实际项目中,光照变化是最大的敌人。我建议优先尝试自适应阈值,它比固定阈值鲁棒得多。
4.1.2 边缘检测
边缘检测是另一种经典方法。它的思路是:目标与背景的交界处,像素值会发生剧烈变化。找到这些变化的位置,就找到了目标的轮廓。
Canny边缘检测是我最常用的。它有三个关键参数:低阈值、高阈值和核大小。调参是个手艺活,我刚开始时也经常调得一头雾水。
# Canny边缘检测
edges = cv2.Canny(img, 50, 150)
# 找到轮廓
contours, hierarchy = cv2.findContours(
edges,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE
)
# 绘制轮廓
cv2.drawContours(img_color, contours, -1, (0, 255, 0), 2)
避坑指南:我曾经在一条产线上调试边缘检测,发现检测结果时好时坏。排查了两天才发现,是传送带上的油污反光导致的。后来加了偏振片,问题才解决。环境因素,千万别忽视。
4.2 传统方法的局限性
传统方法虽然快,但局限性也很明显。我总结了几点:
- 对光照敏感:换个灯光,阈值就得重调
- 对背景敏感:背景一复杂,分割就失效
- 无法区分类别:能检测到「有个东西」,但不知道「是什么东西」
- 多目标重叠时困难:物体一重叠,轮廓就分不清了
为什么会这样?因为传统方法本质上是在做「像素级」的判断,没有「语义」层面的理解。这就引出了深度学习方法。
4.3 深度学习方法:YOLO与SSD
深度学习方法的出现,彻底改变了目标检测的格局。它不再依赖手工设计的特征,而是让网络自己学习「什么是目标」。我个人觉得,这是计算机视觉领域近十年最重要的突破之一。
4.3.1 YOLO:你只看一次
YOLO的全称是You Only Look Once。名字很直白——只看一次,就能把目标检测出来。
它的核心思想是把检测问题转化为回归问题。网络直接输出边界框的位置和类别概率。速度快得惊人,在GPU上能跑到每秒上百帧。
# 使用YOLOv8的示例(简化版)
from ultralytics import YOLO
# 加载预训练模型
model = YOLO('yolov8n.pt')
# 检测图像
results = model('image.jpg')
# 解析结果
for result in results:
boxes = result.boxes
for box in boxes:
x1, y1, x2, y2 = box.xyxy[0]
conf = box.conf[0]
cls = box.cls[0]
print(f'检测到: {model.names[int(cls)]}, 置信度: {conf:.2f}')
YOLO的优势:速度快、精度高、端到端训练。特别适合实时场景,比如视频监控、自动驾驶。
4.3.2 SSD:单次多框检测器
SSD是另一种单阶段检测器。它和YOLO的思路类似,但有个关键区别:SSD在不同尺度的特征图上做检测。
为什么要这样做?因为目标有大有小。大目标在高层特征图上检测,小目标在低层特征图上检测。这样能兼顾不同尺寸的目标。
| 方法 | 速度 | 小目标检测 | 训练难度 |
|---|---|---|---|
| YOLO | 极快 | 一般 | 中等 |
| SSD | 快 | 较好 | 较低 |
| Faster R-CNN | 慢 | 好 | 高 |
我的建议:如果你刚开始做目标检测,从YOLO入手最合适。社区活跃、文档齐全、预训练模型多。等熟悉了再尝试SSD或其他方法。
4.4 传统方法与深度学习的对比
我经常被问到:「到底该用传统方法还是深度学习方法?」我的回答是:看场景。
- 场景简单、要求实时:传统方法更合适。比如嵌入式设备上的简单检测
- 场景复杂、需要泛化:深度学习是首选。比如开放环境下的多类别检测
- 数据量少:传统方法可能更好。深度学习需要大量标注数据
- 计算资源有限:传统方法占优势。深度学习需要GPU
我个人习惯的做法是:先用传统方法快速验证可行性,如果效果不行,再上深度学习。这样能节省大量时间。
4.5 本章知识体系
下面这张图,是我梳理的本章知识结构。你可以用它来快速回顾。
这张图把本章的核心内容串起来了。左边是传统方法,右边是深度学习方法,底部是选择建议。你可以把它当作一个决策参考。
最后提醒一句:别盲目追求新技术。我见过太多人一上来就上YOLO,结果数据不够、硬件不行,折腾一个月还不如用阈值分割。技术选型,务实最重要。
可可精品资料库