程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

IOU和NMS圖解(附Python和C++代碼)

編輯:Python

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}")

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=(x2−x1)∗(y2−y1)+(x4−x3)∗(y4−y3)
要計算兩矩陣的交,則要確定相交的面積的左上和右下坐標,則有:
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_right−middle_left)∗(middle_buttom−middle_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=area−middle_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. 將其他的候選框和當前置信度最大的框計算iou
  4. 如果iou大於一個阈值,則可刪除(說明和置信度大的那個是重疊的)
  5. 將剩下的框重復以上過程

來源

python計算iou以及nms
python實現IOU計算


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved