1. 程式人生 > >faster-rcnn 之 基於roidb get_minibatch(資料準備操作)

faster-rcnn 之 基於roidb get_minibatch(資料準備操作)

【說明】:歡迎加入:faster-rcnn 交流群 238138700這個函式,輸入是roidb,根據roidb中給出的圖片的資訊,讀取圖片的原始檔,然後整理成blobs,供給網路訓練使用;

def get_minibatch(roidb, num_classes):

這個函式會根據roidb中的資訊,呼叫opencv讀取圖片,整理成blobs返回,所以這個函式是faster-rcnn實際的資料準備操作,我們來分析minibatch.py這個檔案;

【輸入】:roidb是一個list,list中的每個元素是一個字典,每個字典對應一張圖片的資訊,其中的主要資訊有:

boxes:該圖片所有的box的4個座標位置

gt_class:每個boxes對應的類別

gt_overlaps

height:圖片原始的高

width:圖片原始的寬

image:圖片的路徑

seg_areas

【函式解析】:

def get_minibatch(roidb, num_classes):
    """Given a roidb, construct a minibatch sampled from it."""
    num_images = len(roidb)#roidb中元素的個數,就是要處理的圖片的個數
    # Sample random scales to use for each image in this batch
    random_scale_inds = npr.randint(0, high=len(cfg.TRAIN.SCALES),
                                    size=num_images)#根據scales的數量,為每張圖片生成一個scales的索引
    assert(cfg.TRAIN.BATCH_SIZE % num_images == 0), \
        'num_images ({}) must divide BATCH_SIZE ({})'. \
        format(num_images, cfg.TRAIN.BATCH_SIZE)#斷言,要求batchsize必須是圖片數量的整數倍
    rois_per_image = cfg.TRAIN.BATCH_SIZE / num_images #計算平均從每個圖片上要產生多少個roi輸入
    fg_rois_per_image = np.round(cfg.TRAIN.FG_FRACTION * rois_per_image) #按比率計算每張圖片的roi中需要多少個前景

    # Get the input image blob, formatted for caffe
    im_blob, im_scales = _get_image_blob(roidb, random_scale_inds)#呼叫函式,讀取圖片資料,返回矩陣資料和每張圖片的尺寸縮放資訊

    blobs = {'data': im_blob}#把blobs字典的key:data賦值為im_blob,也就是圖片的矩陣資料

    if cfg.TRAIN.HAS_RPN:#這裡是針對RPN網路的訓練過程的
        assert len(im_scales) == 1, "Single batch only"
        assert len(roidb) == 1, "Single batch only"
        # gt boxes: (x1, y1, x2, y2, cls)#gt_boxes每一行對應一個box資訊,包括4個座標和一個類別
        gt_inds = np.where(roidb[0]['gt_classes'] != 0)[0]
        gt_boxes = np.empty((len(gt_inds), 5), dtype=np.float32)
        gt_boxes[:, 0:4] = roidb[0]['boxes'][gt_inds, :] * im_scales[0]
        gt_boxes[:, 4] = roidb[0]['gt_classes'][gt_inds]
        blobs['gt_boxes'] = gt_boxes
        blobs['im_info'] = np.array(
            [[im_blob.shape[2], im_blob.shape[3], im_scales[0]]],
            dtype=np.float32)#影象資訊就是rezise後的高、寬、縮放比例三個資訊
    else: # not using RPN
        # Now, build the region of interest and label blobs
        rois_blob = np.zeros((0, 5), dtype=np.float32)
        labels_blob = np.zeros((0), dtype=np.float32)
        bbox_targets_blob = np.zeros((0, 4 * num_classes), dtype=np.float32)
        bbox_inside_blob = np.zeros(bbox_targets_blob.shape, dtype=np.float32)
        # all_overlaps = []
        for im_i in xrange(num_images):
            labels, overlaps, im_rois, bbox_targets, bbox_inside_weights \
                = _sample_rois(roidb[im_i], fg_rois_per_image, rois_per_image,
                               num_classes)

            # Add to RoIs blob
            rois = _project_im_rois(im_rois, im_scales[im_i])
            batch_ind = im_i * np.ones((rois.shape[0], 1))
            rois_blob_this_image = np.hstack((batch_ind, rois))
            rois_blob = np.vstack((rois_blob, rois_blob_this_image))

            # Add to labels, bbox targets, and bbox loss blobs
            labels_blob = np.hstack((labels_blob, labels))
            bbox_targets_blob = np.vstack((bbox_targets_blob, bbox_targets))
            bbox_inside_blob = np.vstack((bbox_inside_blob, bbox_inside_weights))
            # all_overlaps = np.hstack((all_overlaps, overlaps))

        # For debug visualizations
        # _vis_minibatch(im_blob, rois_blob, labels_blob, all_overlaps)

        blobs['rois'] = rois_blob
        blobs['labels'] = labels_blob

        if cfg.TRAIN.BBOX_REG:
            blobs['bbox_targets'] = bbox_targets_blob
            blobs['bbox_inside_weights'] = bbox_inside_blob
            blobs['bbox_outside_weights'] = \
                np.array(bbox_inside_blob > 0).astype(np.float32)

    return blobs


下面看看具體是如何讀取圖片資料的:

def _get_image_blob(roidb, scale_inds):這個函式其實就是讀取圖片,然後做尺寸變換,然後儲存成4維矩陣的形式,返回;

def _get_image_blob(roidb, scale_inds):
    """Builds an input blob from the images in the roidb at the specified
    scales.
    """
    num_images = len(roidb)
    processed_ims = []
    im_scales = []
    for i in xrange(num_images):
        im = cv2.imread(roidb[i]['image'])#讀取圖片,返回的是一個ndarray的三維的矩陣
        if roidb[i]['flipped']:#如果這張圖片是水平對稱的資料,那麼將三維矩陣中的第二維資料(寬)做對稱操作
            im = im[:, ::-1, :]
        target_size = cfg.TRAIN.SCALES[scale_inds[i]]#確定選定的縮放的(最短邊)尺寸的大小
        im, im_scale = prep_im_for_blob(im, cfg.PIXEL_MEANS, target_size,
                                        cfg.TRAIN.MAX_SIZE)#呼叫函式對圖片進行縮放
        im_scales.append(im_scale)#把縮放係數,放到list中
        processed_ims.append(im)#把三維矩陣資料作為一個元素放到list中

    # Create a blob to hold the input images
    blob = im_list_to_blob(processed_ims)#呼叫函式,把前面在list中的三維矩陣元素,轉換成4維矩陣的形式

    return blob, im_scales

在下面的函式中,作者將list中的3維的元素,轉換成了4維的ndarray,下面看看作者是如何做的:

def im_list_to_blob(ims):#這裡輸入的ims是一個list,其中的每個元素是一個3維的圖片矩陣資料
    """Convert a list of images into a network input.

    Assumes images are already prepared (means subtracted, BGR order, ...).
    """
    max_shape = np.array([im.shape for im in ims]).max(axis=0)#統計所有圖片的height width的最大值
    num_images = len(ims)
    blob = np.zeros((num_images, max_shape[0], max_shape[1], 3),
                    dtype=np.float32)#構造一個全部為0的4維的矩陣,暫時的順序是圖片、高、寬、通道
    for i in xrange(num_images):
        im = ims[i]
        blob[i, 0:im.shape[0], 0:im.shape[1], :] = im #把每個圖片對應的資料copy到blob中
    # Move channels (axis 3) to axis 1
    # Axis order will become: (batch elem, channel, height, width)
    channel_swap = (0, 3, 1, 2)#設定矩陣維度變換的引數,最終的4個維度分別對應圖片、通道、高、寬,這與caffe的blob的格式就保持一致了
    blob = blob.transpose(channel_swap)
    return blob


作者:香蕉麥樂迪--sloanqin--覃元元