Exemplo n.º 1
0
 def test_crop(self):
     crop_rect = Rectangle(top=1, left=0, bottom=10, right=4)
     res_geoms = self.bitmap.crop(crop_rect)
     self.assertEqual(len(res_geoms), 1)
     res_bitmap = res_geoms[0]
     res_data = np.array([[[0.6, 0.7]]], dtype=np.float64)
     self.assertMultichannelBitmapEquals(res_bitmap, 1, 4, res_data)
Exemplo n.º 2
0
def _rect_from_bounds(padding_config: dict, img_h: int,
                      img_w: int) -> Rectangle:
    def get_padding_pixels(raw_side, dim_name):
        side_padding_config = padding_config.get(dim_name)
        if side_padding_config is None:
            padding_pixels = 0
        elif side_padding_config.endswith('px'):
            padding_pixels = int(side_padding_config[:-len('px')])
        elif side_padding_config.endswith('%'):
            padding_fraction = float(side_padding_config[:-len('%')])
            padding_pixels = int(raw_side * padding_fraction / 100.0)
        else:
            raise ValueError(
                'Unknown padding size format: {}. Expected absolute values as "5px" or relative as "5%"'
                .format(side_padding_config))
        return padding_pixels

    def get_padded_side(raw_side, l_name, r_name):
        l_bound = -get_padding_pixels(raw_side, l_name)
        r_bound = raw_side + get_padding_pixels(raw_side, r_name)
        return l_bound, r_bound

    left, right = get_padded_side(img_w, 'left', 'right')
    top, bottom = get_padded_side(img_h, 'top', 'bottom')
    return Rectangle(top=top, left=left, bottom=bottom, right=right)
Exemplo n.º 3
0
def _rectangle_from_cropping_or_padding_bounds(img_shape, crop_config,
                                               do_crop: bool):
    def get_crop_pixels(raw_side, dim_name):
        side_crop_config = crop_config.get(dim_name)
        if side_crop_config is None:
            crop_pixels = 0
        elif side_crop_config.endswith(PX):
            crop_pixels = int(side_crop_config[:-len(PX)])
        elif side_crop_config.endswith(PERCENT):
            padding_fraction = float(side_crop_config[:-len(PERCENT)])
            crop_pixels = int(raw_side * padding_fraction / 100.0)
        else:
            raise ValueError(
                'Unknown padding size format: {}. Expected absolute values as "5px" or relative as "5%"'
                .format(side_crop_config))
        if not do_crop:
            crop_pixels *= -1  # Pad instead of crop.
        return crop_pixels

    # TODO more informative error message.
    return Rectangle(
        top=get_crop_pixels(img_shape[0], TOP),
        left=get_crop_pixels(img_shape[1], LEFT),
        bottom=img_shape[0] - get_crop_pixels(img_shape[0], BOTTOM) - 1,
        right=img_shape[1] - get_crop_pixels(img_shape[1], RIGHT) - 1)
Exemplo n.º 4
0
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
Exemplo n.º 5
0
 def to_bbox(self):
     exterior_np = self.exterior_np
     rows, cols = exterior_np[:, 0], exterior_np[:, 1]
     return Rectangle(top=round(min(rows).item()),
                      left=round(min(cols).item()),
                      bottom=round(max(rows).item()),
                      right=round(max(cols).item()))
Exemplo n.º 6
0
def detection_preds_to_sly_rects(
        idx_to_class, network_prediction: DetectionNetworkPrediction,
        img_shape, min_score_threshold, score_tag_meta) -> list:
    """
    Converts network detection results to Supervisely Labels with Rectangle geometry.

    Args:
        idx_to_class: Dict matching predicted boxes with appropriate ObjClass.
        network_prediction: Network predictions packed into DetectionNetworkPrediction instance.
        img_shape: Size(height, width) of image that was used for inference.
        min_score_threshold: All detections with less scores will be dropped.
        score_tag_meta: TagMeta instance for score tags.
    Returns:
        A list containing labels with detection rectangles.
    """
    labels = []
    thr_mask = np.squeeze(network_prediction.scores) > min_score_threshold
    for box, class_id, score in zip(
            np.squeeze(network_prediction.boxes)[thr_mask],
            np.squeeze(network_prediction.classes)[thr_mask],
            np.squeeze(network_prediction.scores)[thr_mask]):

        xmin = round(float(box[1] * img_shape[1]))
        ymin = round(float(box[0] * img_shape[0]))
        xmax = round(float(box[3] * img_shape[1]))
        ymax = round(float(box[2] * img_shape[0]))

        rect = Rectangle(top=ymin, left=xmin, bottom=ymax, right=xmax)
        class_obj = idx_to_class[int(class_id)]
        label = Label(geometry=rect, obj_class=class_obj)

        score_tag = Tag(score_tag_meta, value=round(float(score), 4))
        label = label.add_tag(score_tag)
        labels.append(label)
    return labels
Exemplo n.º 7
0
 def to_bbox(self):
     rows = [keypoint.location.row for keypoint in self.points]
     cols = [keypoint.location.col for keypoint in self.points]
     return Rectangle(top=round(min(rows)),
                      left=round(min(cols)),
                      bottom=round(max(rows)),
                      right=round(max(cols)))
Exemplo n.º 8
0
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]
Exemplo n.º 9
0
 def test_crop(self):
     crop_rect = Rectangle(25, 0, 200, 200)
     res_geoms = self.poly.crop(crop_rect)
     self.assertEqual(len(res_geoms), 1)
     crop = res_geoms[0]
     self.assertPolyEquals(crop,
                           [[10, 25], [20, 25], [20, 30], [30, 30], [30, 25], [35, 25], [30, 40], [10, 30]],
                           [])
Exemplo n.º 10
0
 def to_bbox(self):
     points_np = np.array([[self._points[p].row, self._points[p].col]
                           for face in self._faces for p in face.tolist()])
     rows, cols = points_np[:, 0], points_np[:, 1]
     return Rectangle(top=round(min(rows).item()),
                      left=round(min(cols).item()),
                      bottom=round(max(rows).item()),
                      right=round(max(cols).item()))
Exemplo n.º 11
0
 def to_bbox(self):
     '''
     The function to_bbox create Rectangle class object from current VectorGeometry class object
     :return: Rectangle class object
     '''
     exterior_np = self.exterior_np
     rows, cols = exterior_np[:, 0], exterior_np[:, 1]
     return Rectangle(top=round(min(rows).item()), left=round(min(cols).item()), bottom=round(max(rows).item()),
                      right=round(max(cols).item()))
Exemplo n.º 12
0
def _find_mask_tight_bbox(raw_mask: np.ndarray) -> Rectangle:
    rows = list(np.any(raw_mask, axis=1).tolist())  # Redundant conversion to list to help PyCharm static analysis.
    cols = list(np.any(raw_mask, axis=0).tolist())
    top_margin = rows.index(True)
    bottom_margin = rows[::-1].index(True)
    left_margin = cols.index(True)
    right_margin = cols[::-1].index(True)
    return Rectangle(top=top_margin, left=left_margin, bottom=len(rows) - 1 - bottom_margin,
                     right=len(cols) - 1 - right_margin)
Exemplo n.º 13
0
 def to_bbox(self):
     '''
     The function to_bbox create Rectangle class object from Point class object
     :return: Rectangle class object
     '''
     return Rectangle(top=self.row,
                      left=self.col,
                      bottom=self.row,
                      right=self.col)
Exemplo n.º 14
0
    def test_crop_by_border(self):
        exterior = [[10, 10], [40, 10], [40, 40], [10, 40]]
        interiors = [[[11, 11], [11, 20], [20, 11]], [[20, 20], [21, 20], [20, 21]]]
        poly = Polygon(exterior=row_col_list_to_points(exterior, flip_row_col_order=True),
                       interior=[row_col_list_to_points(interior, flip_row_col_order=True) for interior in interiors])

        crop_rect = Rectangle(0, 0, 100, 10)
        res_geoms = poly.crop(crop_rect)
        self.assertEqual(len(res_geoms), 0)
Exemplo n.º 15
0
 def to_bbox(self):
     '''
     The function to_bbox create Rectangle class object from current Cuboid class object
     :return: Rectangle class object
     '''
     points_np = np.array([[self._points[p].row, self._points[p].col]
                           for face in self._faces for p in face.tolist()])
     rows, cols = points_np[:, 0], points_np[:, 1]
     return Rectangle(top=round(min(rows).item()), left=round(min(cols).item()), bottom=round(max(rows).item()),
                      right=round(max(cols).item()))
Exemplo n.º 16
0
    def _calc_inner_crop(self):
        """
        Given a rectangle of self.src_imsize HxW that has been rotated by
        self.angle_degrees_ccw (in degrees), computes the location of the
        largest possible axis-aligned rectangle within the rotated rectangle.
        """

        # TODO This needs significant streamlinig.
        a_ccw = np.deg2rad(self.angle_degrees_ccw)
        quadrant = math.floor(a_ccw / (math.pi / 2)) & 3
        sign_alpha = a_ccw if ((quadrant & 1) == 0) else math.pi - a_ccw
        alpha = (sign_alpha % math.pi + math.pi) % math.pi

        h, w = self.src_imsize
        bb_w = w * math.cos(alpha) + h * math.sin(alpha)
        bb_h = w * math.sin(alpha) + h * math.cos(alpha)

        gamma = math.atan2(bb_w, bb_w) if (w < h) else math.atan2(bb_w, bb_w)

        delta = math.pi - alpha - gamma

        length = h if (w < h) else w

        d = length * math.cos(alpha)
        a = d * math.sin(alpha) / math.sin(delta)

        y = a * math.cos(gamma)
        x = y * math.tan(gamma)

        largest_w, largest_h = bb_w - 2 * x, bb_h - 2 * y

        new_h, new_w = self.new_imsize
        left = round((new_w - largest_w) * 0.5)
        right = round((new_w + largest_w) * 0.5)
        top = round((new_h - largest_h) * 0.5)
        bottom = round((new_h + largest_h) * 0.5)
        some_inner_crop = Rectangle(top, left, bottom, right)
        new_img_bbox = Rectangle(0, 0, self.new_imsize[0] - 1,
                                 self.new_imsize[1] - 1)
        self.inner_crop = new_img_bbox.crop(some_inner_crop)[0]
Exemplo n.º 17
0
    def test_complex_crop(self):
        # Crop generate GeometryCollection here
        exterior = [[0, 0], [0, 3], [5, 8], [5, 9], [5, 10], [0, 15], [10, 20], [0, 25], [20, 25], [20, 0]]
        interiors = [[[2, 2], [4, 4], [4, 2]]]

        poly = Polygon(exterior=row_col_list_to_points(exterior, flip_row_col_order=True),
                       interior=[row_col_list_to_points(interior, flip_row_col_order=True) for interior in interiors])

        crop_rect = Rectangle(0, 0, 30, 5)
        res_geoms = poly.crop(crop_rect)
        self.assertEqual(len(res_geoms), 3)
        self.assertPolyEquals(res_geoms[0],
                              [[0, 0], [5, 0], [5, 8], [0, 3]], interiors)
Exemplo n.º 18
0
 def test_crop(self):  # @TODO: mb delete compress while cropping
     crop_rect = Rectangle(0, 0, 8, 8)
     res_geoms = self.bitmap.crop(crop_rect)
     self.assertEqual(len(res_geoms), 1)
     res_bitmap = res_geoms[0]
     res_mask = np.array([[0, 0, 1, 0],
                          [0, 1, 1, 1],
                          [1, 0, 1, 0],
                          [0, 0, 1, 0],
                          [0, 0, 1, 0],
                          [0, 0, 1, 0],
                          [0, 0, 1, 0]], dtype=np.bool)
     self.assertBitmapEquals(res_bitmap, 0, 5, res_mask)
Exemplo n.º 19
0
def add_background(ann: Annotation, bg_class: ObjClass) -> Annotation:
    """
    Adds background rectangle (size equals to image size) to annotation.

    Args:
        ann: Input annotation.
        bg_class: ObjClass instance for background class label.
    Returns:
        Annotation with added background rectangle.
    """
    img_size = ann.img_size
    rect = Rectangle(0, 0, img_size[0] - 1, img_size[1] - 1)
    new_label = Label(rect, bg_class)
    return ann.add_label(new_label)
Exemplo n.º 20
0
    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
Exemplo n.º 21
0
    def test_draw(self):
        rect = Rectangle(1, 1, 3, 3)

        bitmap_1 = np.zeros((5, 5), dtype=np.uint8)
        rect.draw_contour(bitmap_1, 1)
        expected_mask_1 = np.array([[0, 0, 0, 0, 0],
                                    [0, 1, 1, 1, 0],
                                    [0, 1, 0, 1, 0],
                                    [0, 1, 1, 1, 0],
                                    [0, 0, 0, 0, 0]], dtype=np.uint8)
        self.assertTrue(np.array_equal(bitmap_1, expected_mask_1))

        bitmap_2 = np.zeros((5, 5), dtype=np.uint8)
        rect.draw(bitmap_2, 1)
        expected_mask_2 = np.array([[0, 0, 0, 0, 0],
                                    [0, 1, 1, 1, 0],
                                    [0, 1, 1, 1, 0],
                                    [0, 1, 1, 1, 0],
                                    [0, 0, 0, 0, 0]], dtype=np.uint8)
        self.assertTrue(np.array_equal(bitmap_2, expected_mask_2))
Exemplo n.º 22
0
    def from_imgaug(cls,
                    img,
                    ia_boxes=None,
                    ia_masks=None,
                    index_to_class=None,
                    meta: ProjectMeta = None):
        if ((ia_boxes is not None) or (ia_masks is not None)) and meta is None:
            raise ValueError("Project meta has to be provided")

        labels = []
        if ia_boxes is not None:
            for ia_box in ia_boxes:
                obj_class = meta.get_obj_class(ia_box.label)
                if obj_class is None:
                    raise KeyError(
                        "Class {!r} not found in project meta".format(
                            ia_box.label))
                lbl = Label(
                    Rectangle(top=ia_box.y1,
                              left=ia_box.x1,
                              bottom=ia_box.y2,
                              right=ia_box.x2), obj_class)
                labels.append(lbl)

        if ia_masks is not None:
            if index_to_class is None:
                raise ValueError(
                    "mapping from index to class name is needed to transform masks to SLY format"
                )
            class_mask = ia_masks.get_arr()
            # mask = white_mask == 255
            (unique, counts) = np.unique(class_mask, return_counts=True)
            for index, count in zip(unique, counts):
                if index == 0:
                    continue
                mask = class_mask == index
                bitmap = Bitmap(data=mask[:, :, 0])
                restore_class = meta.get_obj_class(index_to_class[index])
                labels.append(Label(geometry=bitmap, obj_class=restore_class))

        return cls(img_size=img.shape[:2], labels=labels)
Exemplo n.º 23
0
    def setUp(self):
        self._obj_class_gt = ObjClass(name='a', geometry_type=Rectangle)
        self._obj_class_pred = ObjClass(name='b', geometry_type=Rectangle)
        self._confidence_tag_meta = TagMeta(name='confidence', value_type=TagValueType.ANY_NUMBER)
        self._meta = ProjectMeta(
            obj_classes=ObjClassCollection([self._obj_class_gt, self._obj_class_pred]),
            tag_metas=TagMetaCollection([self._confidence_tag_meta]))

        # Will match self._pred_obj_1
        self._gt_obj_1 = Label(obj_class=self._obj_class_gt, geometry=Rectangle(0, 0, 10, 10))

        # Will match self._pred_obj_3
        self._gt_obj_2 = Label(obj_class=self._obj_class_gt, geometry=Rectangle(13, 13, 15, 15))

        # Will be a false negative
        self._gt_obj_3 = Label(obj_class=self._obj_class_gt, geometry=Rectangle(43, 43, 45, 45))

        # Will match self._gt_obj_1
        self._pred_obj_1 = Label(
            obj_class=self._obj_class_pred,
            geometry=Rectangle(0, 0, 9, 9),
            tags=TagCollection([Tag(meta=self._confidence_tag_meta, value=0.7)]))

        # Will be a false positive (self._pred_obj_1 has higher IoU).
        self._pred_obj_2 = Label(
            obj_class=self._obj_class_pred,
            geometry=Rectangle(0, 0, 8, 8),
            tags=TagCollection([Tag(meta=self._confidence_tag_meta, value=0.6)]))

        # Will match self._gt_obj_2
        self._pred_obj_3 = Label(
            obj_class=self._obj_class_pred,
            geometry=Rectangle(13, 13, 15, 15),
            tags=TagCollection([Tag(meta=self._confidence_tag_meta, value=0.1)]))

        # More false positives.
        self._pred_objs_fp = [
            Label(obj_class=self._obj_class_pred,
                  geometry=Rectangle(20, 20, 30, 30),
                  tags=TagCollection([Tag(meta=self._confidence_tag_meta, value=v / 100)]))
            for v in range(15, 85, 10)]

        self._metric_calculator = MAPMetric(class_mapping={'a': 'b'}, iou_threshold=0.5)
Exemplo n.º 24
0
 def test_crop(self):
     crop_rect = Rectangle(0, 0, 100, 100)
     res_geoms = self.point.crop(crop_rect)
     self.assertEqual(len(res_geoms), 1)
     res_point = res_geoms[0]
     self.assertPointEquals(res_point, self.point.row, self.point.col)
Exemplo n.º 25
0
 def to_bbox(self):
     return Rectangle(top=self.row,
                      left=self.col,
                      bottom=self.row,
                      right=self.col)
Exemplo n.º 26
0
 def test_empty_crop(self):
     crop_rect = Rectangle(100, 100, 200, 200)
     res_geoms = self.poly.crop(crop_rect)
     self.assertEqual(len(res_geoms), 0)
Exemplo n.º 27
0
 def test_empty_crop(self):
     crop_rect = Rectangle(top=0, left=0, bottom=10, right=3)
     res_geoms = self.bitmap.crop(crop_rect)
     self.assertEqual(len(res_geoms), 0)
Exemplo n.º 28
0
 def test_empty_crop(self):
     crop_rect = Rectangle(0, 0, 4, 4)
     res_geoms = self.bitmap.crop(crop_rect)
     self.assertEqual(len(res_geoms), 0)
Exemplo n.º 29
0
 def test_relative_crop(self):
     crop_rect = Rectangle(5, 5, 100, 100)
     res_geoms = self.point.relative_crop(crop_rect)
     self.assertEqual(len(res_geoms), 1)
     res_point = res_geoms[0]
     self.assertPointEquals(res_point, 5, 0)
Exemplo n.º 30
0
 def test_relative_crop(self):
     crop_rect = Rectangle(25, 0, 200, 200)
     res_geoms = self.poly.relative_crop(crop_rect)
     self.assertEqual(len(res_geoms), 1)
     crop = res_geoms[0]
     self.assertPolyEquals(crop, [[10, 0], [20, 0], [20, 5], [30, 5], [30, 0], [35, 0], [30, 15], [10, 5]], [])