如图所示,绿色的框为飞机的Ground Truth,红色的框是提取的Region Proposal。那么即便红色的框被分类器识别为飞机,但是由于红色的框定位不准(IoU<0.5),那么这张图相当于没有正确的检测出飞机。如果我们能对红色的框进行微调,使得经过微调后的窗口跟Ground Truth更接近,这样岂不是定位会更准确。所以,Bounding-box regression 就是用来微调这个窗口的。
注意:只有当Proposal和Ground Truth比较接近时(线性问题),我们才能将其作为训练样本训练我们的线性回归模型,否则会导致训练的回归模型不work(当Proposal跟GT离得较远,就是复杂的非线性问题了,此时用线性回归建模显然不合理)。这个也是G-CNN: an Iterative Grid Based Object Detector多次迭代实现目标准确定位的关键。
faster rcnn中进行边框回归存在于两个部分,第一个是在训练RPN的过程中对anchor进行边框回归,另一个是在训练fast rcnn过程中对proposal进行边框回归。
在RPN的训练中,一方面会输出anchor对于gt的预测的偏移量rpn_bbox_pred,同时anchor_target_layer会计算anchor与gt的实际的偏移量rpn_bbox_targets,计算的公式如下:
代码实现如下(该函数中anchor是经过筛选后存在于图片大小边界内的,对于那些筛选掉的anchor,其四个偏移参数默认全为0。)
def bbox_transform(ex_rois, gt_rois):
#计算anchor的长宽以及中心
ex_widths = ex_rois[:, 2] - ex_rois[:, 0] + 1.0
ex_heights = ex_rois[:, 3] - ex_rois[:, 1] + 1.0
ex_ctr_x = ex_rois[:, 0] + 0.5 * ex_widths
ex_ctr_y = ex_rois[:, 1] + 0.5 * ex_heights
#计算gt的长宽以及中心
gt_widths = gt_rois[:, 2] - gt_rois[:, 0] + 1.0
gt_heights = gt_rois[:, 3] - gt_rois[:, 1] + 1.0
gt_ctr_x = gt_rois[:, 0] + 0.5 * gt_widths
gt_ctr_y = gt_rois[:, 1] + 0.5 * gt_heights
#anchor与gt的实际偏移量
targets_dx = (gt_ctr_x - ex_ctr_x) / ex_widths
targets_dy = (gt_ctr_y - ex_ctr_y) / ex_heights
targets_dw = np.log(gt_widths / ex_widths)
targets_dh = np.log(gt_heights / ex_heights)
targets = np.vstack(
(targets_dx, targets_dy, targets_dw, targets_dh)).transpose()
return targets
利用rpn_bbox_pred、rpn_bbox_targets、rpn_inside_weights和rpn_outside_weights就可以计算RPN bbox loss。
见博客tensorflow+faster rcnn代码理解(三):损失函数构建
在训练fast rcnn之前要从proposal_layer从约20000个anchor中选择出12000个proposal作为rois,从anchor->proposal的过程需要对anchor进行修正,修正的公式就是:
代码实现为如下,其中delas就是RPN网络输出的预测偏移量rpn_bbox_pred.
def bbox_transform_inv(boxes, deltas):
if boxes.shape[0] == 0:
return np.zeros((0, deltas.shape[1]), dtype=deltas.dtype)
boxes = boxes.astype(deltas.dtype, copy=False)
widths = boxes[:, 2] - boxes[:, 0] + 1.0
heights = boxes[:, 3] - boxes[:, 1] + 1.0
ctr_x = boxes[:, 0] + 0.5 * widths #anchor的中心
ctr_y = boxes[:, 1] + 0.5 * heights
dx = deltas[:, 0::4]
dy = deltas[:, 1::4]
dw = deltas[:, 2::4]
dh = deltas[:, 3::4]
#修正后的中心点坐标(x,y)以及w、h
pred_ctr_x = dx * widths[:, np.newaxis] + ctr_x[:, np.newaxis]
pred_ctr_y = dy * heights[:, np.newaxis] + ctr_y[:, np.newaxis]
pred_w = np.exp(dw) * widths[:, np.newaxis]
pred_h = np.exp(dh) * heights[:, np.newaxis]
pred_boxes = np.zeros(deltas.shape, dtype=deltas.dtype)
# x1
pred_boxes[:, 0::4] = pred_ctr_x - 0.5 * pred_w
# y1
pred_boxes[:, 1::4] = pred_ctr_y - 0.5 * pred_h
# x2
pred_boxes[:, 2::4] = pred_ctr_x + 0.5 * pred_w
# y2
pred_boxes[:, 3::4] = pred_ctr_y + 0.5 * pred_h
return pred_boxes
修正完毕后,在proposal_target_layer,会选择出来的128个rois,此时就要计算这些rois与gt实际的偏移量bbox_targets,会调用bbox_transform函数,见4.1:
bbox_target_data = _compute_targets(
rois[:, 1:5], gt_boxes[gt_assignment[keep_inds], :4], labels)
而这些rois经过fast rcnn部分的训练后会输出预测的偏移量bbox_pred,因此利用bbox_targets,bbox_pred bbox_inside_weights,bbox_outside_weights就可以计算fastrcnn部分的bbox loss。
见博客tensorflow+faster rcnn代码理解(三):损失函数构建