IOU(Intersection over Union)交并比:
它计算的是“预测的边框”和“真实的边框”的交叠率,即它们的交集和并集的比值。这个比值用于衡量预测边框与真实边框的重叠程度,从而评估目标检测的准确性。
在目标检测任务中,通常使用bounding box与ground truth之间的IoU值大小来判断预测结果的好坏。一般情况下,认为IoU>0.5就是一个不错的预测结果。
两个box区域的交集除以并集
总的来说:IOU是一个在目标检测中非常重要的评估指标,用于量化预测边框与真实边框的匹配程度。
常规重叠框
代码示例
import cv2
import numpy as np
img = np.zeros((300,300,3),dtype=np.uint8)
img[:,:,:] = 255
# 下方红色框
x1,y1,x2,y2 = 20,20,180,180
# 下方蓝色框
x3,y3,x4,y4 = 90,90,280,280
cv2.rectangle(img, (x1, y1), (x2, y2), (0,0,255), 2)
cv2.rectangle(img, (x3, y3), (x4, y4), (255,0,0), 2)
cv2.imshow('img',img)
cv2.waitKey(10000)
cv2.destroyAllWindows()
当前 一个框 由 左上角 + 右下角 共 2 个坐标点 组成
如果 2 个 框 有交集 ,如下
交集 也是一个 矩形框,由 左上角 + 右下角 2个 坐标点 组成
已知 红框 和 篮框 的 左上角 + 右下角 如何 计算 交集 绿色框 的 左上角 + 右下角 坐标
计算方法
绿色区域 (交集) 左上角 与 右下角
左上角:取 红框 和 篮框 左上角点的 横坐标 (x) 与 纵坐标 (y) 最大值
# 红框
a = [x1, y1, x2, y2]
# 蓝框
b = [x3, y3, x4, y4]
c = np.array([a,b])
l_x1,l_y1 = np.max(c[:,0:2],axis=0)
右下角:取 红框 和 篮框 右下角点的 横坐标 (x) 与 纵坐标 (y) 最小值
# 红框
a = [x1, y1, x2, y2]
# 蓝框
b = [x3, y3, x4, y4]
c = np.array([a,b])
r_x2,r_y2 = np.min(c[:,2:],axis=0)
代码实现
import cv2
import numpy as np
img = np.zeros((300,300,3),dtype=np.uint8)
img[:,:,:] = 255
def inter(a,b):
c = np.array([a,b])
l_x1,l_y1 = np.max(c[:,0:2],axis=0)
r_x2,r_y2 = np.min(c[:,2:],axis=0)
return l_x1,l_y1,r_x2,r_y2
x1,y1,x2,y2 = 20,20,180,180
x3,y3,x4,y4 = 90,90,280,280
up_x,up_y,bo_x,bo_y = inter([x1,y1,x2,y2],[x3,y3,x4,y4])
cv2.rectangle(img, (up_x, up_y), (bo_x, bo_y), (0,255,0), -1)
cv2.rectangle(img, (x1, y1), (x2, y2), (0,0,255), 2)
cv2.rectangle(img, (x3, y3), (x4, y4), (255,0,0), 2)
cv2.imshow('img',img)
cv2.waitKey(10000)
cv2.destroyAllWindows()
cv2.imwrite('iou.jpg',img)
方法验证
实验不同的重叠形式
x1,y1,x2,y2 = 20,20,180,180
x3,y3,x4,y4 = 90,10,280,280
x1,y1,x2,y2 = 20,20,180,180
x3,y3,x4,y4 = 40,10,150,200
x1,y1,x2,y2 = 20,20,180,180
x3,y3,x4,y4 = 40,10,280,150
x1,y1,x2,y2 = 20,20,180,180
x3,y3,x4,y4 = 40,50,150,200
x1,y1,x2,y2 = 20,20,180,180
x3,y3,x4,y4 = 40,10,150,150
x1,y1,x2,y2 = 20,20,180,180
x3,y3,x4,y4 = 40,50,150,150
x1,y1,x2,y2 = 20,20,180,180
x3,y3,x4,y4 = 40,50,200,150
计算IoU
先计算 重叠 区域面积,再计算 红/蓝 框的 并集,最后 计算 占比
代码实现
import cv2
import numpy as np
img = np.zeros((300,300,3),dtype=np.uint8)
img[:,:,:] = 255
def inter(a,b):
c = np.array([a,b])
l_x1,l_y1 = np.max(c[:,0:2],axis=0)
r_x2,r_y2 = np.min(c[:,2:],axis=0)
return l_x1,l_y1,r_x2,r_y2
x1,y1,x2,y2 = 20,20,180,180
x3,y3,x4,y4 = 40,50,200,150
up_x,up_y,bo_x,bo_y = inter([x1,y1,x2,y2],[x3,y3,x4,y4])
# 红框 / 蓝框 / 重叠-绿色区域 面积
S_red = (x2-x1) * (y2-y1)
S_blue = (x4-x3) * (y4-y3)
S_green = (bo_x-up_x) * (bo_y-up_y)
print('面积-红框:',S_red,', 面积-蓝框:',S_blue,', 面积-绿色:',S_green)
# 红框 与 蓝框 的 并集
S_union = S_red + S_blue - S_green
print('红框与蓝框的并集-面积:',S_union)
iou = S_green / S_union
print('交集 / 并集: ',iou)
cv2.rectangle(img, (up_x, up_y), (bo_x, bo_y), (0,255,0), -1)
cv2.rectangle(img, (x1, y1), (x2, y2), (0,0,255), 2)
cv2.rectangle(img, (x3, y3), (x4, y4), (255,0,0), 2)
cv2.imshow('img',img)
cv2.waitKey(10000)
cv2.destroyAllWindows()
cv2.imwrite('iou.jpg',img)
结果
面积-红框: 25600 , 面积-蓝框: 16000 , 面积-绿色: 14000
红框与蓝框的并集-面积: 27600
交集 / 并集: 0.5072463768115942
无重叠情况
import cv2
import numpy as np
img = np.zeros((300,300,3),dtype=np.uint8)
img[:,:,:] = 255
def inter(a,b):
c = np.array([a,b])
l_x1,l_y1 = np.max(c[:,0:2],axis=0)
r_x2,r_y2 = np.min(c[:,2:],axis=0)
return l_x1,l_y1,r_x2,r_y2
x1,y1,x2,y2 = 20,20,120,120
x3,y3,x4,y4 = 140,150,260,240
up_x,up_y,bo_x,bo_y = inter([x1,y1,x2,y2],[x3,y3,x4,y4])
print(up_x,up_y,bo_x,bo_y)
cv2.rectangle(img, (x1, y1), (x2, y2), (0,0,255), 2)
cv2.rectangle(img, (x3, y3), (x4, y4), (255,0,0), 2)
cv2.imshow('img',img)
cv2.waitKey(10000)
cv2.destroyAllWindows()
结果
140 150 120 120
左上角:(140, 150)
右下角:(120, 120)
按照上面计算方式,在 2框 无交集的情况的下,也能 算出 重叠区域的 坐标
但 无交集 计算的 坐标特点:左上角 > 右下角
代码实现
import cv2
import numpy as np
img = np.zeros((300,300,3),dtype=np.uint8)
img[:,:,:] = 255
def inter(a,b):
c = np.array([a,b])
l_x1,l_y1 = np.max(c[:,0:2],axis=0)
r_x2,r_y2 = np.min(c[:,2:],axis=0)
return l_x1,l_y1,r_x2,r_y2
x1,y1,x2,y2 = 20,20,120,120
x3,y3,x4,y4 = 140,150,260,240
# x1,y1,x2,y2 = 20,20,180,180
# x3,y3,x4,y4 = 40,50,200,150
up_x,up_y,bo_x,bo_y = inter([x1,y1,x2,y2],[x3,y3,x4,y4])
print(up_x,up_y,bo_x,bo_y)
# 红框 / 蓝框 / 重叠-绿色区域 面积
S_red = (x2-x1) * (y2-y1)
S_blue = (x4-x3) * (y4-y3)
if bo_x > up_x and bo_y > up_y: S_green = (bo_x-up_x) * (bo_y-up_y)
else: S_green = 0
print('面积-红框:',S_red,', 面积-蓝框:',S_blue,', 面积-绿色:',S_green)
# 红框 与 蓝框 的 并集
S_union = S_red + S_blue - S_green
print('红框与蓝框的并集-面积:',S_union)
iou = S_green / S_union
print('交集 / 并集: ',iou)
if bo_x > up_x and bo_y > up_y: cv2.rectangle(img, (up_x, up_y), (bo_x, bo_y), (0,255,0), -1)
cv2.rectangle(img, (x1, y1), (x2, y2), (0,0,255), 2)
cv2.rectangle(img, (x3, y3), (x4, y4), (255,0,0), 2)
cv2.imshow('img',img)
cv2.waitKey(10000)
cv2.destroyAllWindows()
cv2.imwrite('iou.jpg',img)
结果
140 150 120 120
面积-红框: 10000 , 面积-蓝框: 10800 , 面积-绿色: 0
红框与蓝框的并集-面积: 20800
交集 / 并集: 0.0