예제 #1
0
    def __call__(self, results):
        """Call function to rotate image, semantic segmentation maps.

        Args:
            results (dict): Result dict from loading pipeline.

        Returns:
            dict: Rotated results.
        """

        rotate = True if np.random.rand() < self.prob else False
        degree = np.random.uniform(min(*self.degree), max(*self.degree))
        if rotate:
            # rotate image
            results['img'] = mmcv.imrotate(results['img'],
                                           angle=degree,
                                           border_value=self.pal_val,
                                           center=self.center,
                                           auto_bound=self.auto_bound)

            # rotate segs
            for key in results.get('seg_fields', []):
                results[key] = mmcv.imrotate(results[key],
                                             angle=degree,
                                             border_value=self.seg_pad_val,
                                             center=self.center,
                                             auto_bound=self.auto_bound,
                                             interpolation='nearest')
        return results
예제 #2
0
    def __call__(self, results):
        """Call function to randomly rotate images, semantic segmentation maps.

        Args:
            results (dict): Result dict from loading pipeline.

        Returns:
            dict: Randomly rotated results.
        """

        if 'rotation' not in results:
            rotation = True if np.random.rand(
            ) < self.rotation_ratio else False
            results['rotation'] = rotation
        if results['rotation']:
            img = results['img']
            rotation_degree = self.get_rotation_degree()

            # rotate the image and semantic segmentation map
            img = mmcv.imrotate(img, rotation_degree)
            results['img'] = img
            for key in results.get('seg_fields', []):
                results[key] = self.rotate(results[key],
                                           rotation_degree,
                                           borderValue=255,
                                           interpolation='nearest')
        return results
예제 #3
0
    def rotate(self, out_shape, angle, center=None, scale=1.0, fill_val=0):
        """Rotate the BitmapMasks.

        Args:
            out_shape (tuple[int]): Shape for output mask, format (h, w).
            angle (int | float): Rotation angle in degrees. Positive values
                mean counter-clockwise rotation.
            center (tuple[float], optional): Center point (w, h) of the
                rotation in source image. If not specified, the center of
                the image will be used.
            scale (int | float): Isotropic scale factor.
            fill_val (int | float): Border value. Default 0 for masks.

        Returns:
            BitmapMasks: Rotated BitmapMasks.
        """
        if len(self.masks) == 0:
            rotated_masks = np.empty((0, *out_shape), dtype=self.masks.dtype)
        else:
            rotated_masks = mmcv.imrotate(
                self.masks.transpose((1, 2, 0)),
                angle,
                center=center,
                scale=scale,
                border_value=fill_val)
            if rotated_masks.ndim == 2:
                # case when only one mask, (h, w)
                rotated_masks = rotated_masks[:, :, None]  # (h, w, 1)
            rotated_masks = rotated_masks.transpose(
                (2, 0, 1)).astype(self.masks.dtype)
        return BitmapMasks(rotated_masks, *out_shape)
예제 #4
0
    def __call__(self, results):
        angle = random.uniform(self.degrees[0], self.degrees[1])

        for k in self.keys:
            results[k] = mmcv.imrotate(results[k], angle)
            if results[k].ndim == 2:
                results[k] = np.expand_dims(results[k], axis=2)
        results['degrees'] = self.degrees

        return results
예제 #5
0
 def _rotate_seg(self,
                 results,
                 angle,
                 center=None,
                 scale=1.0,
                 fill_val=255):
     """Rotate the segmentation map."""
     for key in results.get('seg_fields', []):
         seg = results[key].copy()
         results[key] = mmcv.imrotate(
             seg, angle, center, scale,
             border_value=fill_val).astype(seg.dtype)
예제 #6
0
 def __call__(self, results):
     if np.random.rand() > self.prob:
         return results
     angle = random_negative(self.angle, self.random_negative_prob)
     for key in results.get('img_fields', ['img']):
         img = results[key]
         img_rotated = mmcv.imrotate(img,
                                     angle,
                                     center=self.center,
                                     scale=self.scale,
                                     border_value=self.pad_val,
                                     interpolation=self.interpolation)
         results[key] = img_rotated.astype(img.dtype)
     return results
예제 #7
0
    def test_imrotate(self):
        img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).astype(np.uint8)
        assert_array_equal(mmcv.imrotate(img, 0), img)
        img_r = np.array([[7, 4, 1], [8, 5, 2], [9, 6, 3]])
        assert_array_equal(mmcv.imrotate(img, 90), img_r)
        img_r = np.array([[3, 6, 9], [2, 5, 8], [1, 4, 7]])
        assert_array_equal(mmcv.imrotate(img, -90), img_r)

        img = np.array([[1, 2, 3, 4], [5, 6, 7, 8]]).astype(np.uint8)
        img_r = np.array([[0, 6, 2, 0], [0, 7, 3, 0]])
        assert_array_equal(mmcv.imrotate(img, 90), img_r)
        img_r = np.array([[1, 0, 0, 0], [2, 0, 0, 0]])
        assert_array_equal(mmcv.imrotate(img, 90, center=(0, 0)), img_r)
        img_r = np.array([[255, 6, 2, 255], [255, 7, 3, 255]])
        assert_array_equal(mmcv.imrotate(img, 90, border_value=255), img_r)
        img_r = np.array([[5, 1], [6, 2], [7, 3], [8, 4]])
        assert_array_equal(mmcv.imrotate(img, 90, auto_bound=True), img_r)

        with pytest.raises(ValueError):
            mmcv.imrotate(img, 90, center=(0, 0), auto_bound=True)
예제 #8
0
 def _rotate_img(self, results, angle, center=None, scale=1.0):
     """Rotate the image.
     Args:
         results (dict): Result dict from loading pipeline.
         angle (float): Rotation angle in degrees, positive values
             mean clockwise rotation. Same in ``mmcv.imrotate``.
         center (tuple[float], optional): Center point (w, h) of the
             rotation. Same in ``mmcv.imrotate``.
         scale (int | float): Isotropic scale factor. Same in
             ``mmcv.imrotate``.
     """
     for key in results.get('img_fields', ['img']):
         img = results[key].copy()
         img_rotated = mmcv.imrotate(
             img, angle, center, scale, border_value=self.img_fill_val)
         results[key] = img_rotated.astype(img.dtype)
 def __call__(self, results):
     if np.random.rand() > self.probablity:
         return results
     # if 'flip' not in results:
     #     flip = True if np.random.rand() < self.flip_ratio else False
     #     results['flip'] = flip
     # if results['flip']:
     else:
         angle = random.randint(1, 3) * 90
         results['img'] = mmcv.imrotate(results['img'], angle)
         h, w = results['img_shape'][:2]
         center = (w - 1) * 0.5, (h - 1) * 0.5
         mat = cv2.getRotationMatrix2D(center=center,
                                       angle=angle,
                                       scale=1.0)
         for key in results.get('bbox_fields', []):
             results[key] = self.bbox_rotate(results[key],
                                             results['img_shape'], mat)
         return results
예제 #10
0
 def __call__(self, results):
     if 'rotate' not in results:
         rotate = True if np.random.rand() < self.rotate_ratio else False
         results['rotate'] = rotate
     if results['rotate']:
         # rotate image
         image = results['img']
         h, w = image.shape[:2]
         rotated_image = mmcv.imrotate(image, angle=self.angle)
         results['img'] = rotated_image
         # rotate bboxes
         for key in results.get('bbox_fields', []):
             bboxes = results[key]
             corners = self.get_corners(bboxes)
             corners = np.hstack((corners, bboxes[:, 4:]))
             corners[:, :8] = self.bbox_rotate(corners[:, :8],
                                               results['img_shape'])
             new_bboxes = self.get_enclosing_box(corners)
             # new_bboxes = self.bbox_clip(new_bboxes, [0, 0, w, h])
             results[key] = new_bboxes
     return results
예제 #11
0
def main():

    bgr_img = mmcv.imread(image_path)

    h, w, _ = bgr_img.shape
    # convert color
    rgb_img = mmcv.bgr2rgb(bgr_img)

    # resize
    resize_img = mmcv.imresize(rgb_img, size=(256, 256))

    # rotate
    rotate_img = mmcv.imrotate(rgb_img, angle=45)

    # flip
    flip_img = mmcv.imflip(rgb_img, direction='horizontal')

    # crop
    if h <= w:
        y_min, y_max = 0, h
        x_min = int((w - h) / 2)
        x_max = x_min + h
    else:
        x_min, x_max = 0, h
        y_min = int((h - w) / 2)
        y_max = y_min + w
    bbox = np.array([x_min, y_min, x_max, y_max])
    crop_img = mmcv.imcrop(rgb_img, bbox)

    # padding
    max_size = max(h, w)
    pad_img = mmcv.impad(rgb_img,
                         shape=(max_size, max_size),
                         padding_mode='constant')

    mmcv.imshow(mmcv.rgb2bgr(pad_img))
예제 #12
0
    def __call__(self,
                 img_group,
                 scale,
                 crop_history=None,
                 flip=False,
                 rotate=None,
                 keep_ratio=True,
                 dropout_prob=None,
                 div_255=False,
                 transpose=True,
                 stack=True):
        # 1. rescale
        if keep_ratio:
            tuple_list = [
                mmcv.imrescale(img, scale, return_scale=True)
                for img in img_group
            ]
            img_group, scale_factors = list(zip(*tuple_list))
            scale_factor = scale_factors[0]
        else:
            tuple_list = [
                mmcv.imresize(img, scale, return_scale=True)
                for img in img_group
            ]
            img_group, w_scales, h_scales = list(zip(*tuple_list))
            scale_factor = np.array(
                [w_scales[0], h_scales[0], w_scales[0], h_scales[0]],
                dtype=np.float32)

        # 2. rotate
        if rotate is not None:
            img_group = [mmcv.imrotate(img, rotate) for img in img_group]

        # 3. crop (if necessary)
        if crop_history is not None:
            self.op_crop = GroupCrop(crop_history)
        if self.op_crop is not None:
            img_group, crop_quadruple = self.op_crop(img_group)
        else:
            crop_quadruple = None

        img_shape = img_group[0].shape

        # 4. flip
        if flip:
            img_group = [mmcv.imflip(img) for img in img_group]

        # 5a. extra augmentation
        if self.extra_augm is not None:
            img_group = self.extra_augm(img_group)

        # 5b. coarse dropout
        if self.dropout_scale is not None and dropout_prob is not None and dropout_prob > 0.0:
            dropout_mask = self._coarse_dropout_mask(img_group[0].shape,
                                                     dropout_prob,
                                                     self.dropout_scale)
            img_group = [img * dropout_mask for img in img_group]

        # 6a. div_255
        if div_255:
            img_group = [
                mmcv.imnormalize(img, 0, 255, False) for img in img_group
            ]

        # 6b. normalize
        if self.mean is not None and self.std is not None:
            img_group = [
                mmcv.imnormalize(img, self.mean, self.std, self.to_rgb)
                for img in img_group
            ]
        elif self.to_rgb:
            img_group = [mmcv.bgr2rgb(img) for img in img_group]

        # 7. pad
        if self.size_divisor is not None:
            img_group = [
                mmcv.impad_to_multiple(img, self.size_divisor)
                for img in img_group
            ]
            pad_shape = img_group[0].shape
        else:
            pad_shape = img_shape

        # 8. transpose
        if transpose:
            img_group = [img.transpose((2, 0, 1)) for img in img_group]

        # 9. stack into numpy.array
        if stack:
            img_group = np.stack(img_group, axis=0)

        return img_group, img_shape, pad_shape, scale_factor, crop_quadruple
예제 #13
0
mmcv.imresize(img, (1000, 600), return_scale=True)

# resize to the same size of another image
mmcv.imresize_like(img, dst_img, return_scale=False)

# resize by a ratio
mmcv.imrescale(img, 0.5)

# resize so that the max edge no longer than 1000, short edge no longer than 800
# without changing the aspect ratio
mmcv.imrescale(img, (1000, 800))


# =============Rotate==============
# rotate the image clockwise by 30 degrees.
img_ = mmcv.imrotate(img, 30)

# rotate the image counterclockwise by 90 degrees.
img_ = mmcv.imrotate(img, -90)

# rotate the image clockwise by 30 degrees, and rescale it by 1.5x at the same time.
img_ = mmcv.imrotate(img, 30, scale=1.5)

# rotate the image clockwise by 30 degrees, with (100, 100) as the center.
img_ = mmcv.imrotate(img, 30, center=(100, 100))

# rotate the image clockwise by 30 degrees, and extend the image size.
img_ = mmcv.imrotate(img, 30, auto_bound=True)


예제 #14
0
    def __call__(self, results):
        img, gt_bboxes, gt_labels = [
            results[k] for k in ('img', 'gt_bboxes', 'gt_labels')
        ]
        img_h, img_w, _ = results['img_shape']
        if img_h > 1000:
            gt_lst = self.all_gt_bboxes()

            if np.random.rand() < self.keep_ratio:
                gt_bboxes_ = gt_bboxes.tolist()
                gt_labels_ = gt_labels.tolist()
            else:
                ind = np.random.randint(len(self.normal_imgs))
                normal_path = self.normal_imgs[ind]
                normal_img = mmcv.imread(normal_path)
                normal_img = mmcv.imresize_like(normal_img, img)
                img = normal_img
                gt_bboxes_, gt_labels_ = [], []

            defects = random.choices(gt_lst, k=self.max_per_img)
            defects = sorted(defects,
                             key=(lambda x: x[-1] * x[-2]),
                             reverse=True)
            for det in defects:
                defect_img = cv2.imread(os.path.join(self.img_path, det[0]))
                label = det[1]
                x, y, w, h = list(map(int, det[2:]))
                defect = defect_img[y:y + h, x:x + w, :]
                mode = np.random.randint(3)
                # scale
                if mode == 0:
                    defect = self.bbox_scale(defect)
                    h, w = defect.shape[:2]
                # rotate
                elif mode == 1:
                    ctx = x + w * 0.5
                    cty = y + h * 0.5
                    corners = np.hstack(
                        (x, y, x + w, y, x, y + h, x + w, y + h))
                    h, w, angle = self.bbox_rotate(corners, h, w)
                    rotated_img = mmcv.imrotate(defect_img,
                                                -angle,
                                                center=(ctx, cty))
                    x1 = int(ctx - w * 0.5)
                    y1 = int(cty - h * 0.5)
                    x2 = x1 + w
                    y2 = y1 + h
                    defect = rotated_img[y1:y2, x1:x2, :]
                try:
                    xmin = np.random.randint(self.left_border,
                                             img_w - self.right_border - w)
                    ymin = np.random.randint(self.top_border,
                                             img_h - self.bottom_border - h)
                    xmax = xmin + w
                    ymax = ymin + h
                    img[ymin:ymax, xmin:xmax, :] = cv2.addWeighted(
                        defect, 1, img[ymin:ymax, xmin:xmax, :], 0, 0)
                    gt_bboxes_.append([xmin, ymin, xmax, ymax])
                    gt_labels_.append(label)
                except:
                    continue

            results['img'] = img
            results['gt_bboxes'] = np.array(gt_bboxes_, dtype=np.float32)
            results['gt_labels'] = np.array(gt_labels_, dtype=np.int64)
        return results
예제 #15
0
def rotate_lines_img(lines, img, angle,  obj_rep, debug_rotation=0):
  '''
  The img sizes of input  and output are the same.
  angle in degree
  '''
  assert obj_rep == 'XYXYSin2'
  assert img.ndim == 3
  assert lines.ndim == 2
  assert lines.shape[1] == 5
  assert img.shape[2] == 4

  img_shape = img.shape[:2]

  if debug_rotation:
    add_cross = 1
    if add_cross:
      img[:,:,1:] = np.abs(img[:,:,1:])*255
      lines = add_cross_in_lines(lines, img_shape)
    #_show_lines_ls_points_ls(img[:,:,0], [lines])
    #_show_lines_ls_points_ls(img[:,:,1:], [lines])
    #_show_lines_ls_points_ls(img[:,:,:3], [lines])
    pass

  n = lines.shape[0]
  if n == 0:
    return lines, img
  lines_2endpts = OBJ_REPS_PARSE.encode_obj(lines, obj_rep, 'RoLine2D_2p').reshape(n,2,2)
  #lines_2endpts = decode_line_rep(lines, obj_rep).reshape(n,2,2)

  h, w = img_shape
  assert h%2 == 0
  assert w%2 == 0
  center = ((w - 1) * 0.5, (h - 1) * 0.5)
  scale = 1.0
  matrix = cv2.getRotationMatrix2D(center, -angle, scale)

  ones = np.ones([n,2,1], dtype=lines.dtype)
  tmp = np.concatenate([lines_2endpts, ones], axis=2)
  lines_2pts_r = np.matmul( tmp, matrix.T )

  # (1) rotate the lines
  lines_rotated = OBJ_REPS_PARSE.encode_obj(lines_2pts_r.reshape(-1,4), 'RoLine2D_2p', obj_rep)
  #lines_rotated = encode_line_rep(lines_2pts_r, obj_rep)
  #_show_lines_ls_points_ls(img[:,:,0], [lines_rotated])

  # (3) scale the lines to fit the image size
  # Move before scaling can increase the scale ratio
  x_min_ =  lines_rotated[:,[0,2]].min()
  x_max_ =  lines_rotated[:,[0,2]].max()
  y_min_ =  lines_rotated[:,[1,3]].min()
  y_max_ =  lines_rotated[:,[1,3]].max()

  border_pad = 4
  gap_x0 = 0 - x_min_
  gap_y0 = 0 - y_min_
  gap_x1 = x_max_ - (w-1)
  gap_y1 = y_max_ - (h-1)
  gap_x = np.ceil(np.array([gap_x0, gap_x1, 0]).max())
  gap_y = np.ceil(np.array([gap_y0, gap_y1, 0]).max())
  scale_x = (w-border_pad*2) / (w+gap_x*2.0)
  scale_y = (h-border_pad*2) / (h+gap_y*2.0)
  scale = min(scale_x, scale_y)
  scale = np.floor(scale * 100)/100.0

  lines_rotated[:,:4] = ((lines_rotated[:,:4].reshape(-1,2) - center) * scale + center).reshape(-1,4)

  # (4) rotate the image (do not scale at this stage)
  if debug_rotation:
    if add_cross:
      add_cross_in_img(img)
    #_show_lines_ls_points_ls(img[:,:,:3], [lines])


  img_big = np.pad(img, ( (h//2,h//2), (w//2,w//2), (0,0) ), 'constant', constant_values=0)
  img_r = mmcv.imrotate(img_big, angle, scale=scale)

  # (5) Move the image
  new_img = np.zeros([h,w], dtype=lines.dtype)
  h1,w1 = img_r.shape[:2]
  region = np.array([
    w1/2-w/2,
    h1/2-h/2,
    w1/2+w/2-1,
    h1/2+h/2-1,
  ])
  region_int = region.astype(np.int32)
  new_img = mmcv.imcrop(img_r, region_int)
  assert new_img.shape[:2] == img_shape

  # rotate the surface normal
  new_img[:,:,[1,2]] = np.matmul( new_img[:,:,[1,2]], matrix[:,:2].T )


  lines_rotated = lines_rotated.astype(np.float32)
  new_img = new_img.astype(np.float32)
  assert lines_rotated[:,:4].min() > 0
  if debug_rotation:
    print(f'\nscale: {scale}')
    #_show_lines_ls_points_ls(img[:,:,:3], [lines])
    _show_lines_ls_points_ls(new_img[:,:,0], [lines_rotated])

    #_show_img_with_norm(img)
    #_show_img_with_norm(new_img)
    if add_cross:
      lines_rotated = lines_rotated[:-4]
    pass

  return  lines_rotated, new_img, scale
예제 #16
0
def rotate_lines_img(lines, img, angle, obj_rep, check_by_cross=False):
    assert img.ndim == 3
    assert lines.ndim == 2
    assert lines.shape[1] == 5

    img_shape = img.shape[:2]
    if check_by_cross:
        lines = add_cross_in_lines(lines, img_shape)

    n = lines.shape[0]
    if n == 0:
        return lines, img
    lines_2endpts = decode_line_rep(lines, obj_rep).reshape(n, 2, 2)

    h, w = img_shape
    assert h % 2 == 0
    assert w % 2 == 0
    center = ((w - 1) * 0.5, (h - 1) * 0.5)
    scale = 1.0
    matrix = cv2.getRotationMatrix2D(center, -angle, scale)

    ones = np.ones([n, 2, 1], dtype=lines.dtype)
    tmp = np.concatenate([lines_2endpts, ones], axis=2)
    lines_2pts_r = np.matmul(tmp, matrix.T)

    # (1) rotate the lines
    lines_rotated = encode_line_rep(lines_2pts_r, obj_rep)

    # (2) move the lines to center
    x_min = lines_rotated[:, [0, 2]].min()
    x_max = lines_rotated[:, [0, 2]].max()
    y_min = lines_rotated[:, [1, 3]].min()
    y_max = lines_rotated[:, [1, 3]].max()
    x_cen = (x_min + x_max) / 2
    y_cen = (y_min + y_max) / 2

    x_offset = np.floor(x_cen - (w - 1) / 2) * 1
    y_offset = np.floor(y_cen - (h - 1) / 2) * 1

    lines_rotated[:, [0, 2]] -= x_offset
    lines_rotated[:, [1, 3]] -= y_offset

    # (3) scale the lines to fit the image size
    # Move before scaling can increase the scale ratio
    x_min_ = lines_rotated[:, [0, 2]].min()
    x_max_ = lines_rotated[:, [0, 2]].max()
    y_min_ = lines_rotated[:, [1, 3]].min()
    y_max_ = lines_rotated[:, [1, 3]].max()

    gap_x0 = 0 - x_min_
    gap_y0 = 0 - y_min_
    gap_x1 = x_max_ - (w - 1)
    gap_y1 = y_max_ - (h - 1)
    gap_x = np.ceil(np.array([gap_x0, gap_x1, 0]).max())
    gap_y = np.ceil(np.array([gap_y0, gap_y1, 0]).max())
    scale_x = w / (w + gap_x * 2.0)
    scale_y = h / (h + gap_y * 2.0)
    scale = min(scale_x, scale_y) * 0.97
    scale = np.floor(scale * 100) / 100.0
    if scale < 1:
        scale = scale - 0.03
    #print(f'scale: {scale}')

    center = np.repeat(center, 2)
    lines_rotated[:, :4] = (lines_rotated[:, :4] - center) * scale + center

    # (4) rotate the image (do not scale at this stage)
    if check_by_cross:
        add_cross_in_img(img)

    img_big = np.zeros([h * 2, w * 2, img.shape[2]], dtype=lines.dtype)
    img_big[int(h / 2):int(h / 2 * 3), int(w / 2):int(w / 2 * 3)] = img
    img_r = mmcv.imrotate(img_big, angle, scale=scale)

    # (5) Move the image
    new_img = np.zeros([h, w], dtype=lines.dtype)
    h1, w1 = img_r.shape[:2]
    region = np.array([(h1 - h) / 2 + x_offset * scale,
                       (w1 - w) / 2 + y_offset * scale,
                       (h1 - h) / 2 + h - 1 + x_offset * scale,
                       (w1 - w) / 2 + w - 1 + y_offset * scale])
    region_int = region.astype(np.int32)
    new_img = mmcv.imcrop(img_r, region_int)
    assert new_img.shape[:2] == img_shape

    # rotate the surface normal
    new_img[:, :, [1, 2]] = np.matmul(new_img[:, :, [1, 2]], matrix[:, :2].T)

    #_show_img_with_norm(img)
    #_show_img_with_norm(new_img)

    lines_rotated = lines_rotated.astype(np.float32)
    new_img = new_img.astype(np.float32)
    #_show_lines_ls_points_ls(img[:,:,:3]*255, lines)
    #_show_lines_ls_points_ls(new_img[:,:,:3], lines_rotated)
    return lines_rotated, new_img
예제 #17
0
파일: rotation.py 프로젝트: whughw/wwtool
import numpy as np
import wwtool
import mmcv

if __name__ == '__main__':
    thetaobbs = [[400, 400, 300, 150, 45 * np.pi / 180],
                 [600, 600, 300, 200, 135 * np.pi / 180]]
    pointobbs = [wwtool.thetaobb2pointobb(thetaobb) for thetaobb in thetaobbs]

    img = wwtool.generate_image(1024, 1024)
    img_origin = img.copy()
    wwtool.imshow_rbboxes(img, thetaobbs, win_name='origin')

    rotation_angle = 45
    rotation_anchor = [img.shape[0] // 2, img.shape[1] // 2]

    rotated_img = mmcv.imrotate(img_origin, rotation_angle)

    rotated_pointobbs = [
        wwtool.rotate_pointobb(pointobb, rotation_angle * np.pi / 180,
                               rotation_anchor) for pointobb in pointobbs
    ]

    rotated_thetaobbs = [
        wwtool.pointobb2thetaobb(rotated_pointobb)
        for rotated_pointobb in rotated_pointobbs
    ]
    wwtool.imshow_rbboxes(rotated_img, rotated_thetaobbs, win_name='rotated')