The mapper to preprocess the input data for training. Since the mapping may run in other processes, we write a new class and explicitly pass cfg to it, in the spirit of "explicitly pass resources to subprocess".
| 63 | |
| 64 | |
| 65 | class TrainingDataPreprocessor: |
| 66 | """ |
| 67 | The mapper to preprocess the input data for training. |
| 68 | |
| 69 | Since the mapping may run in other processes, we write a new class and |
| 70 | explicitly pass cfg to it, in the spirit of "explicitly pass resources to subprocess". |
| 71 | """ |
| 72 | |
| 73 | def __init__(self, cfg): |
| 74 | self.cfg = cfg |
| 75 | self.aug = imgaug.AugmentorList([ |
| 76 | CustomResize(cfg.PREPROC.TRAIN_SHORT_EDGE_SIZE, cfg.PREPROC.MAX_SIZE), |
| 77 | imgaug.Flip(horiz=True) |
| 78 | ]) |
| 79 | |
| 80 | def __call__(self, roidb): |
| 81 | fname, boxes, klass, is_crowd = roidb["file_name"], roidb["boxes"], roidb["class"], roidb["is_crowd"] |
| 82 | assert boxes.ndim == 2 and boxes.shape[1] == 4, boxes.shape |
| 83 | boxes = np.copy(boxes) |
| 84 | im = cv2.imread(fname, cv2.IMREAD_COLOR) |
| 85 | assert im is not None, fname |
| 86 | im = im.astype("float32") |
| 87 | height, width = im.shape[:2] |
| 88 | # assume floatbox as input |
| 89 | assert boxes.dtype == np.float32, "Loader has to return float32 boxes!" |
| 90 | |
| 91 | if not self.cfg.DATA.ABSOLUTE_COORD: |
| 92 | boxes[:, 0::2] *= width |
| 93 | boxes[:, 1::2] *= height |
| 94 | |
| 95 | # augmentation: |
| 96 | tfms = self.aug.get_transform(im) |
| 97 | im = tfms.apply_image(im) |
| 98 | points = box_to_point4(boxes) |
| 99 | points = tfms.apply_coords(points) |
| 100 | boxes = point4_to_box(points) |
| 101 | if len(boxes): |
| 102 | assert klass.max() <= self.cfg.DATA.NUM_CATEGORY, \ |
| 103 | "Invalid category {}!".format(klass.max()) |
| 104 | assert np.min(np_area(boxes)) > 0, "Some boxes have zero area!" |
| 105 | |
| 106 | ret = {"image": im} |
| 107 | # Add rpn data to dataflow: |
| 108 | try: |
| 109 | if self.cfg.MODE_FPN: |
| 110 | multilevel_anchor_inputs = self.get_multilevel_rpn_anchor_input(im, boxes, is_crowd) |
| 111 | for i, (anchor_labels, anchor_boxes) in enumerate(multilevel_anchor_inputs): |
| 112 | ret["anchor_labels_lvl{}".format(i + 2)] = anchor_labels |
| 113 | ret["anchor_boxes_lvl{}".format(i + 2)] = anchor_boxes |
| 114 | else: |
| 115 | ret["anchor_labels"], ret["anchor_boxes"] = self.get_rpn_anchor_input(im, boxes, is_crowd) |
| 116 | |
| 117 | boxes = boxes[is_crowd == 0] # skip crowd boxes in training target |
| 118 | klass = klass[is_crowd == 0] |
| 119 | ret["gt_boxes"] = boxes |
| 120 | ret["gt_labels"] = klass |
| 121 | except MalformedData as e: |
| 122 | log_once("Input {} is filtered for training: {}".format(fname, str(e)), "warn") |
no outgoing calls
no test coverage detected