From 3463af2a9013bb9327ff0229314eb1a7f9d13e63 Mon Sep 17 00:00:00 2001 From: Yue Zhou <592267829@qq.com> Date: Sat, 28 Sep 2024 19:53:36 +0800 Subject: [PATCH] Revert "[Feature] Full angle range (#1061)" This reverts commit 95123b9340469cea721dd2cdf840dbd40a4708cd. --- mmrotate/core/bbox/coder/angle_coder.py | 12 +- .../bbox/coder/delta_xywha_hbbox_coder.py | 4 +- .../bbox/coder/delta_xywha_rbbox_coder.py | 4 +- mmrotate/core/bbox/transforms.py | 115 ------------------ mmrotate/datasets/pipelines/transforms.py | 3 +- tests/test_utils/test_transformer.py | 20 --- 6 files changed, 8 insertions(+), 150 deletions(-) diff --git a/mmrotate/core/bbox/coder/angle_coder.py b/mmrotate/core/bbox/coder/angle_coder.py index 760065d1b..b84000a5e 100644 --- a/mmrotate/core/bbox/coder/angle_coder.py +++ b/mmrotate/core/bbox/coder/angle_coder.py @@ -27,16 +27,10 @@ class CSLCoder(BaseBBoxCoder): def __init__(self, angle_version, omega=1, window='gaussian', radius=6): super().__init__() self.angle_version = angle_version - assert angle_version in ['oc', 'le90', 'le135', 'full360'] + assert angle_version in ['oc', 'le90', 'le135'] assert window in ['gaussian', 'triangle', 'rect', 'pulse'] - self.angle_range = 90 if angle_version == 'oc' else \ - (360 if angle_version == 'full360' else 180) - self.angle_offset_dict = { - 'oc': 0, - 'le90': 90, - 'le135': 45, - 'full360': 180 - } + self.angle_range = 90 if angle_version == 'oc' else 180 + self.angle_offset_dict = {'oc': 0, 'le90': 90, 'le135': 45} self.angle_offset = self.angle_offset_dict[angle_version] self.omega = omega self.window = window diff --git a/mmrotate/core/bbox/coder/delta_xywha_hbbox_coder.py b/mmrotate/core/bbox/coder/delta_xywha_hbbox_coder.py index 09c692e89..0d99a4f22 100644 --- a/mmrotate/core/bbox/coder/delta_xywha_hbbox_coder.py +++ b/mmrotate/core/bbox/coder/delta_xywha_hbbox_coder.py @@ -68,7 +68,7 @@ def encode(self, bboxes, gt_bboxes): assert bboxes.size(0) == gt_bboxes.size(0) assert bboxes.size(-1) == 4 assert gt_bboxes.size(-1) == 5 - if self.angle_range in ['oc', 'le135', 'le90', 'full360']: + if self.angle_range in ['oc', 'le135', 'le90']: return bbox2delta(bboxes, gt_bboxes, self.means, self.stds, self.angle_range, self.norm_factor, self.edge_swap) @@ -104,7 +104,7 @@ def decode(self, assert pred_bboxes.size(1) == bboxes.size(1) assert bboxes.size(-1) == 4 assert pred_bboxes.size(-1) == 5 - if self.angle_range in ['oc', 'le135', 'le90', 'full360']: + if self.angle_range in ['oc', 'le135', 'le90']: return delta2bbox(bboxes, pred_bboxes, self.means, self.stds, wh_ratio_clip, self.add_ctr_clamp, self.ctr_clamp, self.angle_range, diff --git a/mmrotate/core/bbox/coder/delta_xywha_rbbox_coder.py b/mmrotate/core/bbox/coder/delta_xywha_rbbox_coder.py index 1b2216eb3..e14ced676 100644 --- a/mmrotate/core/bbox/coder/delta_xywha_rbbox_coder.py +++ b/mmrotate/core/bbox/coder/delta_xywha_rbbox_coder.py @@ -67,7 +67,7 @@ def encode(self, bboxes, gt_bboxes): assert bboxes.size(0) == gt_bboxes.size(0) assert bboxes.size(-1) == 5 assert gt_bboxes.size(-1) == 5 - if self.angle_range in ['oc', 'le135', 'le90', 'full360']: + if self.angle_range in ['oc', 'le135', 'le90']: return bbox2delta(bboxes, gt_bboxes, self.means, self.stds, self.angle_range, self.norm_factor, self.edge_swap, self.proj_xy) @@ -99,7 +99,7 @@ def decode(self, torch.Tensor: Decoded boxes. """ assert pred_bboxes.size(0) == bboxes.size(0) - if self.angle_range in ['oc', 'le135', 'le90', 'full360']: + if self.angle_range in ['oc', 'le135', 'le90']: return delta2bbox(bboxes, pred_bboxes, self.means, self.stds, max_shape, wh_ratio_clip, self.add_ctr_clamp, self.ctr_clamp, self.angle_range, diff --git a/mmrotate/core/bbox/transforms.py b/mmrotate/core/bbox/transforms.py index 0153327c2..01d51651e 100644 --- a/mmrotate/core/bbox/transforms.py +++ b/mmrotate/core/bbox/transforms.py @@ -108,8 +108,6 @@ def poly2obb(polys, version='oc'): results = poly2obb_le135(polys) elif version == 'le90': results = poly2obb_le90(polys) - elif version == 'full360': - results = poly2obb_full360(polys) else: raise NotImplementedError return results @@ -131,8 +129,6 @@ def poly2obb_np(polys, version='oc'): results = poly2obb_np_le135(polys) elif version == 'le90': results = poly2obb_np_le90(polys) - elif version == 'full360': - results = poly2obb_np_full360(polys) else: raise NotImplementedError return results @@ -154,9 +150,6 @@ def obb2hbb(rbboxes, version='oc'): results = obb2hbb_le135(rbboxes) elif version == 'le90': results = obb2hbb_le90(rbboxes) - elif version == 'full360': - # NOTE: same as 90 - results = obb2hbb_le90(rbboxes) else: raise NotImplementedError return results @@ -178,9 +171,6 @@ def obb2poly(rbboxes, version='oc'): results = obb2poly_le135(rbboxes) elif version == 'le90': results = obb2poly_le90(rbboxes) - elif version == 'full360': - # NOTE: same as 90 - results = obb2poly_le90(rbboxes) else: raise NotImplementedError return results @@ -202,8 +192,6 @@ def obb2poly_np(rbboxes, version='oc'): results = obb2poly_np_le135(rbboxes) elif version == 'le90': results = obb2poly_np_le90(rbboxes) - elif version == 'full360': - results = obb2poly_np_full360(rbboxes) else: raise NotImplementedError return results @@ -225,9 +213,6 @@ def obb2xyxy(rbboxes, version='oc'): results = obb2xyxy_le135(rbboxes) elif version == 'le90': results = obb2xyxy_le90(rbboxes) - elif version == 'full360': - # NOTE: same as 90 - results = obb2xyxy_le90(rbboxes) else: raise NotImplementedError return results @@ -250,7 +235,6 @@ def hbb2obb(hbboxes, version='oc'): elif version == 'le90': results = hbb2obb_le90(hbboxes) else: - # NOTE: not well defined for full360. Leave it unimplemented raise NotImplementedError return results @@ -314,31 +298,6 @@ def poly2obb_le135(polys): return torch.stack([x_ctr, y_ctr, width, height, angles], 1) -def poly2obb_full360(polys): - """Convert polygons to oriented bounding boxes. - - Args: - polys (torch.Tensor): [x0,y0,x1,y1,x2,y2,x3,y3] - - Returns: - obbs (torch.Tensor): [x_ctr,y_ctr,w,h,angle] - """ - polys = torch.reshape(polys, [-1, 8]) - pt1, pt2, pt3, _ = polys[..., :8].chunk(4, 1) - width = torch.sqrt( - torch.pow(pt1[..., 0] - pt2[..., 0], 2) + - torch.pow(pt1[..., 1] - pt2[..., 1], 2)) - height = torch.sqrt( - torch.pow(pt2[..., 0] - pt3[..., 0], 2) + - torch.pow(pt2[..., 1] - pt3[..., 1], 2)) - angles = torch.atan2((pt1[..., 1] - pt2[..., 1]), - (pt1[..., 0] - pt2[..., 0])) - angles = norm_angle(angles, 'full360') - x_ctr = (pt1[..., 0] + pt3[..., 0]) / 2.0 - y_ctr = (pt1[..., 1] + pt3[..., 1]) / 2.0 - return torch.stack([x_ctr, y_ctr, width, height, angles], 1) - - def poly2obb_le90(polys): """Convert polygons to oriented bounding boxes. @@ -459,33 +418,6 @@ def poly2obb_np_le90(poly): return x, y, w, h, a -def poly2obb_np_full360(poly): - """Convert polygons to oriented bounding boxes. Assumes head points then - tail points. - - Args: - polys (ndarray): [x0,y0,x1,y1,x2,y2,x3,y3] - - Returns: - obbs (ndarray): [x_ctr,y_ctr,w,h,angle] - """ - pt1, pt2, pt3, pt4 = np.array(poly).reshape((4, 2)) - x, y = (pt1 + pt2 + pt3 + pt4) / 4.0 - dx, dy = pt2 - pt1 - a = np.arctan2(dy, dx) - w = np.linalg.norm(pt2 - pt1) - h = np.linalg.norm(pt3 - pt2) - if w < 2 or h < 2: - return - while not np.pi > a >= -np.pi: - if a >= np.pi: - a -= np.pi - else: - a += np.pi - assert np.pi > a >= -np.pi - return x, y, w, h, a - - def obb2poly_oc(rboxes): """Convert oriented bounding boxes to polygons. @@ -702,26 +634,6 @@ def hbb2obb_le90(hbboxes): return obboxes -def hbb2obb_full360(hbboxes): - """Convert horizontal bounding boxes to oriented bounding boxes. - - Args: - hbbs (torch.Tensor): [x_lt,y_lt,x_rb,y_rb] - - Returns: - obbs (torch.Tensor): [x_ctr,y_ctr,w,h,angle] - """ - x = (hbboxes[..., 0] + hbboxes[..., 2]) * 0.5 - y = (hbboxes[..., 1] + hbboxes[..., 3]) * 0.5 - w = hbboxes[..., 2] - hbboxes[..., 0] - h = hbboxes[..., 3] - hbboxes[..., 1] - theta = x.new_zeros(*x.shape) - obboxes1 = torch.stack([x, y, w, h, theta], dim=-1) - obboxes2 = torch.stack([x, y, h, w, theta - np.pi / 2], dim=-1) - obboxes = torch.where((w >= h)[..., None], obboxes1, obboxes2) - return obboxes - - def obb2xyxy_oc(rbboxes): """Convert oriented bounding boxes to horizontal bounding boxes. @@ -871,31 +783,6 @@ def obb2poly_np_le90(obboxes): return polys -def obb2poly_np_full360(obboxes): - """Convert oriented bounding boxes to polygons. - - Args: - obbs (ndarray): [x_ctr,y_ctr,w,h,angle,score] - - Returns: - polys (ndarray): [x0,y0,x1,y1,x2,y2,x3,y3,score] - """ - try: - center, w, h, theta, score = np.split(obboxes, (2, 3, 4, 5), axis=-1) - except: # noqa: E722 - results = np.stack([0., 0., 0., 0., 0., 0., 0., 0., 0.], axis=-1) - return results.reshape(1, -1) - Cos, Sin = np.cos(theta), np.sin(theta) - vector1 = np.concatenate([w / 2 * Cos, w / 2 * Sin], axis=-1) - vector2 = np.concatenate([-h / 2 * Sin, h / 2 * Cos], axis=-1) - point1 = center - vector1 - vector2 - point2 = center + vector1 - vector2 - point3 = center + vector1 + vector2 - point4 = center - vector1 + vector2 - polys = np.concatenate([point1, point2, point3, point4, score], axis=-1) - return polys - - def cal_line_length(point1, point2): """Calculate the length of line. @@ -976,8 +863,6 @@ def norm_angle(angle, angle_range): return (angle + np.pi / 4) % np.pi - np.pi / 4 elif angle_range == 'le90': return (angle + np.pi / 2) % np.pi - np.pi / 2 - elif angle_range == 'full360': - return angle % (2 * np.pi) - np.pi else: print('Not yet implemented.') diff --git a/mmrotate/datasets/pipelines/transforms.py b/mmrotate/datasets/pipelines/transforms.py index 6fa523c2f..63e832182 100644 --- a/mmrotate/datasets/pipelines/transforms.py +++ b/mmrotate/datasets/pipelines/transforms.py @@ -80,10 +80,8 @@ def bbox_flip(self, bboxes, img_shape, direction): flipped = bboxes.copy() if direction == 'horizontal': flipped[:, 0] = img_shape[1] - bboxes[:, 0] - 1 - flipped[:4] = flipped[[1, 0, 3, 2]].copy() elif direction == 'vertical': flipped[:, 1] = img_shape[0] - bboxes[:, 1] - 1 - flipped[:4] = flipped[[1, 0, 3, 2]].copy() elif direction == 'diagonal': flipped[:, 0] = img_shape[1] - bboxes[:, 0] - 1 flipped[:, 1] = img_shape[0] - bboxes[:, 1] - 1 @@ -273,6 +271,7 @@ def __call__(self, results): def __repr__(self): repr_str = self.__class__.__name__ repr_str += f'(rotate_ratio={self.rotate_ratio}, ' \ + f'base_angles={self.base_angles}, ' \ f'angles_range={self.angles_range}, ' \ f'auto_bound={self.auto_bound})' return repr_str diff --git a/tests/test_utils/test_transformer.py b/tests/test_utils/test_transformer.py index 173e9ffd2..f33bf9205 100644 --- a/tests/test_utils/test_transformer.py +++ b/tests/test_utils/test_transformer.py @@ -28,23 +28,3 @@ def test_transforms(): obboxes3 = rtf.hbb2obb(hbboxes, 'le90') assert not np.allclose(obboxes1.numpy(), obboxes2) assert np.allclose(obboxes2.numpy(), obboxes3) - - # test full360 - # Check obb2poly and poly2obb is inverse function in full360 rotation - for angle in np.linspace(-.9 * np.pi, .9 * np.pi, 4): - # numpy version - box_np = np.array((100, 100, 80, 50, angle), dtype=np.float32) - pts_np = rtf.obb2poly_np(box_np[None], version='full360')[0] - box2_np = rtf.poly2obb_np(pts_np, version='full360') - np.testing.assert_almost_equal(box_np, box2_np, decimal=4) - - # torch version - box_torch = torch.tensor((100, 100, 80, 50, angle), - dtype=torch.float32) - pts_torch = rtf.obb2poly(box_torch[None], version='full360')[0] - box2_torch = rtf.poly2obb(pts_torch, version='full360')[0] - torch.norm(box_torch - box2_torch) < 1e-4 - - # compatibility between numpy and torch implementations - torch.norm(box_torch - torch.from_numpy(box_np)) < 1e-4 - torch.norm(pts_torch - torch.from_numpy(pts_np)) < 1e-4