nms实现

# 定义一个nms函数
def nms(dets, thresh):'''input:dets: dets是(n,5)的ndarray,第0维度的每个元素代表一个框:[x1, y1, x2, y2, score] thresh: floatoutput:index'''x1 = dets[:, 0] # dets:(n,5)  x1:(n,)  dets是ndarray, x1是ndarrayy1 = dets[:, 1]x2 = dets[:, 2]y2 = dets[:, 3]scores = dets[:, 4] # scores是ndarray# 每一个候选框的面积areas = (x2 - x1 + 1) * (y2 - y1 + 1) # areas:(n,)# order是按照score降序排序的order = scores.argsort()[::-1] # order:(n,) 降序下标 order是ndarraykeep = []while order.size > 0:i = order[0] # i 是当下分数最高的框的下标# print(i)keep.append(i)# 计算当前概率最大矩形框与其他矩形框的相交框的坐标,会用到numpy的broadcast机制,得到的是向量# 当order只有一个值的时候,order[1]会报错说index out of range,而order[1:]会是[],不报错,[]也可以作为x1的索引,x1[[]]为[]xx1 = np.maximum(x1[i], x1[order[1:]]) # xx1:(n-1,)的ndarray x1[i]:numpy_64浮点数一个,x1[order[1:]]是个ndarray,可以是空的ndarray,如果是空ndarray那么xx1为空ndarray,如果非空,那么x1[order[1:]]有多少个元素,xx1就是有多少个元素的ndarray。x1[]是不是ndarray看中括号内的是不是ndarray,看中括号内的是不是ndarray看中括号内的order[]的中括号内有没有冒号,有冒号的是ndarray,没有的是一个数。yy1 = np.maximum(y1[i], y1[order[1:]])xx2 = np.minimum(x2[i], x2[order[1:]])yy2 = np.minimum(y2[i], y2[order[1:]])# 计算相交框的面积,注意矩形框不相交时w或h算出来会是负数,用0代替w = np.maximum(0.0, xx2 - xx1 + 1) # xx2-xx1是(n-1,)的ndarray,w是(n-1,)的ndarray, n会逐渐减小至1# 当xx2和xx1是空的,那w是空的h = np.maximum(0.0, yy2 - yy1 + 1)inter = w * h # inter是(n,)的ndarray# 当w和h是空的,inter是空的# 计算重叠度IOU:重叠面积/(面积1+面积2-重叠面积)eps = np.finfo(areas.dtype).eps # 除法考虑分母为0的情况,np.finfo(dtype).eps,np.finfo(dtype)是个类,它封装了机器极限浮点类型的数,比如eps,episilon的缩写,表示小正数。ovr = inter / np.maximum(eps, areas[i] + areas[order[1:]] - inter) # n-1   #一旦(面积1+面积2-重叠面积)为0,就用eps进行替换# 当inter为空,areas[i]无论inter空不空都是有值的,那么ovr也为空# 找到重叠度不高于阈值的矩形框索引inds = np.where(ovr <= thresh)[0]# 当ovr为空, inds为空# 将order序列更新,由于前面得到的矩形框索引要比矩形框在原order序列中的索引小1,所以要把这个1加回来order = order[inds + 1]# 当inds为空,原来的order不为空,那么索引后的order为空print("order:{}".format(order))return keepimport numpy as np
import cv2# 读入图片,录入原始框([x1, y1, x2, y2, score])
image = cv2.imread('w.jpg')
boxes = np.array([[5,  52, 171,    270, 0.9999],
[13,    1,  179,    268, 0.9998],
[20,    7,  176,    262, 0.8998],
[7, 5,  169,    272, 0.9687],
[3, 43, 162,    256, 0.9786],
[10,    56, 167,    266, 0.8988]])# 将框绘制在图像上
image_for_nms_box = image.copy()
for box in boxes:x1, y1, x2, y2, score = int(box[0]), int(box[1]), int(box[2]), int(box[3]), box[4] # x:col y:rowimage_for_nms_box = cv2.rectangle(image_for_nms_box, (x1, y1), (x2, y2), (0,255,0), 2)
cv2.imwrite("w_all_boxes.jpg", image_for_nms_box)
cv2.imshow('w_all_boxes', image_for_nms_box)# 使用nms对框进行筛选
keep = nms(boxes, thresh=0.2) # 0.2可以,0.9有很多框存留,因为iou小于thresh才能存留,当设定的thresh过大,存留下来的框就多
nms_boxs = boxes[keep]# 将筛选过后的框绘制在图像上
image_for_nms_box = image.copy()
for box in nms_boxs:x1, y1, x2, y2, score = int(box[0]), int(box[1]), int(box[2]), int(box[3]), box[4] # x:col y:rowimage_for_nms_box = cv2.rectangle(image_for_nms_box, (x1, y1), (x2, y2), (0,255,0), 2)
cv2.imwrite("w_nms.jpg", image_for_nms_box)
cv2.imshow('w_nms', image_for_nms_box)cv2.waitKey()
cv2.destroyAllWindows()

nms前后效果图

before:

after:

nms存在的问题

如果两个物体 的iou很大,那么网络生成的关于这两个物体的bboxes的iou也很大。nms的做法是,假设第一个物体的某个bbox分数最高,那么这个物体被记录下来,计算它跟其他bbox的iou,如果iou大于某个阈值就把对应的bbox剔除,而跟这个物体的iou很大的物体的bbox就会被剔除掉,也就是上图出现的明明有两个物体,经过nms后只剩下一个bbox的原因。

soft_nms原理

nms的原理可以表示为以下公式:
si=siifiou<thresh,else0s_i=s_i\ if\ iou<thresh, else\ 0si​=si​ if iou<thresh,else 0
sis_isi​代表第i个bbox的分数。
分数粗暴地由iou和thresh决定,当iou很大时直接置为0。
有人提出了soft_max,用于解决nms中两个物体iou很大导致的漏检问题,原理可以表示为以下公式:
si=si∗e−iou2/σs_i = s_i * e^{-iou^2/\sigma}si​=si​∗e−iou2/σ
这样分数由分数本身和iou共同决定,当iou很大时,分数并不会直接置为0,因为e−xe^{-x}e−x是单调递减,极限为0的函数,当x趋于正无穷大的时候才趋于0,本身不会等于0。另外,这个公式还有sis_isi​作为系数。
同时,它也保留了nms的优点,当两个物体的iou为0是,相互没有影响,因为e0e^0e0为1,si=sis_i=s_isi​=si​。另外,当两个物体越靠近,iou越大,惩罚越大,sis_isi​越小,这是由于e−xe^{-x}e−x单调递减的性质决定的。
得到了重新赋值的分数,人为设定一个阈值,当分数低于这个阈值,对应的bbox就被剔除,这就是soft_nms。
举个例子,比如上图,物体1 和物体2周围都有很多围绕着各自的框,假设物体1的某个框分数最高,那么这个框被记录。物体1周围的其他框跟这个被记录的框iou比物体2周围的框跟这个被记录的框iou大,所以惩罚更大,sis_isi​越小,并且由于小于阈值,所以被剔除掉了,(这一步可以在代码里打印出来,每次迭代的最后打印被保留下来的框的下标),那么接下来的迭代,一定是物体2周围本身分数最高的框被记录,然后物体2周围的其他框由于跟这个新的被记录的框的iou很大,被剔除掉了,所以最后剩下两个框。

soft_nms的优点

1,解决了物体挨得很近导致的漏检问题
2,需要增加的超参数很少,只增加了一个sigma,阈值nms本来也有,iou是算出来的
3,计算复杂度相对于nms没有增加,都是O(n^2),n是bboxes的数量。

soft_nms实现


import numpy as np# 定义一个nms函数
def soft_nms(dets, thresh=0.3, sigma=0.5): # score大于thresh的才能存留下来,当设定的thresh过低,存留下来的框就很多,所以要根据实际情况调参'''input:dets: dets是(n,5)的ndarray,第0维度的每个元素代码一个框:[x1, y1, x2, y2, score] thresh: floatsigma: flaotoutput:index'''x1 = dets[:, 0] # dets:(n,5)  x1:(n,)  dets是ndarray, x1是ndarrayy1 = dets[:, 1]x2 = dets[:, 2]y2 = dets[:, 3]scores = dets[:, 4] # scores是ndarray# 每一个候选框的面积areas = (x2 - x1 + 1) * (y2 - y1 + 1) # areas:(n,)# order是按照score降序排序的order = scores.argsort()[::-1] # order:(n,) 降序下标 order是ndarraykeep = []while order.size > 0:i = order[0] # i 是当下分数最高的框的下标# print(i)keep.append(i)# 计算当前概率最大矩形框与其他矩形框的相交框的坐标,会用到numpy的broadcast机制,得到的是向量# 当order只有一个值的时候,order[1]会报错说index out of range,而order[1:]会是[],不报错,[]也可以作为x1的索引,x1[[]]为[]xx1 = np.maximum(x1[i], x1[order[1:]]) # xx1:(n-1,)的ndarray x1[i]:numpy_64浮点数一个,x1[order[1:]]是个ndarray,可以是空的ndarray,如果是空ndarray那么xx1为空ndarray,如果非空,那么x1[order[1:]]有多少个元素,xx1就是有多少个元素的ndarray。x1[]是不是ndarray看中括号内的是不是ndarray,看中括号内的是不是ndarray看中括号内的order[]的中括号内有没有冒号,有冒号的是ndarray,没有的是一个数。yy1 = np.maximum(y1[i], y1[order[1:]])xx2 = np.minimum(x2[i], x2[order[1:]])yy2 = np.minimum(y2[i], y2[order[1:]])# 计算相交框的面积,注意矩形框不相交时w或h算出来会是负数,用0代替w = np.maximum(0.0, xx2 - xx1 + 1) # xx2-xx1是(n-1,)的ndarray,w是(n-1,)的ndarray, n会逐渐减小至1# 当xx2和xx1是空的,那w是空的h = np.maximum(0.0, yy2 - yy1 + 1)inter = w * h # inter是(n,)的ndarray# 当w和h是空的,inter是空的# 计算重叠度IOU:重叠面积/(面积1+面积2-重叠面积)eps = np.finfo(areas.dtype).eps # 除法考虑分母为0的情况,np.finfo(dtype).eps,np.finfo(dtype)是个类,它封装了机器极限浮点类型的数,比如eps,episilon的缩写,表示小正数。ovr = inter / np.maximum(eps, areas[i] + areas[order[1:]] - inter) # n-1   #一旦(面积1+面积2-重叠面积)为0,就用eps进行替换# 当inter为空,areas[i]无论inter空不空都是有值的,那么ovr也为空# 更新分数weight = np.exp(-ovr*ovr/sigma)scores[order[1:]] *= weight# 更新orderscore_order = scores[order[1:]].argsort()[::-1] + 1order = order[score_order]keep_ids = np.where(scores[order]>thresh)[0]order = order[keep_ids]return keepimport numpy as np
import cv2# 读入图片,录入原始人框([x1, y1, x2, y2, score])
image = cv2.imread('w.jpg')boxes = np.array([[5,    52, 171,    270, 0.9999],
[13,    1,  179,    268, 0.9998],
[20,    7,  176,    262, 0.8998],
[7, 5,  169,    272, 0.9687],
[3, 43, 162,    256, 0.9786],
[10,    56, 167,    266, 0.8988]])# 将框绘制在图像上
image_for_nms_box = image.copy()
for box in boxes:x1, y1, x2, y2, score = int(box[0]), int(box[1]), int(box[2]), int(box[3]), box[4] # x:col y:rowimage_for_nms_box = cv2.rectangle(image_for_nms_box, (x1, y1), (x2, y2), (0,255,0), 2)
cv2.imwrite("w_all.jpg", image_for_nms_box)
cv2.imshow('w_all', image_for_nms_box)# 使用soft_nms对框进行筛选
keep = soft_nms(boxes)
soft_nms_boxs = boxes[keep]# 将筛选过后的框绘制在图像上
image_for_nms_box = image.copy()
for box in soft_nms_boxs:x1, y1, x2, y2, score = int(box[0]), int(box[1]), int(box[2]), int(box[3]), box[4]image_for_nms_box = cv2.rectangle(image_for_nms_box, (x1, y1), (x2, y2), (0,255,0), 2)
# Syntax: cv2.imwrite(filename, image)
cv2.imwrite("w_soft_nms.jpg", image_for_nms_box)
cv2.imshow('w_soft_nms', image_for_nms_box)cv2.waitKey()
cv2.destroyAllWindows()

soft_nms前后对比图

before:

after:

nms和soft_nms效果对比图

nms:

soft_nms

原图

soft_nms实现相关推荐

  1. yolov5 soft_nms cluster_nms,cluster_SPM_nms,cluster_diounms,cluster_SPM_dist_nms,diou_nms

    本机项目: yolov5_mangguo_new 调用: # Non-maximum suppressionif method == 'standard':nms_indices = nms(pred ...

  2. CornerNet:实现demo、可视化heatmap、测试各类别精度

    CornerNet:实现demo.可视化heatmap.测试各类别精度 文章目录 CornerNet:实现demo.可视化heatmap.测试各类别精度 前言 实现demo 方案一 方案二 可视化he ...

  3. 目标检测比赛中的tricks集锦

    ↑ 点击蓝字 关注视学算法 作者丨初识CV@知乎 来源丨https://zhuanlan.zhihu.com/p/102817180 编辑丨极市平台 极市导读 本文总结了目标检测比赛中的8点技巧,包含 ...

  4. 干货 | 目标检测技巧大汇总(含代码与解读)

    点击上方"视学算法",选择"星标"公众号 重磅干货,第一时间送达 来自 | 知乎    作者丨初识CV 来源丨https://zhuanlan.zhihu.co ...

  5. 【干货】目标检测比赛中的trick

    关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! 作者:初识CV https://zhuanlan.zhihu.com/p/1028 ...

  6. 目标检测比赛中的trick

    关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! 作者:初识CV https://zhuanlan.zhihu.com/p/1028 ...

  7. Windows 编译cython nms

    https://github.com/pjl1995/CTracker/blob/master/model.py 调用: from lib.cython_nms.cpu_nms import soft ...

  8. NMS和soft-nms算法

    NMS和soft-nms算法 nms :iou阈值的作用,如果iou大于阈值,则认为是两个框是同一个物体,所以会删除分数小的框. https://blog.csdn.net/eurus_/articl ...

  9. 【mmdetection】参数解析 转载

    原文地址: https://blog.csdn.net/u013066730/article/details/106859399/?utm_medium=distribute.pc_relevant. ...

最新文章

  1. javascript迭代器_JavaScript迭代器概述
  2. 人工智能产业发展联盟公布首轮AI芯片基准评测结果,评估工具已开源
  3. MSE病毒库离线更新包
  4. js observer 添加_简单了解4种JS设计模式
  5. javafx设计自适应大小的窗口_“翅膀”开始流行 宝马坐不住了 开发摩托车自适应空气动力设计...
  6. Tomcat 配置支持APR
  7. AN IMAGE IS WORTH 16X16 WORDS :TRANSFORMERS FOR IMAGE RECOGNITION AT SCALE(VIT)
  8. yii框架cookie写入与读取方法
  9. 关于BEA-000402和BEA-000438(没有进程来读取写入管道的数据)
  10. windchill文件无法上传服务器,Windchill MethodServer无法启动
  11. 【分治】LeetCode 69. Sqrt(x)
  12. Android 获取联系人列表
  13. linux佳能打印机驱动下载,佳能lbp2900打印机驱动下载
  14. 机房动环监控系统方案
  15. java域名校验_域名规则校验Java版本
  16. Qt QImage类详解(QImage类型转换、QImage类函数及QImage像素操作)
  17. Servlet概念性回顾(结合Ajax)
  18. SVM算法教科书(一)
  19. 经济低迷影响亚洲“黑池”
  20. Python 爬虫多线程爬取美女图片保存到本地

热门文章

  1. vim粘贴从其他地方复制过来的内容时多出来其他字符比如反斜杠或空格
  2. http协议的状态码(常见网页错误代码)
  3. 10 个必须下载的 Google Chrome 插件
  4. ASP.NET中 ValidationSummary(验证总结)的使用
  5. CSS3 聚光灯特效
  6. iOS开发之---用iTunes打包ipa
  7. Carson带你学JVM:图文解析Java虚拟机内存结构
  8. 【Python】推荐五个常用的图像处理库
  9. BERT融合知识图谱之模型及代码浅析
  10. 寒假-第一周-几何-(点线关系的问题)