def get_add_padding(self, source_shape): source_rect = Rectangle.from_size(source_shape) window_rect = Rectangle.from_size(self.window_shape) if not source_rect.contains(window_rect): raise RuntimeError( 'Sliding window: window is larger than source (image).') hw_limit = tuple(source_shape[i] - self.window_shape[i] for i in (0, 1)) for wind_top in range(0, hw_limit[0] + self.stride[0], self.stride[0]): for wind_left in range(0, hw_limit[1] + self.stride[1], self.stride[1]): roi = window_rect.translate(drow=wind_top, dcol=wind_left) yield roi
def geometry_to_bitmap(geometry, radius: int = 0, crop_image_shape: tuple = None) -> list: """ Args: geometry: Geometry type which implemented 'draw', 'translate' and 'to_bbox` methods radius: half of thickness of drawed vector elements crop_image_shape: if not None - crop bitmap object by this shape (HxW) Returns: Bitmap (geometry) object """ thickness = radius + 1 bbox = geometry.to_bbox() extended_bbox = Rectangle(top=bbox.top - radius, left=bbox.left - radius, bottom=bbox.bottom + radius, right=bbox.right + radius) bitmap_data = np.full(shape=(extended_bbox.height, extended_bbox.width), fill_value=False) geometry = geometry.translate(-extended_bbox.top, -extended_bbox.left) geometry.draw(bitmap_data, color=True, thickness=thickness) origin = PointLocation(extended_bbox.top, extended_bbox.left) bitmap_geometry = Bitmap(data=bitmap_data, origin=origin) if crop_image_shape is not None: crop_rect = Rectangle.from_size(*crop_image_shape) return bitmap_geometry.crop(crop_rect) return [bitmap_geometry]
def validate_bounds(self, img_size, _auto_correct=False): canvas_rect = Rectangle.from_size(img_size) if canvas_rect.contains(self.geometry.to_bbox()) is False: raise OutOfImageBoundsExtension("Figure is out of image bounds") if _auto_correct is True: geometries_after_crop = [cropped_geometry for cropped_geometry in self.geometry.crop(canvas_rect)] if len(geometries_after_crop) != 1: raise OutOfImageBoundsExtension("Several geometries after crop") self._set_geometry_inplace(geometries_after_crop[0])
def _all_filtered_bbox_rois(ann: Annotation, included_classes, crop_config: dict): for src_label in ann.labels: effective_roi = None if is_name_included(src_label.obj_class.name, included_classes): bbox = src_label.geometry.to_bbox() roi = _make_padded_rectangle((bbox.height, bbox.width), crop_config) maybe_effective_roi = roi.translate(drow=bbox.top, dcol=bbox.left).crop( Rectangle.from_size(ann.img_size)) if len(maybe_effective_roi) > 0: [effective_roi] = maybe_effective_roi yield src_label, effective_roi
def _add_labels_impl(self, dest, labels): ''' The function _add_labels_impl extend list of the labels of the current Annotation object :param dest: destination list of the Label class objects :param labels: list of the Label class objects to be added to the destination list :return: list of the Label class objects ''' for label in labels: # TODO Reconsider silent automatic normalization, reimplement canvas_rect = Rectangle.from_size(self.img_size) dest.extend(label.crop(canvas_rect))
def get_change_size(self, source_shape): source_rect = Rectangle.from_size(source_shape) window_rect = Rectangle.from_size(self.window_shape) if not source_rect.contains(window_rect): raise RuntimeError( 'Sliding window: window is larger than source (image).') hw_limit = tuple(source_shape[i] - self.window_shape[i] for i in (0, 1)) for wind_top in range(0, hw_limit[0] + self.stride[0], self.stride[0]): for wind_left in range(0, hw_limit[1] + self.stride[1], self.stride[1]): wind_bottom = min(wind_top + self.stride[0], source_shape[0]) wind_right = min(wind_left + self.stride[1], source_shape[1]) roi = Rectangle(wind_top, wind_left, wind_bottom - 1, wind_right - 1) if not source_rect.contains(roi): raise RuntimeError( 'Sliding window: result crop bounds are invalid.') yield roi
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 validate_bounds(self, img_size, _auto_correct=False): ''' The function validate_bounds checks if given image contains a figure. Raise error if figure is out of image bounds :param img_size: tuple or list of integers :param _auto_correct: bool ''' canvas_rect = Rectangle.from_size(img_size) if canvas_rect.contains(self.geometry.to_bbox()) is False: raise OutOfImageBoundsExtension("Figure is out of image bounds") if _auto_correct is True: geometries_after_crop = [cropped_geometry for cropped_geometry in self.geometry.crop(canvas_rect)] if len(geometries_after_crop) != 1: raise OutOfImageBoundsExtension("Several geometries after crop") self._set_geometry_inplace(geometries_after_crop[0])
def _add_labels_impl(self, dest, labels): for label in labels: # TODO Reconsider silent automatic normalization, reimplement canvas_rect = Rectangle.from_size(self.img_size) dest.extend(label.crop(canvas_rect))