第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 SSD 局限性:光照敏感、背景敏感 优势:速度快、精度高、泛化强 选择建议:看场景、看资源、看需求

这张图把本章的核心内容串起来了。左边是传统方法,右边是深度学习方法,底部是选择建议。你可以把它当作一个决策参考。

最后提醒一句:别盲目追求新技术。我见过太多人一上来就上YOLO,结果数据不够、硬件不行,折腾一个月还不如用阈值分割。技术选型,务实最重要。

可可精品资料库