data_generator.py

class SampleSelector:

#param:class_count, img_data

def __init__:

          self.classes = [b for b in class_count.keys() if class_count[b] >0]

          self.class_cycle = itertools.cycle(self.classes)

          self.curr_class =next(self.class_cycle)#迭代器


def skip_sample_for_balanced_class(self, img_data):

获取img_data中box信息,对于每个bbox,有key['class']表示该box中图像的类别:

for bbox in img_data['bboxes']:

   cls_name = bbox['class']


def get_anchor_gt(all_img_data, class_count, C, model='train')

如果model=='train',则采用data_augment;否则,不采用:

img_data_aug, x_img = data_augment


令img_size最小边为C.im_size,即最小边为600,并等比缩放另一条边:

resized_width, resized_height = get_new_img_size


计算rpn,

def calc_rpn(C, ing_data, width, height, resized_width, resized_height)

downscale = float(C.rpn_stride)

anchor_sizes = C.anchor_box_scales

anchor_ratios = C.anchor_box_ratios

num_anchors = len(anchor_sizes) * len(anchor_ratios)


初始化输出目标:

y_rpn_overlap = np.zeros((output_height, output_width, num_anchors))#

y_is_box_valid = np.zeros((output_height, output_width, num_anchors))

y_rpn_regr = np.zeros((output_height, output_width, num_anchors * 4))


获取一张图中的bbox数量:

num_bboxes = len(img_data['bboxes'])


定义best_anchor:best_anchor_for_bbox = -1 * np.ones((num_bboxes, 4)).astype(int)

初始化iou, x, dx:

        best_iou_for_bbox = np.zeros(num_bboxes).astype(np.float32)#每一个bbox的IoU

        best_x_for_bbox = np.zeros((num_bboxes, 4)).astype(int)#每一个bbox的中心和宽高

        best_dx_for_bbox = np.zeros((num_bboxes, 4)).astype(np.float32)#每一个bbox的缩放平移


        由于在图片预处理时,将图像最短边定为600,且整个图像做了缩放,所以在这一步获取bbox坐标时,也应作相对应的变化。

for bbox_num, bbox in enumerate(img_data['bboxes']):

'''获取每个bbox的ground truth'''

           gta[bbox_num, 0] = bbox['x1'] * (resized_width / float(width))

           gta[bbox_num, 1] = bbox['x2'] * (resized_width / float(width))

           gta[bbox_num, 2] = bbox['y1'] * (resized_height / float(height))

           gta[bbox_num, 3] = bbox['y2'] * (resized_height / float(height))


获取rpn gound truth:

在图片上,从bbox整体不越界的第一个位置开始,每隔rpn_stride=16个像素,取3 x 3个anchor;

for anchor_size_idx in range(len(anchor_sizes)):

    for anchor_ratio_idx in range(n_anchratios):

            anchor_x = anchor_sizes[anchor_size_idx] * anchor_ratios[anchor_ratio_idx][0]

            anchor_y = anchor_sizes[anchor_size_idx] * anchor_ratios[anchor_ratio_idx][1]

            for ix in range(output_width):

                   # x-coordinates of the current anchor box

                  x1_anc = downscale * (ix +0.5) - anchor_x /2

                  x2_anc = downscale * (ix +0.5) + anchor_x /2

                  # ignore boxes that go across image boundaries

                  if x1_anc <0 or x2_anc > resized_width:

                           continue

           for jy in range(output_height):

                   # y-coordinates of the current anchor box

                   y1_anc = downscale * (jy +0.5) - anchor_y /2

                   y2_anc = downscale * (jy +0.5) + anchor_y /2

                  # ignore boxes that go across image boundaries

                  if y1_anc <0 or y2_anc > resized_height:

                           continue


这一步嵌套在上层for循环中,即对每个bbox做判断。

初始化该bbox是否为target:bbox_type = 'neg'

计算当前bbox和图像中所有ground truth的bbox的IoU(调用def iou),结果赋给curr_iou;对每一个ground truth 的bbox,执行如下操作:


gta中存储的是原图的bbox的ground truth!!!

首先获取当前比较的这个ground truth bbox的中心:

cx = (gta[bbox_num, 0] + gta[bbox_num, 1]) / 2.0

cy = (gta[bbox_num, 2] + gta[bbox_num, 3]) / 2.0

再获取当前bbox中心:
cxa = (x1_anc + x2_anc) / 2.0

cya = (y1_anc + y2_anc) / 2.0

紧接着,比较两个bbox间的差异:

tx = (cx - cxa) / (x2_anc - x1_anc)#中心坐标

ty = (cy - cya) / (y2_anc - y1_anc)#中心坐标

tw = np.log((gta[bbox_num,1] - gta[bbox_num,0]) / (x2_anc - x1_anc))

th = np.log((gta[bbox_num,3] - gta[bbox_num,2]) / (y2_anc - y1_anc))#宽高比


如果当前ground truth bbox的label class不是background,即框住了某个物体:

!!!!必须保证原图中每一个ground truth bbox都能找到至少一个对应的anchor

如果当前这个坐标和尺寸的bbox与当前比较的ground truth bbox的IoU得分大于已有的得分,则更新:

best_anchor_for_bbox[bbox_num] = [jy, ix, anchor_ratio_idx,anchor_size_idx]#参数为当前bbox的中心坐标和长宽比以及整体尺寸;

并更新得分:

best_iou_for_bbox[bbox_num] = curr_iou

更新中心位置,即为当前这个anchor的坐标:

best_x_for_bbox[bbox_num,:] = [x1_anc, x2_anc, y1_anc, y2_anc]

更新当前bbox与ground truth bbox的差异,宽高差异百分比、缩放差异百分比:

best_dx_for_bbox[bbox_num,:] = [tx, ty, tw, th]


与上一个如果(if)是并列:

如果现在这个bbox与当前对比的ground truth bbox的重叠度超过C.rpn_max_overlap=0.7:

则认为当前bbox为正样本:bbox_type = 'pos'

当前ground_truth_bbox对应的anchor数量加一。

####

best_iou_for_loc在每次确定一个anchor对应的bbox后,初始化为0,接下来开始遍历所有原图中的ground truth bbox;目的是,找到和当前bbox匹配度最高的ground truth bbox。

#####

且,如果当前bbox的IoU大于了best_iou_for_loc,即这一步是定最好的回归参数:

           best_iou_for_loc = curr_iou

           best_regr = (tx, ty, tw, th)


如果当前IoU在0.3到0.7之间,则认为该bbox与当前遍历到的ground truth bbox关系不密切,则设:bbox_type = 'neutral'


对于一个bbox,遍历完原图中所有的ground truth bbox后,

(1)如果bbox_type == 'neg',则表明该bbox是有用的,可以作为负样本,但是没有和rpn重叠;

(2)如果bbox_type == 'neutral',则表明该bbox没有用处;

(3)如果bbox_type == 'pos'(只要该bbox与原图中任何一个ground truth bbox的IoU>0.7,则该bbox可作为正样本),则表明该bbox是有用的,可以作为正样本,并且和rpn有重叠。此时可以将其对应的回归参数best_regr保存下来。

对应的,

与rpn有重叠,y_rpn_overlap=1;bbox有用,y_is_box_valid=1;

y_rpn_overlap, y_is_box_valid:[output_height, output_width, num_anchors],

输出图片的某个位置[x, y]上,第i号尺寸的bbox有overlap或valid,记作:

y_rpn_overlap[x,y,i]=1, y_is_box_valid[x, y, i]=1


对于每一个anchor位置,每一种bbox尺寸都遍历完之后

如果,有某个gound truth bbox没有对应的anchor,即:

在各个尺寸的bbox下,没有一个anchor的bbox和gound truth bbox的IoU>0.7,也就是说

num_anchors_for_bbox = 0

我们必须保证每个ground truth bbox都能找到至少一个对应的anchor,则现在采取如下措施:
找到与其IoU最高的(尽管<0.7),将其坐标和尺寸以及相应的回归系数作为这个ground truth bbox对应的anchor。


定义pos_loc为rpn_overlap和box_valid都为1的位置,定义neg_loc为均为0的位置。

由于RPN存在的问题是,negative远超过positive,故对正负样本做一定的取舍。


y_rpn_regr:[output_height, output_width, num_anchors * 4]

进行transpose以及expand_dim后:
y_rpn_overlap: [0, num_anchors, output_height, output_width]

y_is_box_valid: [0, num_anchors, output_height, output_width]

y_rpn_regr: [0, num_anchors*4, output_height, output_width]


最终,

y_rpn_cls = np.concatenate([y_is_box_valid, y_rpn_overlap],axis=1)

# [0, num_anchors*2, output_height , output_width]

y_rpn_regr = np.concatenate([np.repeat(y_rpn_overlap,4,axis=1), y_rpn_regr],axis=1)

# [0, num_anchors*8, output_height , output_width]


return np.copy(y_rpn_cls), np.copy(y_rpn_regr)


在def get_anchor_gt中,

y_rpn_cls, y_rpn_regr = 上栏中的return()

对于y_rpn_regr[0, num_anchors*8, output_height, output_width]第二个维度后4个anchor参数做std_scaling,即对bbox的偏移做scaling:

y_rpn_regr[:, y_rpn_regr.shape[1]//2:, :, :] *= C.std_scaling


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容