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]
class RectangleTest(unittest.TestCase): def setUp(self): self.rect = Rectangle(top=5, left=10, bottom=30, right=30) def assertRectEquals(self, rect, top, left, bottom, right): self.assertIsInstance(rect, Rectangle) self.assertEqual(rect.top, top) self.assertEqual(rect.left, left) self.assertEqual(rect.bottom, bottom) self.assertEqual(rect.right, right) def test_empty_crop(self): crop_rect = Rectangle(100, 100, 200, 200) res_geoms = self.rect.crop(crop_rect) self.assertEqual(len(res_geoms), 0) def test_crop(self): crop_rect = Rectangle(0, 0, 100, 100) res_geoms = self.rect.crop(crop_rect) self.assertEqual(len(res_geoms), 1) res_rect = res_geoms[0] self.assertRectEquals(res_rect, self.rect.top, self.rect.left, self.rect.bottom, self.rect.right) def test_relative_crop(self): crop_rect = Rectangle(3, 4, 100, 100) res_geoms = self.rect.relative_crop(crop_rect) self.assertEqual(len(res_geoms), 1) res_rect = res_geoms[0] self.assertRectEquals(res_rect, 2, 6, 27, 26) def test_rotate(self): imsize = (101, 101) rotator = ImageRotator(imsize=imsize, angle_degrees_ccw=90) res_rect = self.rect.rotate(rotator) self.assertRectEquals(res_rect, 70, 5, 90, 30) def test_resize(self): in_size = (100, 100) out_size = (200, 150) res_rect = self.rect.resize(in_size, out_size) self.assertRectEquals(res_rect, 10, 15, 60, 45) def test_scale(self): factor = 1.3 res_rect = self.rect.scale(factor) self.assertRectEquals(res_rect, 6, 13, 39, 39) def test_translate(self): drows = 8 dcols = 259 res_rect = self.rect.translate(drows, dcols) self.assertRectEquals(res_rect, 13, 269, 38, 289) def test_fliplr(self): im_size = (100, 200) res_rect = self.rect.fliplr(im_size) self.assertRectEquals(res_rect, 5, 170, 30, 190) def test_flipud(self): im_size = (100, 200) res_rect = self.rect.flipud(im_size) self.assertRectEquals(res_rect, 70, 10, 95, 30) def test_area(self): area = self.rect.area self.assertIsInstance(area, float) self.assertEqual(area, 546.0) def test_to_bbox(self): res_rect = self.rect.to_bbox() self.assertRectEquals(res_rect, self.rect.top, self.rect.left, self.rect.bottom, self.rect.right) def test_clone(self): res_rect = self.rect.clone() self.assertRectEquals(res_rect, self.rect.top, self.rect.left, self.rect.bottom, self.rect.right) self.assertIsNot(res_rect, self.rect) def test_from_json(self): packed_obj = { 'some_stuff': 'aaa', POINTS: { EXTERIOR: [[17, 3], [34, 45]], INTERIOR: [] } } res_rect = Rectangle.from_json(packed_obj) self.assertRectEquals(res_rect, 3, 17, 45, 34) def test_to_json(self): res_obj = self.rect.to_json() expected_dict = { POINTS: { EXTERIOR: [[10, 5], [30, 30]], INTERIOR: [] } } self.assertDictEqual(res_obj, expected_dict) 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))