1、bbox回归,首先依据锚框与偏移量预测出目标框,然后根据目标框与原框求出偏移量。交并比为相交部分面积/相并部分面积,以及生成锚框。
公式如下:
依据锚框及偏移量输出预测框
np.maxinum(array,0) 将数组的最大值限制为0
np.clip(array,0,100) 将数组的最小值限制为0,最大值限制为100
依据预测框与原框输出偏移量
代码如下:
import numpy as np
import numpy as xp
import six
from six import __init__
def loc2bbox(src_bbox, loc):
if src_bbox.shape[0] == 0:
return xp.zeros((0, 4), dtype=loc.dtype)
src_bbox = src_bbox.astype(src_bbox.dtype, copy=False)
src_height = src_bbox[:, 2] - src_bbox[:, 0] //输出一维数组——高度
src_width = src_bbox[:, 3] - src_bbox[:, 1] //输出一维数组——宽度
src_ctr_y = src_bbox[:, 0] + 0.5 * src_height //输出一维数组——中心点纵坐标
src_ctr_x = src_bbox[:, 1] + 0.5 * src_width //输出一维数组——中心点横坐标
dy = loc[:, 0::4] //二维数组纵坐标偏移量
dx = loc[:, 1::4] //二维数组横坐标偏移量
dh = loc[:, 2::4] //二维数组高度
dw = loc[:, 3::4] //二维数组宽度
ctr_y = dy * src_height[:, xp.newaxis] + src_ctr_y[:, xp.newaxis] //增加一维数组的一个维度变成二维数组求出预测框中心点纵坐标
ctr_x = dx * src_width[:, xp.newaxis] + src_ctr_x[:, xp.newaxis] //增加一维数组的一个维度 变成二维数组求出预测框中心点横坐标
h = xp.exp(dh) * src_height[:, xp.newaxis] //增加一维数组一个维度变成二维数组求出预测框高度
w = xp.exp(dw) * src_width[:, xp.newaxis] //增加一维数组一个维度变成二维数组求出预测框宽度
dst_bbox = xp.zeros(loc.shape, dtype=loc.dtype) //创建一个与偏移量大小相同的二维数组用于装预测框的左上和右下坐标
dst_bbox[:, 0::4] = ctr_y - 0.5 * h //左上纵坐标
dst_bbox[:, 1::4] = ctr_x - 0.5 * w //左上横坐标
dst_bbox[:, 2::4] = ctr_y + 0.5 * h //右下纵坐标
dst_bbox[:, 3::4] = ctr_x + 0.5 * w //右下横坐标
return dst_bbox //返回预测框的左上和右下坐标
def bbox2loc(src_bbox, dst_bbox): //输入原框和预测框
height = src_bbox[:, 2] - src_bbox[:, 0] //一维数组原框高度
width = src_bbox[:, 3] - src_bbox[:, 1] //一维数组原框宽度
ctr_y = src_bbox[:, 0] + 0.5 * height //一维数组原框中心点纵坐标
ctr_x = src_bbox[:, 1] + 0.5 * width //一维数组原框中心点横坐标
base_height = dst_bbox[:, 2] - dst_bbox[:, 0] //一维数组预测框高度
base_width = dst_bbox[:, 3] - dst_bbox[:, 1] //一维数组预测框 宽度
base_ctr_y = dst_bbox[:, 0] + 0.5 * base_height //一维数组预测框中心点纵坐标
base_ctr_x = dst_bbox[:, 1] + 0.5 * base_width //一维数组预测框中心点横坐标
eps = xp.finfo(height.dtype).eps //eps是一个非负数值很小10的-16次方
height = xp.maximum(height, eps) //一维数组高度与eps逐位比较取最大值重组一个一维数组因为被除数不能为0 np.max值取数组内最大值,如果用于在一个数组中取一个阈值进行比较,可采用np.maximum
width = xp.maximum(width, eps) //一维数组宽度与eps逐位比较取最大值重组一个一维数组
dy = (base_ctr_y - ctr_y) / height //一维数组,求出纵坐标偏移量
dx = (base_ctr_x - ctr_x) / width //一维数组,求出横坐标偏移量
dh = xp.log(base_height / height) //一维数组,求出偏移量高度
dw = xp.log(base_width / width) //一维数组,求出偏移量宽度
loc = xp.vstack((dy, dx, dh, dw)).transpose() //垂直合并dy,dx,dh,dw然后进行转置输出shape为src_bbox.shape[0],4
return loc 返回偏移量框
def bbox_iou(bbox_a, bbox_b): //交并比,输入为预测框与原框
if bbox_a.shape[1] != 4 or bbox_b.shape[1] != 4:
raise IndexError
# top left
tl = xp.maximum(bbox_a[:, None, :2], bbox_b[:, :2]) //比较两个框的左上角横纵坐标,取最大值
# bottom right
br = xp.minimum(bbox_a[:, None, 2:], bbox_b[:, 2:]) //比较两个框的右下角横纵坐标,取最小值
area_i = xp.prod(br - tl, axis=2) * (tl < br).all(axis=2) //相当于两个框相交部分的高度和宽度,然后prod乘积运算求出相交部分的面积,如果右下角小于左上角输出面积为0
area_a = xp.prod(bbox_a[:, 2:] - bbox_a[:, :2], axis=1) //bbox_a的右下角坐标-左上角坐标求出宽度和高度进行乘积求面积
area_b = xp.prod(bbox_b[:, 2:] - bbox_b[:, :2], axis=1) //bbox_b的右下角坐标-左上角坐标求出宽度和高度进行乘积求面积
return area_i / (area_a[:, None] + area_b - area_i) 返回分数,分母为相交部分的面积,分子为输入两个框的面积和减去相交部分的面积即相并面积
def __test():
pass
if __name__ == '__main__':
__test()
def generate_anchor_base(base_size=16, ratios=[0.5, 1, 2],
anchor_scales=[8, 16, 32]): //每个点生成锚框
py = base_size / 2. //纵坐标缩放比例
px = base_size / 2. //横坐标缩放比例
anchor_base = np.zeros((len(ratios) * len(anchor_scales), 4),
dtype=np.float32) //创建单点锚框
for i in six.moves.range(len(ratios)): //形状的比
for j in six.moves.range(len(anchor_scales)): //遍历尺寸
h = base_size * anchor_scales[j] * np.sqrt(ratios[i]) //生成锚框的高 因为遍历9次,所以一共有9种高度
w = base_size * anchor_scales[j] * np.sqrt(1. / ratios[i]) //生成锚框的宽
index = i * len(anchor_scales) + j //这9个锚框对应的索引值
anchor_base[index, 0] = py - h / 2. //这9个锚框每一个锚框的左上角纵坐标
anchor_base[index, 1] = px - w / 2. //这9个锚框每一个锚框的左上角横坐标
anchor_base[index, 2] = py + h / 2. //这9个锚框每一个锚框的右下角纵坐标
anchor_base[index, 3] = px + w / 2. //这9个锚框每一个锚框的右下角横坐标
return anchor_base 返回一个点生成的9个锚框