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)
初始化輸出目標(biāo):
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數(shù)量:
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的縮放平移
? ? ? ? 由于在圖片預(yù)處理時,將圖像最短邊定為600,且整個圖像做了縮放,所以在這一步獲取bbox坐標(biāo)時,也應(yīng)作相對應(yīng)的變化。
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循環(huán)中,即對每個bbox做判斷。
初始化該bbox是否為target:bbox_type = 'neg'
計算當(dāng)前bbox和圖像中所有g(shù)round truth的bbox的IoU(調(diào)用def iou),結(jié)果賦給curr_iou;對每一個ground truth 的bbox,執(zhí)行如下操作:
gta中存儲的是原圖的bbox的ground truth?。。?/p>
首先獲取當(dāng)前比較的這個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
再獲取當(dāng)前bbox中心:
cxa = (x1_anc + x2_anc) / 2.0
cya = (y1_anc + y2_anc) / 2.0
緊接著,比較兩個bbox間的差異:
tx = (cx - cxa) / (x2_anc - x1_anc)#中心坐標(biāo)
ty = (cy - cya) / (y2_anc - y1_anc)#中心坐標(biāo)
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))#寬高比
如果當(dāng)前ground truth bbox的label class不是background,即框住了某個物體:
!?。。”仨毐WC原圖中每一個ground truth bbox都能找到至少一個對應(yīng)的anchor
如果當(dāng)前這個坐標(biāo)和尺寸的bbox與當(dāng)前比較的ground truth bbox的IoU得分大于已有的得分,則更新:
best_anchor_for_bbox[bbox_num] = [jy, ix, anchor_ratio_idx,anchor_size_idx]#參數(shù)為當(dāng)前bbox的中心坐標(biāo)和長寬比以及整體尺寸;
并更新得分:
best_iou_for_bbox[bbox_num] = curr_iou
更新中心位置,即為當(dāng)前這個anchor的坐標(biāo):
best_x_for_bbox[bbox_num,:] = [x1_anc, x2_anc, y1_anc, y2_anc]
更新當(dāng)前bbox與ground truth bbox的差異,寬高差異百分比、縮放差異百分比:
best_dx_for_bbox[bbox_num,:] = [tx, ty, tw, th]
與上一個如果(if)是并列:
如果現(xiàn)在這個bbox與當(dāng)前對比的ground truth bbox的重疊度超過C.rpn_max_overlap=0.7:
則認(rèn)為當(dāng)前bbox為正樣本:bbox_type = 'pos'
當(dāng)前ground_truth_bbox對應(yīng)的anchor數(shù)量加一。
####
best_iou_for_loc在每次確定一個anchor對應(yīng)的bbox后,初始化為0,接下來開始遍歷所有原圖中的ground truth bbox;目的是,找到和當(dāng)前bbox匹配度最高的ground truth bbox。
#####
且,如果當(dāng)前bbox的IoU大于了best_iou_for_loc,即這一步是定最好的回歸參數(shù):
? ? ? ? ? ?best_iou_for_loc = curr_iou
? ? ? ? ? ?best_regr = (tx, ty, tw, th)
如果當(dāng)前IoU在0.3到0.7之間,則認(rèn)為該bbox與當(dāng)前遍歷到的ground truth bbox關(guān)系不密切,則設(shè):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有重疊。此時可以將其對應(yīng)的回歸參數(shù)best_regr保存下來。
對應(yīng)的,
與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沒有對應(yīng)的anchor,即:
在各個尺寸的bbox下,沒有一個anchor的bbox和gound truth bbox的IoU>0.7,也就是說
num_anchors_for_bbox = 0
我們必須保證每個ground truth bbox都能找到至少一個對應(yīng)的anchor,則現(xiàn)在采取如下措施:
找到與其IoU最高的(盡管<0.7),將其坐標(biāo)和尺寸以及相應(yīng)的回歸系數(shù)作為這個ground truth bbox對應(yīng)的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參數(shù)做std_scaling,即對bbox的偏移做scaling:
y_rpn_regr[:, y_rpn_regr.shape[1]//2:, :, :] *= C.std_scaling