前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从一个 OpenCV 的 BUG 说起~

从一个 OpenCV 的 BUG 说起~

作者头像
机器视觉CV
修改2019-11-25 21:10:59
1.1K0
修改2019-11-25 21:10:59
举报
文章被收录于专栏:机器视觉CV

本文建议阅读时间 8 min

我们上次分享过 YOLO 实现目标检测,但是,当笔者今天再测试时发现里面竟然存在一个有趣的 BUG

但我重新运行目标检测的程序时,测试了以下这只可爱的猫咪:

此时我就在想,目标检测不是要经过一步 NMS(非极大值抑制)吗,才能得到最后的输出框,那么我可不可以在还没有经过 NMS 时,把所有的锚框都绘制出来呢,那就动手吧

BUG 分析

WHAT,怎么还有个 bed (上图左上角那个蓝色框框)给画出来,但是预测的时候却没有呢,于是我又回顾了一遍 非极大值抑制(NMS)算法:从输出结果中提取最有可能的对象和其对应的边界框。流程如下:

  • 1.设置一个 Score 的阈值,一个 IOU 的阈值(overlap);
  • 2.对于每类对象,遍历属于该类的所有候选框, ① 过滤掉 Score 低于 Score 阈值的候选框; ② 找到剩下的候选框中最大 Score 对应的候选框,添加到输出列表; ③ 进一步计算剩下的候选框与 ② 中输出列表中每个候选框的 IOU,若该 IOU 大于设置的 IOU 阈值,将该候选框过滤掉(大于一定阈值,代表重叠度比较高),否则加入输出列表中; ④ 最后输出列表中的候选框即为图片中该类对象预测的所有边界框
  • 3.返回步骤 2 继续处理下一类对象。

看着没毛病是吧,那我们就看看 OpenCV 的非极大值抑制是怎么实现的吧

代码语言:javascript
复制
indices    =   cv.dnn.NMSBoxes(bboxes, scores, score_threshold, nms_threshold[, eta[, top_k]])
# bboxes,scores 分别是经过 YOLO 检测后,得到所有候选框及其分数
# score_threshold 是我们设定的要选定的候选框的分数值
# nms_threshold 是我们设定的 NMS 的参数,也就是两个边界框的 IoU 

咦!不是说对每类的对象执行非极大值抑制操作吗,怎么没有各个类别的参数输入???

难道是 OpenCV 的 BUG(/兴奋脸)?还是另有所用?

既然遇见了这个问题,那么,我们就把这个 BUG 给填上呗!

先上代码

代码语言:javascript
复制
def NMSBoxes_fix(boxes, confidences, confidence_thre, nms_thre, class_id):
    class_id_set = set(class_id)  #  总共有几类
    result = []  #  用来存储结果的
    for cls in class_id_set:  # 遍历每个类别
        cls_boxes = []  # 用来保存每个类别的  边框
        cls_confidences = []  # 用来保存每个类别边框的分数
        indices = [i for i, c in enumerate(class_id) if c == cls] # 某一类在原始输入的所有索引
        for i in indices:
            cls_boxes.append(boxes[i])  # 把属于该类的框框和分数找出来
            cls_confidences.append(confidences[i]) 
        idxs = cv2.dnn.NMSBoxes(cls_boxes, cls_confidences, confidence_thre, nms_thre)  # 对每类进行 NMS 操作
        for i in idxs:  #  找出原始输入的索引,并把经过 NMS 操作后保留下来的框框的索引保存下来到一个列表中
            result.append([indices[i[0]]])  #  
    return np.array(result)  #  opencv 原始的 NMS 输出是一个 np.array 的数据,所以我们也将其转化成指定格式

其实很简单,我们只要先把每个类别对应的框框找出来,然后对其进行 NMS 操作,最后,将各个类别经过 NMS 操作的结果合并起来输出即可。

写好了代码,我们测试一下我们的结果呗,用一张目标检测的常用测试图进行实验。

首先,我们设置一下我们实验的参数:

  • nms_thre= 0.5 overlap 即 IoU 值
  • confidence_thre = 0.5 边框属于某个类别的分数的阈值

我们分别使用 OpenCV 自带的 NMS 操作和自己写的 MNS 操作进行对比,即:

代码语言:javascript
复制
# 使用非极大值抑制方法抑制弱、重叠边界框
idxs = cv2.dnn.NMSBoxes(boxes, confidences, confidence_thre, nms_thre)

# 自己修正过的 非极大值抑制方法
idxs = NMSBoxes_fix(boxes, confidences, confidence_thre, nms_thre, classIDs)

得到的结果是一样的,因为图中 dog 区域在 bicycle 区域的 IoU 大概是 0.255,我们实验的值是 nms_thre=0.5 自然得到的结果是一样的

此时,我们改变实验的参数时:

  • nms_thre= 0.2 overlap 即 IoU 值
  • confidence_thre = 0.5 边框属于某个类别的分数的阈值

这时,OpenCV 自带的 NMS 得到的结果如下图,原因是 dog 的分数比较高,在 OpenCV 进行 NMS 操作时(即不考虑类别时),会把分数较高的 dog 保留下来,而分数较低的 bicycle 给滤出掉

而使用我们自己写的 NMS 操作(考虑类别时)得到的结果还是同上面一样

思考:
  • 一张好的测试图片是如此的重要,要是没有那张可爱的猫咪图片,我也发现不了这个问题
  • 现成的框架不一定是正确的,可能也得根据你的需求进行更改
  • 多发现,对每步的处理知根知底

要有打破沙锅问到底的决心

完整的程序在 https://github.com/FLyingLSJ/Computer_Vision_Project 上,欢迎 Fork Star。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-10-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 机器视觉CV 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • BUG 分析
  • 思考:
相关产品与服务
图像识别
腾讯云图像识别基于深度学习等人工智能技术,提供车辆,物体及场景等检测和识别服务, 已上线产品子功能包含车辆识别,商品识别,宠物识别,文件封识别等,更多功能接口敬请期待。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档