text: # Copyright (c) 2017-present, Facebook, Inc.
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #
  #     http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  ##############################################################################
  #
  # Based on:
  # --------------------------------------------------------
  # Fast R-CNN
  # Copyright (c) 2015 Microsoft
  # Licensed under The MIT License [see LICENSE for details]
  # Written by Ross Girshick
  # --------------------------------------------------------
  
  """Construct minibatches for Detectron networks."""
  
  from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  from __future__ import unicode_literals
  
  import cv2
  import logging
  import numpy as np
  
  from detectron.core.config import cfg
  import detectron.roi_data.fast_rcnn as fast_rcnn_roi_data
  import detectron.roi_data.retinanet as retinanet_roi_data
  import detectron.roi_data.rpn as rpn_roi_data
  import detectron.roi_data.classification as classification_roi_data
  import detectron.utils.blob as blob_utils
  
  logger = logging.getLogger(__name__)
  
  
  def get_minibatch_blob_names(is_training=True):
      """Return blob names in the order in which they are read by the data loader.
      """
      # data blob: holds a batch of N images, each with 3 channels
      blob_names = ['data']
      if cfg.RPN.RPN_ON:
          # RPN-only or end-to-end Faster R-CNN
          blob_names += rpn_roi_data.get_rpn_blob_names(is_training=is_training)
      elif cfg.RETINANET.RETINANET_ON:
          blob_names += retinanet_roi_data.get_retinanet_blob_names(
              is_training=is_training
          )
      elif cfg.MODEL.CLASSIFICATION:
          # for classification models
          blob_names += classification_roi_data.get_classification_blob_names(
              is_training=is_training
          )
      else:
          # Fast R-CNN like models trained on precomputed proposals
          blob_names += fast_rcnn_roi_data.get_fast_rcnn_blob_names(
              is_training=is_training
          )
      return blob_names
  
  
  def get_minibatch(roidb):
      """Given a roidb, construct a minibatch sampled from it."""
      # We collect blobs from each image onto a list and then concat them into a
      # single tensor, hence we initialize each blob to an empty list
      blobs = {k: [] for k in get_minibatch_blob_names()}
      # Get the input image blob, formatted for caffe2
      im_blob, im_scales = _get_image_blob(roidb)
      blobs['data'] = im_blob
      if cfg.RPN.RPN_ON:
          # RPN-only or end-to-end Faster/Mask R-CNN
          valid = rpn_roi_data.add_rpn_blobs(blobs, im_scales, roidb)
      elif cfg.RETINANET.RETINANET_ON:
          im_width, im_height = im_blob.shape[3], im_blob.shape[2]
          # im_width, im_height corresponds to the network input: padded image
          # (if needed) width and height. We pass it as input and slice the data
          # accordingly so that we don't need to use SampleAsOp
          valid = retinanet_roi_data.add_retinanet_blobs(
              blobs, im_scales, roidb, im_width, im_height
          )
      elif cfg.MODEL.CLASSIFICATION:
          # for classification models
          valid = classification_roi_data.add_classification_blobs(
              blobs, im_scales, roidb
          )
      else:
          # Fast R-CNN like models trained on precomputed proposals
          valid = fast_rcnn_roi_data.add_fast_rcnn_blobs(blobs, im_scales, roidb)
      return blobs, valid
  
  
  def _get_image_blob(roidb):
      """Builds an input blob from the images in the roidb at the specified
      scales.
      """
      num_images = len(roidb)
      # Sample random scales to use for each image in this batch
      scale_inds = np.random.randint(
          0, high=len(cfg.TRAIN.SCALES), size=num_images
      )
      processed_ims = []
      im_scales = []
      for i in range(num_images):
          im = cv2.imread(roidb[i]['image'])
          assert im is not None, \
              'Failed to read image \'{}\''.format(roidb[i]['image'])
          if roidb[i]['flipped']:
              im = im[:, ::-1, :]
          target_size = cfg.TRAIN.SCALES[scale_inds[i]]
          im, im_scale = blob_utils.prep_im_for_blob(
              im, cfg.PIXEL_MEANS, target_size, cfg.TRAIN.MAX_SIZE
          )
          im_scales.append(im_scale)
          processed_ims.append(im)
  
      # Create a blob to hold the input images
      blob = blob_utils.im_list_to_blob(processed_ims)
  
      return blob, im_scales
  