• IOU和NMS图解(附Python和C++代码)


    IOU计算: 交并比

    先上代码

    Python版

    class Iou:
        def compute_iou(self, x1, y1, x2, y2, x3, y3, x4, y4):
        
            #两矩阵面积之和
            area = (x2 - x1) * (y2 - y1) + (x4 - x3) * (y4 - y3)
    		# 两矩阵相交部分的左上角和右下角坐标确定
            middle_x1 = max(x1, x3)
            middle_x2 = min(x2, x4)
            middle_y1 = max(y1, y3)
            middle_y2 = min(y2, y4)
            middle_w = max(0.0, middle_x2 - middle_x1)
            middle_h = max(0.0, middle_y2 - middle_y1)
            
            #两矩阵之交
            middle_area = middle_w * middle_h
            
            # return 交 / 并
            return middle_area / (area - middle_area)
    
    
    if __name__=="__main__":
        rec1 = [27, 661, 47, 679]
        rec2 = [27, 662, 47, 682]
        a = Iou().compute_iou(*rec1, *rec2)
        print(f"a: {a}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    C++ 版

    推导过程

    在这里插入图片描述

    IOU公式如下:

    I O U = 两 矩 阵 交 / 两 矩 阵 并 IOU = 两矩阵交 /两矩阵并 IOU=/

    以左上角为远点。已知两个矩阵的左上角和右下角坐标,计算IOU。具体地,
    第一个矩形rec1,左上:(x1, y1) ,右下:(x2, y2) ;
    第二个矩形rec2,左上:(x3, y3) ,右下:(x4, y4) ;
    很容易计算两个矩阵的和,公式如下:
    a r e a = r e c 1 + r e c 2 = ( x 2 − x 1 ) ∗ ( y 2 − y 1 ) + ( x 4 − x 3 ) ∗ ( y 4 − y 3 ) area = rec1 + rec2 = (x2 - x1)*(y2 - y1) + (x4 - x3)*(y4 - y3) area=rec1+rec2=(x2x1)(y2y1)+(x4x3)(y4y3)
    要计算两矩阵的交,则要确定相交的面积的左上和右下坐标,则有:
    m i d d l e _ l e f t = m a x ( x 1 , x 3 ) middle\_left = max(x1, x3) middle_left=max(x1,x3)
    m i d d l e _ r i g h t = m i n ( x 2 , x 4 ) middle\_right = min(x2, x4) middle_right=min(x2,x4)
    m i d d l e _ t o p = m a x ( y 1 , y 3 ) middle\_top = max(y1, y3) middle_top=max(y1,y3)
    m i d d l e _ b u t t o m = m i n ( y 2 , y 4 ) middle\_buttom = min(y2, y4) middle_buttom=min(y2,y4)
    因此矩阵的交为:
    m i d d l e _ a r e a = ( m i d d l e _ r i g h t − m i d d l e _ l e f t ) ∗ ( m i d d l e _ b u t t o m − m i d d l e _ t o p ) middle\_area = (middle\_right - middle\_left) * (middle\_buttom - middle\_top) middle_area=(middle_rightmiddle_left)(middle_buttommiddle_top)

    矩阵的并为:
    矩 阵 的 并 = 矩 阵 的 和 − 矩 阵 的 交 矩阵的并 = 矩阵的和 - 矩阵的交 =
    因此最终公式为
    I O U = m i d d l e _ a r e a a r e a − m i d d l e _ a r e a IOU = \frac{middle\_area}{area - middle\_area} IOU=areamiddle_areamiddle_area

    NMS:非极大值抑制(Non-Maximum Suppression, NMS)

    先上代码

    import numpy as np
    import matplotlib.pyplot as plt
    
    class Solution:
        def nms(self, boxes, threshold):
    
            # 计算所有候选框面积,利用numpy一次计算所有的候选框
            x1, y1, x2, y2, score = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3],  boxes[:, 4]
    
            #计算每个框的面积
            areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    
            # 对每个框的置信度进行从小到大排序,order存储的是对应score中从小到大的索引值
            order = np.argsort(score)
    
            # keep是返回值,经过 NMS 后挑选出的框
            keep = []
    
            while order.size > 0:
                # 将当前置信度最大的框加入返回值,并用其抑制iou>给定阈值的框,小于阈值的框继续做NMS,直到所有框被挑选完
                index = order[-1]
                keep.append(index)
    
                # 计算置信度最大的框和其余框的iou,这里计算的数量为当前order.size - 1.
                middle_x1 = np.maximum(x1[index], x1[order[:-1]])
                middle_x2 = np.minimum(x2[index], x2[order[:-1]])
                middle_y1 = np.maximum(y1[index], y1[order[:-1]])
                middle_y2 = np.minimum(y2[index], y2[order[:-1]])
    
                # 特殊情况处理,对左上角和右下角框的坐标进行判断:右下角坐标 - 左上角坐标 > 0 返回对应值,否则返回 0
                middle_w = np.maximum(0.0, middle_x2 - middle_x1 + 1)
                middle_h = np.maximum(0.0, middle_y2 - middle_y1 + 1)
                middle_area = middle_h * middle_w
    
                # 计算当前置信度最大的框与其余框的iou,将iou大于阈值的框删除
                iou_ratio = middle_area / (areas[index] + areas[order[:-1]] - middle_area)
    
                # 挑选小于给定阈值的iou继续进行 NMS
                left = np.where(iou_ratio < threshold)
    
                # 将所有< threshold的索引取出来
                order = order[left]
    
            return keep
        def plot_bbox(self, dets, c='k'):
            x1 = dets[:, 0]
            y1 = dets[:, 1]
            x2 = dets[:, 2]
            y2 = dets[:, 3]
    
            plt.plot([x1, x2], [y1, y1], c)
            plt.plot([x1, x1], [y1, y2], c)
            plt.plot([x1, x2], [y2, y2], c)
            plt.plot([x2, x2], [y1, y2], c)
            plt.title(" nms")
    
    
    
    if __name__=="__main__":
        boxes = np.array([[100, 100, 250, 250, 0.8],
                          [250, 250, 420, 420, 0.95],
                          [220, 220, 320, 330, 0.92],
                          [100, 100, 210, 210, 0.7],
                          [230, 240, 325, 330, 0.81],
                          [220, 230, 315, 340, 0.9]])
        threshold = 0.7
    
        s1 = Solution()
        a = s1.nms(boxes, threshold)
        for i in boxes[a]:
            print(f"boxes_nms: {i}")
    
        # 可视化 NMS 效果
        plt.figure(1)
        ax1 = plt.subplot(1, 2, 1)
        ax2 = plt.subplot(1, 2, 2)
    
        plt.sca(ax1)
        s1.plot_bbox(boxes, 'k')  # before nms
    
        keep = a
        plt.sca(ax2)
        s1.plot_bbox(boxes[keep], 'r')  # after nm
        plt.show()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84

    推导过程

    1. 我们先将所有候选框的置信度排序,因为我们最终是要最大的
    2. 将置信度最大的加入到最终的返回值中
    3. 将其他的候选框和当前置信度最大的框计算iou
    4. 如果iou大于一个阈值,则可删除(说明和置信度大的那个是重叠的)
    5. 将剩下的框重复以上过程

    来源

    python计算iou以及nms
    python实现IOU计算

  • 相关阅读:
    Docker搭建ELKF日志分析系统
    下面哪些情况可能导致神经网络训练失败
    《基于 Vue 组件库 的 Webpack5 配置》8.在生成打包文件之前清空 output(dist) 目录(两种方式)
    轻松驾驭Python格式化:5个F-String实用技巧分享
    dell 720 安装系统
    Hi3519AV100通过ORTP库实现局域网图传和VLC实时预览
    MySQL高级八:SQL执行流程
    Java老人护理上门服务类型系统小程序APP源码
    【Python学习笔记】超详细Python快速入门教程(下)
    Ubuntu 20.04.05安装PCL-1.12.0
  • 原文地址:https://blog.csdn.net/weixin_44623662/article/details/125509176