def bitwise_mask( ann: Annotation, class_mask: str, classes_to_correct: List[str], bitwise_op: Callable[[np.ndarray, np.ndarray], np.ndarray] = np.logical_and ) -> Annotation: """ Performs bitwise operation between two masks. Uses one target mask to correct all others. Args ann: Input annotation. class_mask: Class name of target mask. classes_to_correct: List of classes which will be corrected using target mask. bitwise_op: Bitwise numpy function to process masks.For example: "np.logical_or", "np.logical_and", "np.logical_xor". Returns: Annotation containing corrected Bitmaps. """ imsize = ann.img_size def find_mask_class(labels, class_mask_name): for label in labels: if label.obj_class.name == class_mask_name: if not isinstance(label.geometry, Bitmap): raise RuntimeError( 'Class <{}> must be a Bitmap.'.format(class_mask_name)) return label mask_label = find_mask_class(ann.labels, class_mask) if mask_label is not None: target_original, target_mask = mask_label.geometry.origin, mask_label.geometry.data full_target_mask = np.full(imsize, False, bool) full_target_mask[target_original.row:target_original.row + target_mask.shape[0], target_original.col:target_original.col + target_mask.shape[1]] = target_mask def perform_op(label): if label.obj_class.name not in classes_to_correct or label.obj_class.name == class_mask: return [label] if not isinstance(label.geometry, Bitmap): raise RuntimeError('Input class must be a Bitmap.') new_geom = label.geometry.bitwise_mask(full_target_mask, bitwise_op) return [label.clone( geometry=new_geom)] if new_geom is not None else [] res_ann = ann.transform_labels(perform_op) else: res_ann = ann.clone() return res_ann
def _get_annotation_for_bbox(img: np.ndarray, roi: Rectangle, model) -> Annotation: """Runs inference within the given roi; moves resulting figures to global reference frame.""" img_cropped = roi.get_cropped_numpy_slice(img) # TODO pass through image and parent figure tags via roi_ann. roi_ann = Annotation(img_size=(roi.height, roi.width)) raw_result_ann = model.inference(img_cropped, roi_ann) return Annotation(img_size=img.shape[:2], labels=[label.translate(drow=roi.top, dcol=roi.left) for label in raw_result_ann.labels], img_tags=raw_result_ann.img_tags, img_description=raw_result_ann.img_description, pixelwise_scores_labels=[label.translate(drow=roi.top, dcol=roi.left) for label in raw_result_ann.pixelwise_scores_labels])
def run_evaluation(self): progress = Progress('metric evaluation', self._project_gt.total_items) for ds_name in self._project_gt.datasets.keys(): ds_gt = self._project_gt.datasets.get(ds_name) ds_pred = self._project_pred.datasets.get(ds_name) for sample_name in ds_gt: try: ann_gt = Annotation.load_json_file(ds_gt.get_ann_path(sample_name), self._project_gt.meta) ann_pred = Annotation.load_json_file(ds_pred.get_ann_path(sample_name), self._project_pred.meta) self._metric.add_pair(ann_gt, ann_pred) except ValueError as e: logger.warning('An error has occured ({}). Sample "{}" in dataset "{}" will be skipped' .format(str(e), sample_name, ds_gt.name)) progress.iter_done_report()
def _do_single_img_inference(self, img, in_msg): in_project_meta = self._in_project_meta_from_msg(in_msg) ann_json = in_msg.get('annotation') if ann_json is not None: if in_project_meta is None: raise ValueError('In order to perform inference with annotation you must specify the appropriate' ' project meta.') ann = Annotation.from_json(ann_json, in_project_meta) else: in_project_meta = in_project_meta or ProjectMeta() ann = Annotation(img.shape[:2]) inference_mode = self._make_inference_mode(in_msg.get(MODE, {}), in_project_meta) inference_result = inference_mode.infer_annotate(img, ann) return inference_result.to_json()
def post(self): args = self._parser.parse_args() img_bytes = args[IMAGE].stream.read() img = sly_image.read_bytes(img_bytes) ann = self._model.inference(img, Annotation(img_size=img.shape[:2])) return {ANNOTATION: ann.to_json()}
def _do_infer_annotate(self, img: np.ndarray, ann: Annotation) -> Annotation: result_ann = ann.clone() model_labels = [] for roi in self._sliding_windows.get(ann.img_size): raw_roi_ann = _get_annotation_for_bbox(img, roi, self._model) all_rectangle_labels = [ label for label in raw_roi_ann.labels if isinstance(label.geometry, Rectangle) ] model_labels.extend( _replace_labels_classes(all_rectangle_labels, self._model_class_mapper, self._model_tag_meta_mapper, skip_missing=True)) model_img_level_tags = make_renamed_tags( raw_roi_ann.img_tags, self._model_tag_meta_mapper, skip_missing=True) result_ann = result_ann.add_labels( _maybe_make_bbox_label(roi, self._intermediate_bbox_class, tags=model_img_level_tags)) nms_conf = self._config.get(NMS_AFTER, {ENABLE: False}) if nms_conf[ENABLE]: result_ann = result_ann.add_labels( self._general_nms(labels=model_labels, iou_thresh=nms_conf[IOU_THRESHOLD], confidence_tag_name=nms_conf.get( CONFIDENCE_TAG_NAME, CONFIDENCE))) else: result_ann = result_ann.add_labels(model_labels) return result_ann
def _do_infer_annotate(self, img: np.ndarray, ann: Annotation) -> Annotation: result_labels = [] for src_label, roi in self._all_filtered_bbox_rois( ann, self._config[FROM_CLASSES], self._config[PADDING]): if roi is None: result_labels.append(src_label) else: roi_ann = _get_annotation_for_bbox(img, roi, self._model) result_labels.extend( _replace_labels_classes(roi_ann.labels, self._model_class_mapper, self._model_tag_meta_mapper, skip_missing=True)) model_img_level_tags = make_renamed_tags( roi_ann.img_tags, self._model_tag_meta_mapper, skip_missing=True) if self._config[SAVE]: result_labels.append( Label(geometry=roi, obj_class=self._intermediate_class_mapper.map( src_label.obj_class), tags=model_img_level_tags)) # Regardless of whether we need to save intermediate bounding boxes, also put the inference result tags # onto the original source object from which we created a bounding box. # This is necessary for e.g. classification models to work, so that they put the classification results # onto the original object. result_labels.append(src_label.add_tags(model_img_level_tags)) return ann.clone(labels=result_labels)
def save_project_as_pascal_voc_detection(save_path, project: Project): # Create root pascal 'datasets' folders for dataset in project.datasets: pascal_dataset_path = os.path.join(save_path, dataset.name) pascal_dataset_relative_path = os.path.relpath(pascal_dataset_path, save_path) images_dir = os.path.join(pascal_dataset_path, 'JPEGImages') anns_dir = os.path.join(pascal_dataset_path, 'Annotations') lists_dir = os.path.join(pascal_dataset_path, 'ImageSets/Layout') fs_utils.mkdir(pascal_dataset_path) for subdir in [ 'ImageSets', # Train list, Val list, etc. 'ImageSets/Layout', 'Annotations', 'JPEGImages' ]: fs_utils.mkdir(os.path.join(pascal_dataset_path, subdir)) samples_by_tags = defaultdict(list) # TRAIN: [img_1, img2, ..] for item_name in dataset: img_path, ann_path = dataset.get_item_paths(item_name) no_ext_name = fs_utils.get_file_name(item_name) pascal_img_path = os.path.join(images_dir, no_ext_name + OUT_IMG_EXT) pascal_ann_path = os.path.join(anns_dir, no_ext_name + XML_EXT) if item_name.endswith(OUT_IMG_EXT): fs_utils.copy_file(img_path, pascal_img_path) else: img = image_utils.read(img_path) image_utils.write(pascal_img_path, img) ann = Annotation.load_json_file(ann_path, project_meta=project.meta) # Read tags for images lists generation for tag in ann.img_tags: samples_by_tags[tag.name].append( (no_ext_name, len(ann.labels))) writer = pascal_voc_writer.Writer( path=pascal_dataset_relative_path, width=ann.img_size[1], height=ann.img_size[0]) for label in ann.labels: obj_class = label.obj_class rect: Rectangle = label.geometry.to_bbox() writer.addObject(name=obj_class.name, xmin=rect.left, ymin=rect.top, xmax=rect.right, ymax=rect.bottom) writer.save(pascal_ann_path) save_images_lists(lists_dir, samples_by_tags)
def _do_infer_annotate(self, img: np.ndarray, ann: Annotation) -> Annotation: result_ann = ann.clone() model_labels = [] roi_bbox_labels = [] for roi in self._sliding_windows.get(ann.img_size): raw_roi_ann = _get_annotation_for_bbox(img, roi, self._model) # Accumulate all the labels across the sliding windows to potentially run non-max suppression over them. # Only retain the classes that will be eventually saved to avoid running NMS on objects we will # throw away anyway. model_labels.extend([ label for label in raw_roi_ann.labels if isinstance(label.geometry, Rectangle) and self._model_class_mapper.map(label.obj_class) is not None]) model_img_level_tags = make_renamed_tags( raw_roi_ann.img_tags, self._model_tag_meta_mapper, skip_missing=True) roi_bbox_labels.extend( _maybe_make_bbox_label(roi, self._intermediate_bbox_class, tags=model_img_level_tags)) nms_conf = self._config.get(NMS_AFTER, {ENABLE: False}) if nms_conf[ENABLE]: confidence_tag_name = nms_conf.get(CONFIDENCE_TAG_NAME, CONFIDENCE) model_labels = self._general_nms( labels=model_labels, iou_thresh=nms_conf[IOU_THRESHOLD], confidence_tag_name=confidence_tag_name) model_labels_renamed = _replace_or_drop_labels_classes( model_labels, self._model_class_mapper, self._model_tag_meta_mapper) result_ann = result_ann.add_labels(roi_bbox_labels + model_labels_renamed) return result_ann
def _make_final_ann(self, result_ann): frontend_compatible_labels = _remove_backend_only_labels(result_ann.labels) return Annotation(img_size=result_ann.img_size, labels=frontend_compatible_labels, img_tags=result_ann.img_tags, img_description=result_ann.img_description, pixelwise_scores_labels=result_ann.pixelwise_scores_labels)
def adjust_annotations(ann_paths, meta, progress): for ann_path in ann_paths: temp_json_data = None with open(ann_path, 'r') as annotation_file: temp_annotation = Annotation.from_json(json.load(annotation_file), meta) # Adjust Image dimension infos for annotation file new_img_size = tuple( map(lambda dim: dim + fsoco.FSOCO_IMPORT_BORDER_THICKNESS * 2, temp_annotation.img_size)) temp_annotation._img_size = new_img_size # Transform labels according to borders added by watermarking #translate_label = (lambda label: [label.translate(drow=fsoco.FSOCO_IMPORT_BORDER_THICKNESS, dcol=fsoco.FSOCO_IMPORT_BORDER_THICKNESS)]) #temp_annotation.transform_labels(translate_label) temp_labels = [] for label in temp_annotation._labels: # Do stuff to labels # Add border thickness once to each dimension of the bbox points. temp_label = label.translate( fsoco.FSOCO_IMPORT_BORDER_THICKNESS, fsoco.FSOCO_IMPORT_BORDER_THICKNESS) temp_labels.append(temp_label) temp_annotation._labels = temp_labels # Save transformed annotation temp_json_data = temp_annotation.to_json() with open(ann_path, 'w') as annotation_file: annotation_file.write(json.dumps(temp_json_data)) progress.iter_done_report()
def inference(self, img, ann): # Rescale with proportions and pad image to model input size min_side_coef = min(self.input_size[0] / float(img.shape[0]), self.input_size[1] / float(img.shape[1])) img_resized = cv2.resize(img, dsize=None, fx=min_side_coef, fy=min_side_coef, interpolation=cv2.INTER_CUBIC) img_padded = cv2.copyMakeBorder( img_resized, 0, self.input_size[0] - img_resized.shape[0], 0, self.input_size[1] - img_resized.shape[1], cv2.BORDER_CONSTANT, value=0) preds = self.sess.run(self.pred_holder, feed_dict={self.image_tensor: img_padded})[0] preds = np.argmax(preds, axis=2) # Un-pad and rescale prediction to original image size preds = preds[0:img_resized.shape[0], 0:img_resized.shape[1]] preds = cv2.resize(preds, (img.shape[1], img.shape[0]), interpolation=cv2.INTER_NEAREST) labels = raw_to_labels.segmentation_array_to_sly_bitmaps( self.out_class_mapping, preds) return Annotation(img_size=ann.img_size, labels=labels)
def single_inference_process_fn(inference_initializer, inference_mode_config, in_project_meta_json, request_queue, response_queue): """Loads a separate model, processes requests from request_queue, results go to result_queue. None request signals the process to finish. """ single_image_inference = inference_initializer() inference_mode = InferenceModeFactory.create( inference_mode_config, ProjectMeta.from_json(in_project_meta_json), single_image_inference) out_meta_json = inference_mode.out_meta.to_json() req = '' while req is not None: req = request_queue.get() if req is not None: in_img = sly_image.read(req.item_paths.img_path) in_ann = Annotation.load_json_file(req.item_paths.ann_path, inference_mode.out_meta) ann = inference_mode.infer_annotate(in_img, in_ann) resp = InferenceResponse(ds_name=req.ds_name, item_name=req.item_name, item_paths=req.item_paths, ann_json=ann.to_json(), meta_json=out_meta_json) response_queue.put(resp) request_queue.task_done()
def verify_data(orig_ann: Annotation, classes_matching: dict, res_project_meta: ProjectMeta) -> Annotation: ann = orig_ann.clone() imsize = ann.img_size for first_class, second_class in classes_matching.items(): mask1 = np.zeros(imsize, dtype=np.bool) mask2 = np.zeros(imsize, dtype=np.bool) for label in ann.labels: if label.obj_class.name == first_class: label.geometry.draw(mask1, True) elif label.obj_class.name == second_class: label.geometry.draw(mask2, True) iou_value = _compute_masks_iou(mask1, mask2) tag_meta = res_project_meta.img_tag_metas.get(make_iou_tag_name(first_class)) tag = Tag(tag_meta, iou_value) ann.add_tag(tag) fp_mask = _create_fp_mask(mask1, mask2) if fp_mask.sum() != 0: fp_object_cls = res_project_meta.obj_classes.get(make_false_positive_name(first_class)) fp_geom = Bitmap(data=fp_mask) fp_label = Label(fp_geom, fp_object_cls) ann.add_label(fp_label) fn_mask = _create_fn_mask(mask1, mask2) if fn_mask.sum() != 0: fn_object_cls = res_project_meta.obj_classes.get(make_false_negative_name(first_class)) fn_geom = Bitmap(data=fn_mask) fn_label = Label(fn_geom, fn_object_cls) ann.add_label(fn_label) return ann
def set_ann(self, item_name: str, ann: Annotation): if type(ann) is not Annotation: raise TypeError( "Type of 'ann' have to be Annotation, not a {}".format( type(ann))) dst_ann_path = self.get_ann_path(item_name) dump_json_file(ann.to_json(), dst_ann_path)
def _do_infer_annotate(self, img: np.ndarray, ann: Annotation) -> Annotation: result_ann = ann.clone() all_pixelwise_scores_labels = [] for roi in self._sliding_windows.get(ann.img_size): raw_roi_ann = _get_annotation_for_bbox(img, roi, self._model) all_pixelwise_scores_labels.extend(raw_roi_ann.pixelwise_scores_labels) model_img_level_tags = make_renamed_tags(raw_roi_ann.img_tags, self._model_img_tag_meta_mapper, make_renamed_tags) result_ann = result_ann.add_labels( _maybe_make_bbox_label(roi, self._intermediate_bbox_class, tags=model_img_level_tags)) model_class_name_to_id = {name: idx for idx, name in enumerate(set(label.obj_class.name for label in all_pixelwise_scores_labels))} id_to_class_obj = {idx: self._model.model_out_meta.obj_classes.get(name) for name, idx in model_class_name_to_id.items()} summed_scores = np.zeros(ann.img_size + tuple([len(model_class_name_to_id)])) for label in all_pixelwise_scores_labels: class_idx = model_class_name_to_id[label.obj_class.name] label_matching_summer_scores = label.geometry.to_bbox().get_cropped_numpy_slice(summed_scores) label_matching_summer_scores[:, :, class_idx, np.newaxis] += label.geometry.data # TODO consider instead filtering pixels by all-zero scores. if np.sum(summed_scores, axis=2).min() == 0: raise RuntimeError('Wrong sliding window moving, implementation error.') aggregated_model_labels = raw_to_labels.segmentation_array_to_sly_bitmaps(id_to_class_obj, np.argmax(summed_scores, axis=2)) result_ann = result_ann.add_labels( replace_labels_classes(aggregated_model_labels, self._model_class_mapper, skip_missing=True)) return result_ann
def load_ann(ann_fpath, classes_mapping, project_meta): ann_packed = load_json_file(ann_fpath) ann = Annotation.from_json(ann_packed, project_meta) # ann.normalize_figures() # @TODO: enaaaable! (h, w) = ann.img_size gt_boxes, classes_text, classes = [], [], [] for label in ann.labels: gt = np.zeros((h, w), dtype=np.uint8) # default bkg gt_idx = classes_mapping.get(label.obj_class.name, None) if gt_idx is None: raise RuntimeError( 'Missing class mapping (title to index). Class {}.'.format( label.obj_class.name)) label.geometry.draw(gt, 1) if np.sum(gt) > 0: xmin, ymin, xmax, ymax = get_bbox(gt) gt_boxes.append([ymin / h, xmin / w, ymax / h, xmax / w]) classes_text.append(label.obj_class.name.encode('utf8')) # List of string class name of bounding box (1 per box) classes.append( gt_idx) # List of integer class id of bounding box (1 per box) num_boxes = len(gt_boxes) gt_boxes = np.array(gt_boxes).astype(np.float32) classes = np.array(classes, dtype=np.int64) if num_boxes == 0: gt_boxes = np.reshape(gt_boxes, [0, 4]) return gt_boxes, classes, np.array([num_boxes]).astype(np.int32)[0]
def rotate(img: np.ndarray, ann: Annotation, degrees: float, mode: str=RotationModes.KEEP) ->\ (np.ndarray, Annotation): # @TODO: add "preserve_size" mode """ Rotates the image by random angle. Args: img: Input image array. ann: Input annotation. degrees: Rotation angle, counter-clockwise. mode: parameter: "keep" - keep original image data, then new regions will be filled with black color; "crop" - crop rotated result to exclude black regions; Returns: A tuple containing rotated image array and annotation. """ _validate_image_annotation_shape(img, ann) rotator = ImageRotator(img.shape[:2], degrees) if mode == RotationModes.KEEP: rect_to_crop = None elif mode == RotationModes.CROP: rect_to_crop = rotator.inner_crop else: raise NotImplementedError('Wrong black_regions mode.') res_img = rotator.rotate_img(img, use_inter_nearest=False) res_ann = ann.rotate(rotator) if rect_to_crop is not None: res_img = sly_image.crop(res_img, rect_to_crop) res_ann = res_ann.relative_crop(rect_to_crop) return res_img, res_ann
def crop(img: np.ndarray, ann: Annotation, top_pad: int = 0, left_pad: int = 0, bottom_pad: int = 0, right_pad: int = 0) -> (np.ndarray, Annotation): """ Crops the given image array and annotation from all sides with the given values. Args: img: Input image array. ann: Input annotation. top_pad: The size in pixels of the piece of picture that will be cut from the top side. left_pad: The size in pixels of the piece of picture that will be cut from the left side. bottom_pad: The size in pixels of the piece of picture that will be cut from the bottom side. right_pad: The size in pixels of the piece of picture that will be cut from the right side. Returns: A tuple containing cropped image array and annotation. """ _validate_image_annotation_shape(img, ann) height, width = img.shape[:2] crop_rect = Rectangle(top_pad, left_pad, height - bottom_pad - 1, width - right_pad - 1) res_img = sly_image.crop(img, crop_rect) res_ann = ann.relative_crop(crop_rect) return res_img, res_ann
def run_inference(self): inference_mode = InferenceModeFactory.create( self._inference_mode_config, self._in_project.meta, self._single_image_inference) out_project = Project( os.path.join(TaskPaths.RESULTS_DIR, self._in_project.name), OpenMode.CREATE) out_project.set_meta(inference_mode.out_meta) progress_bar = Progress('Model applying: ', self._in_project.total_items) for in_dataset in self._in_project: out_dataset = out_project.create_dataset(in_dataset.name) for in_item_name in in_dataset: # Use output project meta so that we get an annotation that is already in the context of the output # project (with added object classes etc). in_item_paths = in_dataset.get_item_paths(in_item_name) in_img = sly_image.read(in_item_paths.img_path) in_ann = Annotation.load_json_file(in_item_paths.ann_path, inference_mode.out_meta) logger.trace('Will process image', extra={ 'dataset_name': in_dataset.name, 'image_name': in_item_name }) inference_annotation = inference_mode.infer_annotate( in_img, in_ann) out_dataset.add_item_file(in_item_name, in_item_paths.img_path, ann=inference_annotation) progress_bar.iter_done_report() report_inference_finished()
def filter_objects_by_area(ann: Annotation, classes: List[str], comparator=operator.lt, thresh_percent: float = None) -> Annotation: # @ TODO: add size mode """ Deletes labels less (or greater) than specified percentage of image area. Args ann: Input annotation. classes: List of classes to filter. comparator: Comparison function. thresh_percent: Threshold percent value of image area. Returns: Annotation containing filtered labels. """ imsize = ann.img_size img_area = float(imsize[0] * imsize[1]) def _del_filter_percent(label: Label): if label.obj_class.name in classes: fig_area = label.area area_percent = 100.0 * fig_area / img_area if comparator(area_percent, thresh_percent): # satisfied condition return [] # action 'delete' return [label] return ann.transform_labels(imsize, _del_filter_percent)
def inference(self, image, ann): res_labels = inference_lib.infer_on_image(image, self.graph, self.model, self.idx_to_class_title, self.model_out_meta, self.confidence_tag_meta) return Annotation(ann.img_size, labels=res_labels)
def infer_annotate(self, img: np.ndarray, ann: Annotation): result_ann = self._do_infer_annotate(img, ann) frontend_compatible_labels = _remove_backend_only_labels( result_ann.labels) return Annotation(img_size=result_ann.img_size, labels=frontend_compatible_labels, img_tags=result_ann.img_tags, img_description=result_ann.img_description)
def inference(self, img, ann): output = infer_on_img(img, self.input_size, self.model) tag_id = np.argmax(output) score = output[tag_id] tag_name = self.idx_to_classification_tags[tag_id] tag = Tag(self.classification_tags.get(tag_name), round(float(score), 4)) tags = TagCollection([tag]) return Annotation(ann.img_size, img_tags=tags)
def inference(self, img, ann): resized_img = cv2.resize(img, self.input_size[::-1]) model_input = input_image_normalizer(resized_img) pixelwise_probas_array = pytorch_inference.infer_per_pixel_scores_single_image( self.model, model_input, img.shape[:2]) labels = raw_to_labels.segmentation_array_to_sly_bitmaps( self.out_class_mapping, np.argmax(pixelwise_probas_array, axis=2)) pixelwise_scores_labels = raw_to_labels.segmentation_scores_to_per_class_labels( self.out_class_mapping, pixelwise_probas_array) return Annotation(ann.img_size, labels=labels, pixelwise_scores_labels=pixelwise_scores_labels)
def _do_infer_annotate(self, img: np.ndarray, ann: Annotation) -> Annotation: result_ann = ann.clone() inference_result_ann = self._model.inference(img, ann) result_ann = result_ann.add_labels( replace_labels_classes(inference_result_ann.labels, self._model_class_mapper, skip_missing=True)) renamed_tags = make_renamed_tags(inference_result_ann.img_tags, self._model_img_tag_meta_mapper, skip_missing=True) result_ann = result_ann.add_tags(renamed_tags) return result_ann
def _do_infer_annotate(self, img: np.ndarray, ann: Annotation) -> Annotation: result_ann = ann.clone() roi = _make_cropped_rectangle(ann.img_size, self._config[BOUNDS]) roi_ann = _get_annotation_for_bbox(img, roi, self._model) result_ann = result_ann.add_labels( replace_labels_classes(roi_ann.labels, self._model_class_mapper, skip_missing=True)) img_level_tags = make_renamed_tags(roi_ann.img_tags, self._model_img_tag_meta_mapper, skip_missing=True) result_ann = result_ann.add_labels( _maybe_make_bbox_label(roi, self._intermediate_bbox_class, tags=roi_ann.img_tags)) result_ann = result_ann.add_tags(img_level_tags) return result_ann
def _do_infer_annotate_generic(self, inference_fn, img, ann: Annotation): result_ann = ann.clone() inference_result_ann = inference_fn(img, ann) result_ann = result_ann.add_labels( _replace_or_drop_labels_classes( inference_result_ann.labels, self._model_class_mapper, self._model_tag_meta_mapper)) renamed_tags = make_renamed_tags(inference_result_ann.img_tags, self._model_tag_meta_mapper, skip_missing=True) result_ann = result_ann.add_tags(renamed_tags) return result_ann
def instance_crop(img: np.ndarray, ann: Annotation, class_title: str, save_other_classes_in_crop: bool = True, padding_config: dict = None) -> list: """ Crops objects of specified classes from image with configurable padding. Args: img: Input image array. ann: Input annotation. class_title: Name of class to crop. save_other_classes_in_crop: save non-target classes in each cropped annotation. padding_config: Dict with padding Returns: List of cropped [image, annotation] pairs. """ padding_config = take_with_default(padding_config, {}) _validate_image_annotation_shape(img, ann) results = [] img_rect = Rectangle.from_size(img.shape[:2]) if save_other_classes_in_crop: non_target_labels = [ label for label in ann.labels if label.obj_class.name != class_title ] else: non_target_labels = [] ann_with_non_target_labels = ann.clone(labels=non_target_labels) for label in ann.labels: if label.obj_class.name == class_title: src_fig_rect = label.geometry.to_bbox() new_img_rect = _rect_from_bounds(padding_config, img_w=src_fig_rect.width, img_h=src_fig_rect.height) rect_to_crop = new_img_rect.translate(src_fig_rect.top, src_fig_rect.left) crops = rect_to_crop.crop(img_rect) if len(crops) == 0: continue rect_to_crop = crops[0] image_crop = sly_image.crop(img, rect_to_crop) cropped_ann = ann_with_non_target_labels.relative_crop( rect_to_crop) label_crops = label.relative_crop(rect_to_crop) for label_crop in label_crops: results.append((image_crop, cropped_ann.add_label(label_crop))) return results
def _set_ann_by_type(self, item_name, ann): if ann is None: img_size = sly_image.read(self.get_img_path(item_name)).shape[:2] self.set_ann(item_name, Annotation(img_size)) elif type(ann) is Annotation: self.set_ann(item_name, ann) elif type(ann) is str: self.set_ann_file(item_name, ann) elif type(ann) is dict: self.set_ann_dict(item_name, ann) else: raise TypeError("Unsupported type {!r} for ann argument".format( type(ann)))