日萌社
人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)
1.候选框的坐标表示为(左上角的x坐标,左上角的y坐标,右下角的x坐标,右下角的y坐标)
2.一般的都是左上角的x/y坐标小,右下角的x/y坐标大,因为x/y坐标轴的零点位于左上角处。
"""
非极大值抑制(NMS)
1.输入数据:
通过SVM分类器对每个锚框分类好之后,每个锚框都带上了预测类别标签值和该预测类别的置信度score,最终每个锚框都放到对应的类别列表中。
2.迭代过程:
对每个分类列表中的锚框进行处理,比如对某个类别的列表中所有锚框根据其预测类别的置信度score按从大到小进行排序,
首先类别的列表中取出第一个score值最大的锚框放到输出列表中,然后类别的列表中剩余的所有锚框逐一和输出列表中第一个锚框进行计算IoU值(交并比),
把IoU值>0.5的锚框都丢弃掉,只留下IoU值<0.5的锚框继续进行下一轮比较。
下一轮比较中,仍然先把分类列表中剩余的(score值最大)第一个锚框放到输出列表中,
然后分类列表中剩余的所有锚框再和输出列表中最后添加进去的锚框进行计算IoU值(交并比),
同样的把IoU值>0.5的锚框都丢弃掉,只留下IoU值<0.5的锚框,以此类推继续进行下一轮比较。
"""
import numpy as np
def nms(bounding_boxes, confidence_score, threshold):
"""
:param bounding_boxes: 检测的 boxes 及对应的 scores
:param confidence_score: 置信度score
:param threshold: 设定的阈值
:return:
"""
# boxes 位置
x1 = bounding_boxes[:, 0] # 左上角的x坐标
y1 = bounding_boxes[:, 1] # 左上角的y坐标
x2 = bounding_boxes[:, 2] # 右下角的x坐标
y2 = bounding_boxes[:, 3] # 右下角的y坐标
#一般的都是左上角的x/y坐标小,右下角的x/y坐标大,因为x/y坐标轴的零点位于左上角处。
# 右下角的x坐标x2 - 左上角的x坐标x1 = 长
# 右下角的y坐标y2 - 左上角的y坐标y1 = 高
areas = (x2 - x1) * (y2 - y1) # 各 box 的面积 = 长*高
# argsort从小到大排序,返回的是元素的索引值,[::-1]表示倒排变成从大到小 排序,排序后返回的结果为元素索引值[0, 2, 1]
order = confidence_score.argsort()[::-1] # boxes 的按照 置信度score 从大到小 排序
keep_box = [] # 记录保留下的 boxes 作为输出列表
keep_confidence_score = [] # 记录保留下的 置信度score 作为输出列表
while order.size > 0:
i = order[0] # score 最大的 box 对应的 index
keep_box.append(i) # 将本轮 score 最大的 box 的 index 保留
keep_confidence_score.append(i) # 将本轮 score 最大的 box 的 置信度score
# 计算剩余 boxes 与当前 box 的重叠程度 IoU
""" 类别的列表中剩余的所有锚框逐一和输出列表中第一个锚框进行 计算交集,作为分子 """
xx1 = np.maximum(x1[i], x1[order[1:]])
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 = np.maximum(0.0, xx2 - xx1 + 1)
h = np.maximum(0.0, yy2 - yy1 + 1)
""" 交集面积,作为分子 """
inter = w * h
"""
areas[i]:最后添加进输出列表的的锚框的面积
areas[order[1:]]:类别列表中的剩余锚框的面积
areas[i] + areas[order[1:]] - inter:两者相加再减去两者的交集求出两者的并集面积
两者的交集面积作为分子,两者的并集面积作为分母,求出的分别都是剩余锚框的 IoU值(交并比)
"""
ovr = inter / (areas[i] + areas[order[1:]] - inter)
"""
np.where()[0] 表示行的索引
np.where()[1] 表示列的索引
把剩余锚框的<=阈值的锚框都留下继续进行下一轮比较
此处的np.where()[0]取出的是类别列表中剩余锚框的索引值
"""
# 保留 IoU 小于设定阈值的 boxes
inds = np.where(ovr <= threshold)[0]
#只保留 <=阈值的锚框,根据所取出类别列表中剩余锚框的索引值取出该部分锚框进行下一轮比较
order = order[inds + 1]
return keep_box, keep_confidence_score
def union(au, bu, area_intersection):
"""
计算并集
:param au:
:param bu:
:param area_intersection:
:return:
"""
# 计算a的面积
area_a = (au[2] - au[0]) * (au[3] - au[1])
# 计算b的面积
area_b = (bu[2] - bu[0]) * (bu[3] - bu[1])
# a和b的面积-交集面积=总共面积
area_union = area_a + area_b - area_intersection
return area_union
def intersection(ai, bi):
"""
计算交集
:param ai:a框坐标
:param bi:b框坐标
:return:
"""
# 1、取出交集的左上角点
x = max(ai[0], bi[0])
y = max(ai[1], bi[1])
# 2、取出交集的右下角点,并减去左上角点值,计算出交集长宽
w = min(ai[2], bi[2]) - x
h = min(ai[3], bi[3]) - y
# 3、如果一个为0,返回交集面积为0
if w < 0 or h < 0:
return 0
return w*h
def iou(a, b):
"""
计算交并比
:param a: a框坐标
:param b: b框坐标
:return:
"""
# 1、如果a,b 传入有问题
if a[0] >= a[2] or a[1] >= a[3] or b[0] >= b[2] or b[1] >= b[3]:
return 0.0
# 2、计算IOU
# 交集区域
area_i = intersection(a, b)
# 并集区域
area_u = union(a, b, area_i)
return float(area_i) / float(area_u + 1e-6) # 防止分母为0,加一个稳定系数
if __name__ == '__main__':
# 1.候选框的坐标表示为(左上角的x坐标,左上角的y坐标,右下角的x坐标,右下角的y坐标)
# 2.一般的都是左上角的x/y坐标小,右下角的x/y坐标大,因为x/y坐标轴的零点位于左上角处。
bounding_boxes = np.array([(187, 82, 337, 317), (150, 67, 305, 282), (246, 121, 368, 304)])
confidence_score = np.array([0.9, 0.75, 0.8]) # 置信度score
threshold = 0.4 # 阈(yu)值
keep_box, keep_confidence_score = nms(bounding_boxes,confidence_score,threshold)
print(bounding_boxes[keep_box]) #[[187 82 337 317]]
print(keep_confidence_score) # [0]
def union(au, bu, area_intersection):
"""计算并集面积
:param au: a框坐标
:param bu: b框坐标
:param intersection: 交集面积
:return:
"""
# a框面积
area_a = (au[2] - au[0]) * (au[3] - au[1])
# b框面积
area_b = (bu[2] - bu[0]) * (bu[3] - bu[1])
# a+b面积-交集面积
area_union = area_a + area_b - area_intersection
return area_union
def intersection(ai, bi):
"""计算交集
:param ai: a框坐标
:param bi: b框坐标
:return:
"""
# 1、求出交集的左上角点
# ai和bi的左上角的x谁更大
# ai和bi的左上角的y谁更大
x_left = max(ai[0], bi[0])
y_left = max(ai[1], bi[1])
# 2、求出交集的右下角点
x_right = min(ai[2], bi[2])
y_right = min(ai[3], bi[3])
# 求出长宽
w = x_right - x_left
h = y_right - y_left
if w < 0 or h < 0:
return 0
return w * h
def IoU(a, b):
"""计算交并比
:param a: a框坐标
:param b: b框坐标
:return:
"""
# 1、做异常处理
if a[0] >= a[2] or a[1] >= a[3] or b[0] >= b[2] or b[1] >= b[3]:
return 0.0
# 2、计算交并比,计算交集,计算并集 交集/并集+epsilon
area_i = intersection(a, b)
area_u = union(a, b, area_i)
return float(area_i) / float(area_u + 1e-6)
if __name__ == '__main__':
# 假设一个图片10 x 10的大小,左上角(0, 0) 右下角(10, 10)
# A框:(1, 1, 5, 5),B框:(3, 3, 6, 6)
a = (1, 1, 5, 5)
b = (1, 1, 6, 6)
print("交并比为:%f" % IoU(a, b))