4、添加标签与置信度:cv2.putText在框上显示类别名称和置信度分数

检测框画好了,但光有框可不行。你想想看,一个框框在那,谁知道它代表什么?是猫是狗还是汽车?

嗯,这就是我们今天要解决的问题——在框上添加标签和置信度分数。说白了,就是让检测结果「开口说话」。

4.1 为什么需要标签和置信度?

我在项目中遇到过这么个事:有一次给客户演示YOLO检测效果,框画得漂漂亮亮的,但客户问了一句:「这个框里是什么?」我当场就尴尬了——框上没文字啊!

从那以后,我养成了一个习惯:只要画框,就必须带上标签和置信度。原因很简单:

  • 可读性:一眼就知道检测到了什么
  • 可信度:置信度分数告诉你这个检测有多靠谱
  • 调试效率:低置信度的框可以快速定位问题

核心原则:标签和置信度不是装饰,是调试信息的一部分。它们能帮你快速判断模型表现。

4.2 cv2.putText 基础用法

OpenCV 里添加文字用的是 cv2.putText()。这个函数参数不少,但常用的就这几个:

cv2.putText(
    img,           # 图像
    text,          # 要显示的文字
    org,           # 文字左下角坐标 (x, y)
    fontFace,      # 字体类型
    fontScale,     # 字体大小
    color,         # 颜色 (B, G, R)
    thickness,     # 线条粗细
    lineType       # 线型(可选)
)

我个人习惯用 cv2.FONT_HERSHEY_SIMPLEX 字体,简单清晰,兼容性也好。

4.3 实战:在检测框上添加标签

假设我们已经有了检测结果,每个检测框包含:class_idconfidencex1y1x2y2

来看一个完整的示例:

import cv2
import numpy as np

# 类别名称列表(以COCO数据集为例)
class_names = ['person', 'bicycle', 'car', 'motorcycle', 'airplane',
               'bus', 'train', 'truck', 'boat', 'traffic light']

def draw_detection(img, class_id, confidence, x1, y1, x2, y2):
    """
    在图像上绘制检测框和标签
    """
    # 1. 先画检测框
    color = (0, 255, 0)  # 绿色框
    cv2.rectangle(img, (x1, y1), (x2, y2), color, 2)
    
    # 2. 构造标签文本
    label = f"{class_names[class_id]}: {confidence:.2f}"
    
    # 3. 计算文字尺寸
    font = cv2.FONT_HERSHEY_SIMPLEX
    font_scale = 0.6
    thickness = 2
    (text_w, text_h), baseline = cv2.getTextSize(label, font, font_scale, thickness)
    
    # 4. 绘制文字背景(提高可读性)
    # 文字放在框的左上角
    label_x = x1
    label_y = y1 - 10  # 稍微往上偏移
    
    # 如果文字超出图像上边界,就放在框内
    if label_y - text_h < 0:
        label_y = y1 + text_h + 10
    
    # 画背景矩形
    cv2.rectangle(img, 
                  (label_x, label_y - text_h - 5),
                  (label_x + text_w + 5, label_y + 5),
                  color, -1)  # -1 表示填充
    
    # 5. 写文字(白色文字)
    cv2.putText(img, label, (label_x + 2, label_y - 2),
                font, font_scale, (255, 255, 255), thickness)
    
    return img

# 模拟一个检测结果
img = np.zeros((480, 640, 3), dtype=np.uint8)
img = draw_detection(img, 0, 0.95, 100, 100, 300, 400)

cv2.imshow('Detection', img)
cv2.waitKey(0)

小技巧:文字背景用填充矩形,可以避免文字和检测框颜色重叠时看不清。白色文字配绿色背景,清晰度最高。

4.4 置信度分数的显示策略

置信度不是随便显示的。我曾经犯过一个错误:把所有检测结果的置信度都显示出来,结果画面上一堆「0.02」「0.03」这种低分框,看着特别乱。

后来我总结了一套策略:

置信度范围 显示方式 颜色建议
>= 0.7 正常显示,绿色框 (0, 255, 0)
0.5 ~ 0.7 显示,但用黄色框 (0, 255, 255)
0.3 ~ 0.5 显示,红色框,加警告 (0, 0, 255)
< 0.3 不显示(过滤掉) -

注意:置信度阈值不要设得太低。我一般设 0.5 作为最低显示阈值,低于这个值的框大概率是误检。

4.5 进阶:自适应文字位置

框的位置千变万化,文字放哪最合适?

我常用的策略是:

  1. 优先放框的左上角:这是最自然的位置
  2. 如果左上角超出图像边界:放到框的右下角
  3. 如果框太小:文字放到框外,用连线指示

来看一个自适应位置的实现:

def get_label_position(x1, y1, x2, y2, text_w, text_h, img_h, img_w):
    """
    智能选择标签位置
    返回 (label_x, label_y) 文字左下角坐标
    """
    # 默认放左上角
    label_x = x1
    label_y = y1 - 10
    
    # 检查是否超出上边界
    if label_y - text_h < 0:
        # 尝试放右下角
        label_x = x2 - text_w - 10
        label_y = y2 + text_h + 10
        
        # 如果右下角也超出,放框内顶部
        if label_y > img_h:
            label_x = x1 + 5
            label_y = y1 + text_h + 10
    
    # 确保不超出左右边界
    label_x = max(5, min(label_x, img_w - text_w - 10))
    
    return label_x, label_y

4.6 格式化显示的艺术

同样的信息,不同的显示方式,效果天差地别。

我推荐几种格式化方式:

  • 简洁版person 0.95 —— 适合快速调试
  • 详细版person: 95.2% —— 适合展示给客户
  • 多行版person\n95.2% —— 适合框比较宽的场景

多行文本的实现稍微麻烦一点,因为 cv2.putText 不支持换行符。需要手动分行绘制:

def draw_multiline_text(img, lines, x, y, font, scale, color, thickness):
    """
    绘制多行文本
    """
    line_height = cv2.getTextSize("A", font, scale, thickness)[0][1] + 5
    
    for i, line in enumerate(lines):
        y_pos = y + i * line_height
        cv2.putText(img, line, (x, y_pos), font, scale, color, thickness)

4.7 性能优化建议

如果你是在视频流上做实时检测,文字绘制也可能成为瓶颈。我踩过这个坑:

  • 避免频繁调用 getTextSize:可以预先计算好常用文字的尺寸
  • 减少文字绘制次数:只绘制置信度高于阈值的框
  • 使用固定字体大小:不要根据框大小动态调整字体,那样计算量太大

我的经验:在实时视频流中,文字绘制占用的时间不要超过总处理时间的 5%。如果发现卡顿,优先检查是不是文字绘制太频繁了。

4.8 完整示例:批量绘制检测结果

最后,给一个实际项目中常用的批量绘制函数:

def draw_detections(img, detections, class_names, conf_threshold=0.5):
    """
    批量绘制检测结果
    detections: [(class_id, confidence, x1, y1, x2, y2), ...]
    """
    for det in detections:
        class_id, confidence, x1, y1, x2, y2 = det
        
        # 过滤低置信度
        if confidence < conf_threshold:
            continue
        
        # 根据置信度选择颜色
        if confidence >= 0.7:
            color = (0, 255, 0)    # 绿色
        elif confidence >= 0.5:
            color = (0, 255, 255)  # 黄色
        else:
            color = (0, 0, 255)    # 红色
        
        # 绘制框和标签
        img = draw_detection(img, class_id, confidence, 
                            x1, y1, x2, y2, class_names, color)
    
    return img

嗯,到这里你应该已经掌握了如何在检测框上添加标签和置信度。记住,好的可视化调试工具,能让你的模型调优效率翻倍。

下一章,我们会聊聊如何用不同颜色区分不同类别,让检测结果更加一目了然。