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)
    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)
Exemple #3
0
    def to_contours(self):
        origin, mask = self.origin, self.data
        _, contours, hier = cv2.findContours(
            mask.astype(np.uint8),
            mode=cv2.RETR_CCOMP,  # two-level hierarchy, to get polygons with holes
            method=cv2.CHAIN_APPROX_SIMPLE
        )
        if (hier is None) or (contours is None):
            return []

        res = []
        for idx, hier_pos in enumerate(hier[0]):
            next_idx, prev_idx, child_idx, parent_idx = hier_pos
            if parent_idx < 0:
                external = contours[idx][:, 0].tolist()
                internals = []
                while child_idx >= 0:
                    internals.append(contours[child_idx][:, 0])
                    child_idx = hier[0][child_idx][0]
                if len(external) > 2:
                    new_poly = Polygon(exterior=row_col_list_to_points(external, flip_row_col_order=True),
                                       interior=[row_col_list_to_points(x, flip_row_col_order=True) for x in internals])
                    res.append(new_poly)

        offset_row, offset_col = origin.row, origin.col
        res = [x.translate(offset_row, offset_col) for x in res]
        return res
 def test_from_json(self):
     packed_obj = {
         'some_stuff': 'aaa',
         POINTS: {
             EXTERIOR: self.exterior,
             INTERIOR: self.interiors
         }
     }
     res_poly = Polygon.from_json(packed_obj)
     self.assertPolyEquals(res_poly, self.exterior, self.interiors)
Exemple #5
0
def geometry_to_polygon(geometry, approx_epsilon=None):
    if type(geometry) not in (Rectangle, Polyline, Polygon, Bitmap):
        raise KeyError('Can not convert {} to {}'.format(
            geometry.geometry_name(), Polygon.__name__))

    if type(geometry) == Rectangle:
        return [Polygon(geometry.corners, [])]

    if type(geometry) == Polyline:
        return [Polygon(geometry.exterior, [])]

    if type(geometry) == Polygon:
        return [geometry]

    if type(geometry) == Bitmap:
        new_geometries = geometry.to_contours()
        if approx_epsilon is None:
            approx_epsilon = 1

        new_geometries = [g.approx_dp(approx_epsilon) for g in new_geometries]
        return new_geometries
    def test_draw_contour(self):
        exterior = [[0, 0], [0, 6], [6, 6], [6, 0]]
        interiors = [[[2, 2], [2, 4], [4, 4], [4, 2]]]
        poly = Polygon(exterior=row_col_list_to_points(exterior),
                       interior=[row_col_list_to_points(interior) for interior in interiors])

        bitmap_1 = np.zeros((7, 7), dtype=np.uint8)
        poly.draw_contour(bitmap_1, color=1)

        expected_mask = np.array([[1, 1, 1, 1, 1, 1, 1],
                                  [1, 0, 0, 0, 0, 0, 1],
                                  [1, 0, 1, 1, 1, 0, 1],
                                  [1, 0, 1, 0, 1, 0, 1],
                                  [1, 0, 1, 1, 1, 0, 1],
                                  [1, 0, 0, 0, 0, 0, 1],
                                  [1, 1, 1, 1, 1, 1, 1]], dtype=np.uint8)
        self.assertTrue(np.array_equal(bitmap_1, expected_mask))

        # Extended test
        exterior = [[0, 0], [0, 6], [10, 6], [10, 0]]
        interiors = [[[1, 1], [1, 2], [2, 1]],
                     [[2, 4], [3, 5], [4, 4], [3, 3]],
                     [[6, 2], [8, 2], [8, 4], [6, 4]]]
        poly = Polygon(exterior=row_col_list_to_points(exterior),
                       interior=[row_col_list_to_points(interior) for interior in interiors])

        bitmap_2 = np.zeros((11, 7), dtype=np.uint8)
        poly.draw_contour(bitmap_2, color=1)

        expected_mask = np.array([[1, 1, 1, 1, 1, 1, 1],
                                  [1, 1, 1, 0, 0, 0, 1],
                                  [1, 1, 0, 0, 1, 0, 1],
                                  [1, 0, 0, 1, 0, 1, 1],
                                  [1, 0, 0, 0, 1, 0, 1],
                                  [1, 0, 0, 0, 0, 0, 1],
                                  [1, 0, 1, 1, 1, 0, 1],
                                  [1, 0, 1, 0, 1, 0, 1],
                                  [1, 0, 1, 1, 1, 0, 1],
                                  [1, 0, 0, 0, 0, 0, 1],
                                  [1, 1, 1, 1, 1, 1, 1]], dtype=np.uint8)

        self.assertTrue(np.array_equal(bitmap_2, expected_mask))
 def draw_mask(exterior_p, interior_p, h, w):
     mask = np.zeros((h, w), dtype=np.uint8)
     poly = Polygon(exterior=row_col_list_to_points(exterior_p),
                    interior=[row_col_list_to_points(interior) for interior in interior_p])
     poly.draw(mask, color=1)
     return mask
 def setUp(self):
     self.exterior = [[10, 10], [40, 10], [30, 40], [10, 30]]
     self.interiors = [[[20, 20], [30, 20], [30, 30], [20, 30]]]
     self.poly = Polygon(exterior=row_col_list_to_points(self.exterior, flip_row_col_order=True),
                         interior=[row_col_list_to_points(self.interiors[0], flip_row_col_order=True)])
class PolygonTest(unittest.TestCase):
    def setUp(self):
        self.exterior = [[10, 10], [40, 10], [30, 40], [10, 30]]
        self.interiors = [[[20, 20], [30, 20], [30, 30], [20, 30]]]
        self.poly = Polygon(exterior=row_col_list_to_points(self.exterior, flip_row_col_order=True),
                            interior=[row_col_list_to_points(self.interiors[0], flip_row_col_order=True)])

    def assertPolyEquals(self, poly, exterior, interiors):
        self.assertIsInstance(poly, Polygon)
        self.assertCountEqual(points_to_row_col_list(poly.exterior, flip_row_col_order=True), exterior)
        self.assertEqual(len(poly.interior), len(interiors))
        for p_interior, interior in zip(poly.interior, interiors):
            self.assertCountEqual(points_to_row_col_list(p_interior, flip_row_col_order=True), interior)

    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)

    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]],
                              [])

    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)

    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)

    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]], [])

    def test_rotate(self):
        imsize = (101, 101)
        rotator = ImageRotator(imsize=imsize, angle_degrees_ccw=-90)
        res_poly = self.poly.rotate(rotator)
        self.assertPolyEquals(res_poly,
                              [[90, 10], [90, 40], [60, 30], [70, 10]],
                              [[[80, 20], [80, 30], [70, 30], [70, 20]]])

    def test_resize(self):
        in_size = (100, 100)
        out_size = (200, 150)
        res_poly = self.poly.resize(in_size, out_size)
        self.assertPolyEquals(res_poly,
                              [[15, 20], [60, 20], [45, 80], [15, 60]],
                              [[[30, 40], [45, 40], [45, 60], [30, 60]]])

    def test_translate(self):
        drow = 5
        dcol = 10
        res_poly = self.poly.translate(drow, dcol)
        self.assertPolyEquals(res_poly,
                              [[20, 15], [50, 15], [40, 45], [20, 35]],
                              [[[30, 25], [40, 25], [40, 35], [30, 35]]])

    def test_fliplr(self):
        imsize = (100, 200)
        res_poly = self.poly.fliplr(imsize)
        self.assertPolyEquals(res_poly,
                              [[190, 10], [160, 10], [170, 40], [190, 30]],
                              [[[180, 20], [170, 20], [170, 30], [180, 30]]])

    def test_area(self):  # @TODO: only exterior area
        area = self.poly.area
        self.assertIsInstance(area, float)
        self.assertEqual(area, 650.0)

    def test_to_bbox(self):
        res_rect = self.poly.to_bbox()
        self.assertIsInstance(res_rect, Rectangle)
        self.assertEqual(res_rect.top, 10)
        self.assertEqual(res_rect.left, 10)
        self.assertEqual(res_rect.right, 40)
        self.assertEqual(res_rect.bottom, 40)

    def test_from_json(self):
        packed_obj = {
            'some_stuff': 'aaa',
            POINTS: {
                EXTERIOR: self.exterior,
                INTERIOR: self.interiors
            }
        }
        res_poly = Polygon.from_json(packed_obj)
        self.assertPolyEquals(res_poly, self.exterior, self.interiors)

    def test_to_json(self):
        res_obj = self.poly.to_json()
        expected_dict = {
            POINTS: {
                EXTERIOR: self.exterior,
                INTERIOR: self.interiors
            }
        }
        self.assertDictEqual(res_obj, expected_dict)

    def test_clone(self):
        res_poly = self.poly.clone()
        self.assertIsInstance(res_poly, Polygon)
        self.assertTrue(np.array_equal(res_poly.exterior_np, self.poly.exterior_np))
        self.assertTrue(np.array_equal(res_poly.interior_np, self.poly.interior_np))
        self.assertIsNot(res_poly, self.poly)

    def test_draw(self):
        def draw_mask(exterior_p, interior_p, h, w):
            mask = np.zeros((h, w), dtype=np.uint8)
            poly = Polygon(exterior=row_col_list_to_points(exterior_p),
                           interior=[row_col_list_to_points(interior) for interior in interior_p])
            poly.draw(mask, color=1)
            return mask

        # Test 1 - draw interior triangles
        exterior = [[0, 0], [0, 6], [4, 6], [4, 0]]
        interiors = [[[1, 1], [1, 3], [3, 1]],  # clockwise
                     [[1, 5], [3, 3], [3, 5]]]  # counterclockwise
        mask_1 = draw_mask(exterior, interiors, h=5, w=7)
        expected_mask = np.array([[1, 1, 1, 1, 1, 1, 1],
                                  [1, 0, 0, 0, 1, 0, 1],
                                  [1, 0, 0, 1, 0, 0, 1],
                                  [1, 0, 1, 0, 0, 0, 1],
                                  [1, 1, 1, 1, 1, 1, 1]], dtype=np.uint8)

        self.assertTrue(np.array_equal(mask_1, expected_mask))

        # Test 1 - draw interior sandglass (bad poly case)
        exterior = [[0, 0], [0, 7], [7, 7], [7, 0]]
        interiors = [[[1, 1], [5, 5], [1, 5], [5, 1]]]  # sandglass
        mask_2 = draw_mask(exterior, interiors, h=7, w=7)
        expected_mask = np.array([[1, 1, 1, 1, 1, 1, 1],
                                  [1, 0, 1, 1, 1, 0, 1],
                                  [1, 0, 0, 1, 0, 0, 1],
                                  [1, 0, 0, 0, 0, 0, 1],
                                  [1, 0, 0, 1, 0, 0, 1],
                                  [1, 0, 1, 1, 1, 0, 1],
                                  [1, 1, 1, 1, 1, 1, 1]], dtype=np.uint8)
        self.assertTrue(np.array_equal(mask_2, expected_mask))

    def test_draw_contour(self):
        exterior = [[0, 0], [0, 6], [6, 6], [6, 0]]
        interiors = [[[2, 2], [2, 4], [4, 4], [4, 2]]]
        poly = Polygon(exterior=row_col_list_to_points(exterior),
                       interior=[row_col_list_to_points(interior) for interior in interiors])

        bitmap_1 = np.zeros((7, 7), dtype=np.uint8)
        poly.draw_contour(bitmap_1, color=1)

        expected_mask = np.array([[1, 1, 1, 1, 1, 1, 1],
                                  [1, 0, 0, 0, 0, 0, 1],
                                  [1, 0, 1, 1, 1, 0, 1],
                                  [1, 0, 1, 0, 1, 0, 1],
                                  [1, 0, 1, 1, 1, 0, 1],
                                  [1, 0, 0, 0, 0, 0, 1],
                                  [1, 1, 1, 1, 1, 1, 1]], dtype=np.uint8)
        self.assertTrue(np.array_equal(bitmap_1, expected_mask))

        # Extended test
        exterior = [[0, 0], [0, 6], [10, 6], [10, 0]]
        interiors = [[[1, 1], [1, 2], [2, 1]],
                     [[2, 4], [3, 5], [4, 4], [3, 3]],
                     [[6, 2], [8, 2], [8, 4], [6, 4]]]
        poly = Polygon(exterior=row_col_list_to_points(exterior),
                       interior=[row_col_list_to_points(interior) for interior in interiors])

        bitmap_2 = np.zeros((11, 7), dtype=np.uint8)
        poly.draw_contour(bitmap_2, color=1)

        expected_mask = np.array([[1, 1, 1, 1, 1, 1, 1],
                                  [1, 1, 1, 0, 0, 0, 1],
                                  [1, 1, 0, 0, 1, 0, 1],
                                  [1, 0, 0, 1, 0, 1, 1],
                                  [1, 0, 0, 0, 1, 0, 1],
                                  [1, 0, 0, 0, 0, 0, 1],
                                  [1, 0, 1, 1, 1, 0, 1],
                                  [1, 0, 1, 0, 1, 0, 1],
                                  [1, 0, 1, 1, 1, 0, 1],
                                  [1, 0, 0, 0, 0, 0, 1],
                                  [1, 1, 1, 1, 1, 1, 1]], dtype=np.uint8)

        self.assertTrue(np.array_equal(bitmap_2, expected_mask))