机器视觉笔记2——交并比IoU及代码实现

引言

        在目标检测领域,交并比(IoU,全称Intersection of Union)是目标检测和和分割任务中一个重要的衡量标准,根据名字很容易知道IoU即为两个边界框(或者是两个分割掩模)的交集区域的面积和两个边界框(或者是两个分割掩模)的并集区域的面积之比。

        并比这一概念来源于数学中的集合,用来描述两个集合A�和B�之间的关系,它等于两个集合的交集里面所包含的元素个数,除以它们的并集里面所包含的元素个数,具体计算公式如下:

IoU=A∩B/A∪B

        交并比的取值范围在0到1之间,值越大表示两个边界框(或者是两个分割掩模)之间的重叠程度越高。当IoU为1时,表示两个边界框(或者是两个分割掩模)完全重叠;当IoU为0时,表示两个边界框(或者是两个分割掩模)没有任何重叠。

        在物体检测任务中,通常将IoU大于某个阈值(例如0.5)的边界框视为检测正确,否则视为检测错误。在分割任务中,通常会根据IoU的大小来计算分割的准确率和召回率等指标。        

交并比IoU计算方法

     假设两个矩形框A和B的位置分别为:  

        假如位置关系如下所示:

        

        假设A和B有相交部分,则相交部分左上角坐标如下:

x_{1}=max(x_{a1},x_{b1}), y_{1}=max(y_{a1},y_{b1})

        相交部分右下角坐标为:

x_{2}=min(x_{a2},x_{b2}), y_{2}=min(y_{a2},y_{b2})

        相交部分(A∩B)面积:

intersection=max(x_{a2}-x_{a1}+1.0)\cdot(y_{a2}-y_{a1}+1.0)

        ***这里需要注意的是:“+1.0”是防止A和B矩形框没有交集为负数。***

        相并部分(A∪B)面积:

union=S_{A}+S_{B}-intersection       

        因此,交并比IoU=A∩B/A∪B如下:

IoU=\frac{intersection}{union}

交并比大小与重合度

        交并比的大小跟重合程度之间的关系,如下图示意了不同交并比下两个框之间的相对位置关系,从 IoU = 0.95 到 IoU = 0。

        其中,两个矩形框完全重合,两个矩形框的IoU等于1;两个矩形框完全不相交两个矩形框的IoU等于0。实际代码实现过程中,为了避免IoU为负值,通常采用“+1.”处理。

代码实现

简单示例       

        在图像处理中,这里采用坐标原点在左上角(Top-Left Origin),A坐标为[50,50,300,300],B坐标为[60,60,320,320],计算A和B的交并比。

import cv2
import numpy as np
from matplotlib import pyplot as plt

def CountIOU(RecA, RecB):
    xA = max(RecA[0], RecB[0])
    yA = max(RecA[1], RecB[1])
    xB = min(RecA[2], RecB[2])
    yB = min(RecA[3], RecB[3])
    # 计算交集部分面积
    interArea = max(0, xB - xA + 1) * max(0, yB - yA + 1)
    # 计算预测值和真实值的面积
    RecA_Area = (RecA[2] - RecA[0] + 1) * (RecA[3] - RecA[1] + 1)
    RecB_Area = (RecB[2] - RecB[0] + 1) * (RecB[3] - RecB[1] + 1)
    # 计算IOU
    iou = interArea / float(RecA_Area + RecB_Area - interArea)

    return iou

img = np.zeros((512,512,3), np.uint8)
img.fill(255)

RecA = [50,50,300,300]
RecB = [60,60,320,320]

cv2.rectangle(img, (RecA[0],RecA[1]), (RecA[2],RecA[3]), (0, 255, 0), 5)
cv2.rectangle(img, (RecB[0],RecB[1]), (RecB[2],RecB[3]), (255, 0, 0), 5)

IOU = CountIOU(RecA,RecB)
font = cv2.FONT_HERSHEY_SIMPLEX

cv2.putText(img,"IOU = %.2f"%IOU,(130, 190),font,0.8,(0,0,0),2)

# 保存图像文件
cv2.imwrite('output_image.jpg', img)

# 在Colab中显示图像文件
image = cv2.imread('output_image.jpg')
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.show()

        结果如下:

图片实现

        在图片“girlwithdog.jpg”显示小女孩和小狗的交并比。其中,A和B坐标如下:RecA = [381,86,715,651],RecB = [558,371,781,608]。

import cv2
import numpy as np
from matplotlib import pyplot as plt

def CountIOU(RecA, RecB):
    xA = max(RecA[0], RecB[0])
    yA = max(RecA[1], RecB[1])
    xB = min(RecA[2], RecB[2])
    yB = min(RecA[3], RecB[3])
    # 计算交集部分面积
    interArea = max(0, xB - xA + 1) * max(0, yB - yA + 1)
    # 计算预测值和真实值的面积
    RecA_Area = (RecA[2] - RecA[0] + 1) * (RecA[3] - RecA[1] + 1)
    RecB_Area = (RecB[2] - RecB[0] + 1) * (RecB[3] - RecB[1] + 1)
    # 计算IOU
    iou = interArea / float(RecA_Area + RecB_Area - interArea)

    return iou

img = cv2.imread('/content/girlwithdog.jpg')
if img is None:
    print("Error: Could not read the image.")
    exit()

RecA = [381,86,715,651]
RecB = [558,371,781,608]

cv2.rectangle(img, (RecA[0],RecA[1]), (RecA[2],RecA[3]), (0, 255, 0), 5)
cv2.rectangle(img, (RecB[0],RecB[1]), (RecB[2],RecB[3]), (255, 0, 0), 5)

IOU = CountIOU(RecA,RecB)
font = cv2.FONT_HERSHEY_SIMPLEX

cv2.putText(img,"IOU = %.2f"%IOU,(580, 500),font,1.0,(0,0,255),2,cv2.LINE_AA)

# 保存图像文件
cv2.imwrite('output_image.jpg', img)

# 在Colab中显示图像文件
image = cv2.imread('output_image.jpg')
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.show()

        结果:

        如果A和B直接从上个章节的xml文件中读取

机器视觉笔记1——XML标记语言生成与读取-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/qq_35644010/article/details/136112307?spm=1001.2014.3001.5501代码如下:

        

import cv2
import numpy as np
from matplotlib import pyplot as plt
import xml.etree.ElementTree as ET
from PIL import Image
import matplotlib.patches as patches

# 解析XML文件
xml_file = '/content/girlwithdog.xml'
tree = ET.parse(xml_file)
root = tree.getroot()

# 获取图像文件名
filename = root.find('filename').text

# 获取图像尺寸
size = root.find('size')
width = int(size.find('width').text)
height = int(size.find('height').text)

# 读取图像
image_path = filename
image = Image.open(image_path)



# 定义类别和对应的颜色
category_colors = {'dog': 'r', 'person': 'b', 'car': 'g'}


# 获取并绘制边界框
for obj in root.findall('object'):
    # 获取类别和边界框信息
    obj_name = obj.find('name').text
    bbox = obj.find('bndbox')
    xmin = int(bbox.find('xmin').text)
    ymin = int(bbox.find('ymin').text)
    xmax = int(bbox.find('xmax').text)
    ymax = int(bbox.find('ymax').text)
    width = xmax - xmin
    height = ymax - ymin

    # 绘制边界框
    rect = patches.Rectangle((xmin, ymin), width, height, linewidth=1, edgecolor=category_colors[obj_name], facecolor='none')
    plt.gca().add_patch(rect)
    plt.text(xmin, ymin - 5, obj_name, color='yellow', fontsize=8, ha='left', va='top')



def CountIOU(RecA, RecB):
    xA = max(RecA[0], RecB[0])
    yA = max(RecA[1], RecB[1])
    xB = min(RecA[2], RecB[2])
    yB = min(RecA[3], RecB[3])
    # 计算交集部分面积
    interArea = max(0, xB - xA + 1) * max(0, yB - yA + 1)
    # 计算预测值和真实值的面积
    RecA_Area = (RecA[2] - RecA[0] + 1) * (RecA[3] - RecA[1] + 1)
    RecB_Area = (RecB[2] - RecB[0] + 1) * (RecB[3] - RecB[1] + 1)
    # 计算IOU
    iou = interArea / float(RecA_Area + RecB_Area - interArea)

    return iou

img = cv2.imread('/content/girlwithdog.jpg')
if img is None:
    print("Error: Could not read the image.")
    exit()


IOU = CountIOU(RecA,RecB)
font = cv2.FONT_HERSHEY_SIMPLEX

cv2.putText(img,"IOU = %.2f"%IOU,(580, 500),font,1.0,(0,0,255),2,cv2.LINE_AA)

# 保存图像文件
cv2.imwrite('output_image.jpg', img)

# 在Colab中显示图像文件
image = cv2.imread('output_image.jpg')
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.axis('on')
plt.show()

        结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值