实际上faster-rcnn对于输入的图片是有resize操作的,在resize的图片基础上提取feature map,而后generate一定数量的RoI。
我想首先去掉这个resize的操作,对每张图都是在原始图片基础上进行识别,所以要找到它到底在哪里resize了图片。
直接搜 grep 'resize' ./lib/ -r
./lib/crnn/utils.py: v.data.resize_(data.size()).copy_(data)
./lib/model/config.py:# Option to set if max-pooling is appended after crop_and_resize.
./lib/model/config.py:# if true, the region will be resized to a square of 2xPOOLING_SIZE,
./lib/model/config.py:# resized to a square of POOLING_SIZE
./lib/model/test.py: im = cv2.resize(im_orig, None, None, fx=im_scale, fy=im_scale,
./lib/nets/network.py:from scipy.misc import imresize
./lib/nets/network.py: image = imresize(image[0], self._im_info[:2] / self._im_info[2])
./lib/utils/blob.py: im = cv2.resize(im, None, None, fx=im_scale, fy=im_scale,
这里在training过程中应当是调用了./lib/utils/blob.py,
该文件包含了两个函数:
1 def im_list_to_blob(ims): 2 """Convert a list of images into a network input. 3 Assumes images are already prepared (means subtracted, BGR order, ...). 4 """ 5 max_shape = np.array([im.shape for im in ims]).max(axis=0) 6 num_images = len(ims) 7 blob = np.zeros((num_images, max_shape[0], max_shape[1], 3), 8 dtype=np.float32) 9 for i in range(num_images): 10 im = ims[i] 11 blob[i, 0:im.shape[0], 0:im.shape[1], :] = im 12 13 return blob 14 15 16 def prep_im_for_blob(im, pixel_means, target_size, max_size): 17 """Mean subtract and scale an image for use in a blob.""" 18 im = im.astype(np.float32, copy=False) 19 im -= pixel_means 20 im_shape = im.shape 21 im_size_min = np.min(im_shape[0:2]) 22 im_size_max = np.max(im_shape[0:2]) 23 im_scale = float(target_size) / float(im_size_min) 24 # Prevent the biggest axis from being more than MAX_SIZE 25 if np.round(im_scale * im_size_max) > max_size: 26 im_scale = float(max_size) / float(im_size_max) 27 im = cv2.resize(im, None, None, fx=im_scale, fy=im_scale, 28 interpolation=cv2.INTER_LINEAR) 29 30 return im, im_scale
而这两个函数都是在./lib/roi_data_layer/minibatch.py 下被调用的。
而该文件也定义了两个函数,其中get_minibatch() 调用了另一个子函数_get_image_blob()。
1 def get_minibatch(roidb, num_classes): 2 """Given a roidb, construct a minibatch sampled from it.""" 3 num_images = len(roidb) 4 # Sample random scales to use for each image in this batch 5 random_scale_inds = npr.randint(0, high=len(cfg.TRAIN.SCALES), 6 size=num_images) 7 assert(cfg.TRAIN.BATCH_SIZE % num_images == 0), 8 'num_images ({}) must divide BATCH_SIZE ({})'. 9 format(num_images, cfg.TRAIN.BATCH_SIZE) 10 11 # Get the input image blob, formatted for caffe 12 im_blob, im_scales = _get_image_blob(roidb, random_scale_inds) 13 14 blobs = {'data': im_blob} 15 16 assert len(im_scales) == 1, "Single batch only" 17 assert len(roidb) == 1, "Single batch only" 18 19 # gt boxes: (x1, y1, x2, y2, cls) 20 if cfg.TRAIN.USE_ALL_GT: 21 # Include all ground truth boxes 22 gt_inds = np.where(roidb[0]['gt_classes'] != 0)[0] 23 else: 24 # For the COCO ground truth boxes, exclude the ones that are ''iscrowd'' 25 gt_inds = np.where(roidb[0]['gt_classes'] != 0 & np.all(roidb[0]['gt_overlaps'].toarray() > -1.0, axis=1))[0] 26 gt_boxes = np.empty((len(gt_inds), 5), dtype=np.float32) 27 gt_boxes[:, 0:4] = roidb[0]['boxes'][gt_inds, :] * im_scales[0] 28 gt_boxes[:, 4] = roidb[0]['gt_classes'][gt_inds] 29 blobs['gt_boxes'] = gt_boxes 30 blobs['im_info'] = np.array( 31 [im_blob.shape[1], im_blob.shape[2], im_scales[0]], 32 dtype=np.float32) 33 34 return blobs 35 36 def _get_image_blob(roidb, scale_inds): 37 """Builds an input blob from the images in the roidb at the specified 38 scales. 39 """ 40 num_images = len(roidb) 41 processed_ims = [] 42 im_scales = [] 43 for i in range(num_images): 44 im = cv2.imread(roidb[i]['image']) 45 if roidb[i]['flipped']: 46 im = im[:, ::-1, :] 47 target_size = cfg.TRAIN.SCALES[scale_inds[i]] 48 im, im_scale = prep_im_for_blob(im, cfg.PIXEL_MEANS, target_size, 49 cfg.TRAIN.MAX_SIZE) 50 im_scales.append(im_scale) 51 processed_ims.append(im) 52 53 # Create a blob to hold the input images 54 blob = im_list_to_blob(processed_ims) 55 56 return blob, im_scales
get_minibatch()又是被./lib/roi_data_layer/layer.py中的类RoIDataLayer的一个方法forward()中调用的另一个方法_get_next_minibatch()调用的。
至此,由于RoIDataLayer类在类Network中被调用,终于把这些都接起来了。
faster-RCNN的代码实在是冗杂,来来回回定义了很多完全可以用一个函数实现的很多很多个函数。我佛了!