Esempio n. 1
0
    def generate_polygon(self, sub_mask_anno):
        contours = measure.find_contours(sub_mask_anno, 0.5, positive_orientation='low')

        segmentations = []
        polygons = []

        for contour in contours:
            for i in range(len(contour)):
                row, col = contour[i]
                contour[i] = (col - 1, row - 1)

            if contour.shape[0] < 3:
                continue
            
            poly = Polygon(contour)
            if poly.area < 5:
                continue
            poly = poly.simplify(1.0, preserve_topology=False)
            if poly.geom_type == 'MultiPolygon':
                for poly_ in poly:
                    polygons.append(poly_)
                    segmentation = np.array(poly_.exterior.coords).ravel().tolist()
                    segmentations.append(segmentation)
            else:
                polygons.append(poly)
                segmentation = np.array(poly.exterior.coords).ravel().tolist()
                segmentations.append(segmentation)

        return segmentations, polygons
Esempio n. 2
0
def create_sub_mask_annotation(sub_mask):
    # Find contours (boundary lines) around each sub-mask
    # Note: there could be multiple contours if the object
    # is partially occluded. (E.g. an elephant behind a tree)
    sub_mask = np.array(sub_mask)
    contours = measure.find_contours(sub_mask, 0.5, positive_orientation='low')

    segmentations = []
    polygons = []
    for contour in contours:
        # Flip from (row, col) representation to (x, y)
        # and subtract the padding pixel
        for i in range(len(contour)):
            row, col = contour[i]
            contour[i] = (col - 1, row - 1)

        # Make a polygon and simplify it
        poly = Polygon(contour)
        poly = poly.simplify(1.0, preserve_topology=False)
        polygons.append(poly)
        segmentation = np.array(poly.exterior.coords).ravel().tolist()
        segmentations.append(segmentation)

    # Combine the polygons to calculate the bounding box and area
    multi_poly = MultiPolygon(polygons)
    x, y, max_x, max_y = multi_poly.bounds
    width = max_x - x
    height = max_y - y
    bbox = (x, y, width, height)
    area = multi_poly.area

    annotation = {'segmentation': segmentations, 'bbox': bbox, 'area': area}

    return annotation
Esempio n. 3
0
def segmentate_figure(mask, width, height):
    # Find contours (boundary lines) around each sub-mask
    # Note: there could be multiple contours if the object
    # is partially occluded. (E.g. an elephant behind a tree)
    # Pad the mask just in case the polygon is touching the borders
    mask = np.pad(mask, 1,'constant')
    contours = measure.find_contours(mask, 0.5, positive_orientation='low')

    segmentations = []
    polygons = []
    for contour in contours:
        # Flip from (row, col) representation to (x, y),
        # subtract the padding pixel
        # and situate the points in their correspondent position
        for i in range(len(contour)):
            row, col = contour[i]
            contour[i] = (col + width - 1, row + height - 1)

        # Make a polygon and simplify it
        poly = Polygon(contour)
        poly = poly.simplify(1.0, preserve_topology=False)

        polygons.append(poly)

        if poly.exterior is not None:
            segmentation = np.array(poly.exterior.coords).ravel().tolist()
            segmentations.append(segmentation)

    multi_poly = MultiPolygon(polygons)

    return segmentations, multi_poly.area
Esempio n. 4
0
    def create_sub_mask_annotation(self, sub_mask):
        # Find contours (boundary lines) around each sub-mask
        # Note: there could be multiple contours if the object
        # is partially occluded. (E.g. an elephant behind a tree)
        contours = measure.find_contours(sub_mask, 0.5, positive_orientation='low')

        polygons = []
        segmentations = []
        j = 0
        for contour in contours:
            # Flip from (row, col) representation to (x, y)
            # and subtract the padding pixel
            for i in range(len(contour)):
                row, col = contour[i]
                contour[i] = (col - 1, row - 1)

            # Make a polygon and simplify it
            poly = Polygon(contour)
            poly = poly.simplify(1.0, preserve_topology=False)

            if (poly.is_empty):
                # Go to next iteration, dont save empty values in list
                continue

            polygons.append(poly)

            segmentation = np.array(poly.exterior.coords).ravel().tolist()
            segmentations.append(segmentation)

        return polygons, segmentations
Esempio n. 5
0
def process_mask_and_bbox(multi_poly):
    new_mask = np.zeros((576, 1024), dtype=np.bool)
    for polygon in multi_poly:
        polygon2mask_aux(new_mask, polygon.exterior.coords)
    new_mask = create_mask(new_mask)
    contours = measure.find_contours(new_mask, 0.5, positive_orientation='low')
    polygons = []
    for contour in contours:
        poly = Polygon(contour)
        poly = poly.simplify(1.0, preserve_topology=True)
        polygons.append(poly)
    multi_poly = MultiPolygon(polygons)
    segmentations = []
    for polygon in multi_poly:
        segmentation = np.array(polygon.exterior.coords)
        temp = np.copy(segmentation[:,0])
        segmentation[:,0] = segmentation[:,1]
        segmentation[:,1] = temp
        segmentation = segmentation.ravel().tolist()
        segmentations.append(segmentation)
    x, y, max_x, max_y = multi_poly.bounds
    width = max_x - x
    height = max_y - y
    bbox = (y, x, height, width)

    return segmentations, bbox
Esempio n. 6
0
def save_as_csv(file_path, npy_list, contours, footprints, npys):
    aoi = '_'.join(npy_list[0].split('/')[-1].split('.')[0].split('_')[5:])
    print('save csv: %s, npoly = %d' % (aoi, footprints.sum()))
    fw = open(file_path[:-4] + '_' + aoi + '.csv', 'w')
    for j, contour in enumerate(contours):
        contour = contour / 3
        p = Polygon(contour)
        p = p.simplify(tolerance=0.2)
        try:
            contour = np.array(p.boundary.xy, dtype='float32').T
        except:
            contour = np.array(p.boundary[0].xy, dtype='float32').T
        contour = np.round(contour.reshape(-1, 2) * 10) / 10

        polygon_str = re.sub(r"[\[\]]", '', ",".join(map(str, contour)))
        polygon_str = polygon_str.replace(". ", ' ')
        polygon_str = polygon_str.replace(".,", ',')
        polygon_str = re.sub(r" {2,}", ' ', polygon_str)
        polygon_str = re.sub(r" {0,}, {0,}", ',', polygon_str)

        for i, npy_file in enumerate(npy_list):
            filename = npy_file.split('/')[-1].split('.')[0]
            flag = footprints[j, i]
            if flag:
                fw.write("%s,%d,\"POLYGON ((%s))\"\n" %
                         (filename, j, polygon_str))
    fw.close()
Esempio n. 7
0
def create_sub_mask_annotation(sub_mask):
    # Find contours (boundary lines) around each sub-mask
    # Note: there could be multiple contours if the object
    # is partially occluded. (E.g. an elephant behind a tree)

    # contours = measure.find_contours(
    #     np.array(sub_mask), 100, positive_orientation="low")
    contours, hierarchy = cv2.findContours((sub_mask), cv2.RETR_EXTERNAL,
                                           cv2.CHAIN_APPROX_TC89_L1)

    polygons = []
    segmentations = []

    for contour in contours:
        # Flip from (row, col) representation to (x, y)
        # and subtract the padding pixel
        new_contour = []
        if len(contour) < 4:
            continue
        for i in range(len(contour)):
            row, col = contour[i][0]
            #contour[i] = (col - 1, row - 1)
            if (col, row) in new_contour:  # multipolygon error
                continue
            new_contour.append((col, row))
        # Make a polygon and simplify it
        poly = Polygon(new_contour)
        poly = poly.simplify(1.0, preserve_topology=False)

        polygons.append(poly)

        segmentation = np.array(poly.exterior.coords).ravel().tolist()
        segmentations.append(segmentation)

    return polygons, segmentations
Esempio n. 8
0
def filter_planes_and_holes(polygons, points, config):
    """Extracts the plane and obstacles returned from polylidar
    Will filter polygons according to: number of vertices and size
    Will also buffer (dilate) and simplify polygons

    Arguments:
        polygons {list[Polygons]} -- A list of polygons returned from polylidar
        points {ndarray} -- MX3 array
        config {dict} -- Configuration for filtering

    Returns:
        tuple -- A list of plane shapely polygons and a list of obstacle polygons
    """
    # filtering configuration
    pot_post = config['polygon']['postprocess']
    pot_filter = pot_post['filter']

    # will hold the plane(s) and obstacles found
    planes = []
    obstacles = []
    for poly in polygons:
        shell_coords = [get_point(pi, points) for pi in poly.shell]
        outline = Polygon(shell=shell_coords)

        outline = outline.buffer(distance=CMTOM * pot_post['buffer'])
        outline = outline.simplify(tolerance=CMTOM * pot_post['simplify'])
        area = outline.area * M2TOCM2
        if area >= pot_filter['plane_area']['min']:
            # Capture the polygon as well as its z height
            planes.append((outline, shell_coords[0][2]))

            for hole_poly in poly.holes:
                # Filter by number of obstacle vertices, removes noisy holes
                if len(hole_poly) > pot_filter['hole_vertices']['min']:
                    shell_coords = [get_point(pi, points) for pi in hole_poly]
                    outline = Polygon(shell=shell_coords)
                    area = outline.area * M2TOCM2
                    # filter by area
                    if area >= pot_filter['hole_area'][
                            'min'] and area < pot_filter['hole_area']['max']:
                        outline = outline.buffer(distance=CMTOM *
                                                 pot_post['buffer'])
                        outline = outline.simplify(tolerance=CMTOM *
                                                   pot_post['simplify'])
                        obstacles.append((outline, shell_coords[0][2]))
    return planes, obstacles
Esempio n. 9
0
def simplify(poly):
    # fig = pyplot.figure(1, figsize=SIZE, dpi=90)

    um = 1e1

    # print(convert_node_to_2d(poly))

    # pp = convert_node_to_2d(poly)
    # p = Polygon(pp)

    xmax, xmin = poly.max(), poly.min()

    p = Polygon(poly)
    # p = Polygon([(0, 0), (1*um, 1*um), (1*um, 0)])

    # 1
    # ax = fig.add_subplot(121)

    q = p.simplify(1.5e5)

    # patch1a = PolygonPatch(p, facecolor=GRAY, edgecolor=GRAY)
    # ax.add_patch(patch1a)

    # patch1b = PolygonPatch(q, facecolor=BLUE, edgecolor=BLUE, alpha=0.5, zorder=2)
    # ax.add_patch(patch1b)

    # ax.set_title('a) tolerance 0.2')
    #
    # xrange = [xmin*um, xmax*um]
    # yrange = [xmin*um, xmax*um]
    # ax.set_xlim(*xrange)
    # ax.set_ylim(*yrange)
    # ax.set_aspect(1)

    #2
    # ax = fig.add_subplot(122)
    #
    # r = p.simplify(0.5)
    #
    # patch2a = PolygonPatch(p, facecolor=GRAY, edgecolor=GRAY, alpha=0.5, zorder=1)
    # ax.add_patch(patch2a)

    # patch2b = PolygonPatch(r, facecolor=BLUE, edgecolor=BLUE, alpha=0.5, zorder=2)
    # ax.add_patch(patch2b)

    # ax.set_title('b) tolerance 0.5')
    #
    # # xrange = [-3*um, 3*um]
    # # yrange = [-3*um, 3*um]
    # xrange = [0*um, 1*um]
    # yrange = [0*um, 1*um]
    # ax.set_xlim(*xrange)
    # ax.set_ylim(*yrange)
    # ax.set_aspect(1)

    # pyplot.show()

    return list(q.exterior.coords)
Esempio n. 10
0
    def _create_annotations(self):
        # Creates annotations for each isolated mask

        # Each image may have multiple annotations, so create an array
        self.annotations = []
        for key, mask in self.isolated_masks.items():
            annotation = dict()
            annotation['segmentation'] = []
            annotation['iscrowd'] = 0
            annotation['image_id'] = self.image_id
            if not self.category_ids.get(key):
                print(f'category color not found: {key}; check for missing category or antialiasing')
                continue
            annotation['category_id'] = self.category_ids[key]
            annotation['id'] = self._next_annotation_id()

            # Find contours in the isolated mask
            mask = np.asarray(mask, dtype=np.float32)
            contours = measure.find_contours(mask, 0.5, positive_orientation='low')

            polygons = []
            for contour in contours:
                # Flip from (row, col) representation to (x, y)
                # and subtract the padding pixel
                for i in range(len(contour)):
                    row, col = contour[i]
                    contour[i] = (col - 1, row - 1)

                # Make a polygon and simplify it
                poly = Polygon(contour)
                poly = poly.simplify(1.0, preserve_topology=False)

                if (poly.area > 16): # Ignore tiny polygons
                    if (poly.geom_type == 'MultiPolygon'):
                        # if MultiPolygon, take the smallest convex Polygon containing all the points in the object
                        poly = poly.convex_hull

                    if (poly.geom_type == 'Polygon'): # Ignore if still not a Polygon (could be a line or point)
                        polygons.append(poly)
                        segmentation = np.array(poly.exterior.coords).ravel().tolist()
                        annotation['segmentation'].append(segmentation)

            if len(polygons) == 0:
                # This item doesn't have any visible polygons, ignore it
                # (This can happen if a randomly placed foreground is covered up
                #  by other foregrounds)
                continue

            # Combine the polygons to calculate the bounding box and area
            multi_poly = MultiPolygon(polygons)
            x, y, max_x, max_y = multi_poly.bounds
            self.width = max_x - x
            self.height = max_y - y
            annotation['bbox'] = (x, y, self.width, self.height)
            annotation['area'] = multi_poly.area

            # Finally, add this annotation to the list
            self.annotations.append(annotation)
Esempio n. 11
0
    def make_valid(polygon: Polygon) -> Tuple[Polygon, float]:
        """Ensures shapely.geometry.Polygon object is valid by repeated simplification"""
        tolerance = 1
        for split in range(1, len(polygon.exterior.coords) - 1):
            if polygon.is_valid or polygon.simplify(polygon.area).is_valid:
                break
            # simplification may not be possible (at all) due to ordering
            # in that case, try another starting point
            polygon = Polygon(polygon.exterior.coords[-split:] +
                              polygon.exterior.coords[:-split])
        for tolerance in range(1, int(polygon.area)):
            if polygon.is_valid:
                break
            # simplification may require a larger tolerance
            polygon = polygon.simplify(tolerance)

        a = polygon.area
        return polygon, tolerance / a if a > 0 else inf
Esempio n. 12
0
def simplify(points):
    polygon = Polygon(map(lambda x: (x["x"], x["y"]), points))
    polygon = polygon.simplify(0.05)

    return {
        "points": map(lambda x: {"x": x[0], "y": x[1]},
            polygon.exterior.coords),
        "centroid": (polygon.centroid.x, polygon.centroid.y),
        "bounds": polygon.bounds,
        "area": polygon.area
    }
Esempio n. 13
0
def get_tile_geometry(path, origin_espg, tolerance=500):
    """ Calculate the data and tile geometry for sentinel-2 tiles """

    with rasterio.open(path) as src:

        # Get tile geometry
        b = src.bounds
        tile_shape = Polygon([(b[0], b[1]), (b[2], b[1]), (b[2], b[3]),
                              (b[0], b[3]), (b[0], b[1])])
        tile_geojson = mapping(tile_shape)

        # read first band of the image
        image = src.read(1)

        # create a mask of zero values
        mask = image == 0.

        # generate shapes of the mask
        novalue_shape = shapes(image, mask=mask, transform=src.affine)

        # generate polygons using shapely
        novalue_shape = [
            Polygon(s['coordinates'][0]) for (s, v) in novalue_shape
        ]

        if novalue_shape:

            # Make sure polygons are united
            # also simplify the resulting polygon
            union = cascaded_union(novalue_shape)

            # generates a geojson
            data_shape = tile_shape.difference(union)

            # If there are multipolygons, select the largest one
            if data_shape.geom_type == 'MultiPolygon':
                areas = {p.area: i for i, p in enumerate(data_shape)}
                largest = max(areas.keys())
                data_shape = data_shape[areas[largest]]

            # if the polygon has interior rings, remove them
            if list(data_shape.interiors):
                data_shape = Polygon(data_shape.exterior.coords)

            data_shape = data_shape.simplify(tolerance,
                                             preserve_topology=False)
            data_geojson = mapping(data_shape)

        else:
            data_geojson = tile_geojson

        # convert cooridnates to degrees
        return (to_latlon(tile_geojson,
                          origin_espg), to_latlon(data_geojson, origin_espg))
Esempio n. 14
0
def reduce_complexity(outline):
    poly = Polygon(outline[0], outline[1:])
    poly = poly.simplify(0.0005)

    reduced = [[[p[0], p[1]] for p in poly.exterior.coords]]

    reduced += [[[p[0], p[1]] for p in hole.coords] for hole in poly.interiors]

    if (len(outline) > 1):
        interiors = list(poly.interiors)

    return reduced
Esempio n. 15
0
def contours2Segmentations(contours_array,
                           tolerance: int = 1.0,
                           preserve_topology: bool = False):
    segmentations = []
    polygons = []

    for contour in contours_array:
        poly = Polygon(contour)
        poly = poly.simplify(tolerance, preserve_topology=preserve_topology)
        polygons.append(poly)
        seg = np.array(poly.exterior.coords).ravel().tolist()
        segmentations.append(seg)
    return polygons, segmentations
Esempio n. 16
0
def simplify(points):
    polygon = Polygon(map(lambda x: (x["x"], x["y"]), points))
    polygon = polygon.simplify(0.05)

    return {
        "points": map(lambda x: {
            "x": x[0],
            "y": x[1]
        }, polygon.exterior.coords),
        "centroid": (polygon.centroid.x, polygon.centroid.y),
        "bounds": polygon.bounds,
        "area": polygon.area
    }
Esempio n. 17
0
def nuclei_segmentation(image,
                        compute_distance=False,
                        radius=10,
                        simp_px=None):
    # apply threshold
    logger.debug('thresholding images')
    thresh_val = filters.threshold_otsu(image)
    thresh = image >= thresh_val
    thresh = morphology.remove_small_holes(thresh)
    thresh = morphology.remove_small_objects(thresh)

    # remove artifacts connected to image border
    cleared = segmentation.clear_border(thresh)

    if len(cleared[cleared > 0]) == 0: return None, None

    if compute_distance:
        distance = distance_transform_edt(cleared)
        local_maxi = feature.peak_local_max(distance,
                                            indices=False,
                                            labels=cleared,
                                            min_distance=radius / 4,
                                            exclude_border=False)
        markers, num_features = ndi.label(local_maxi)
        if num_features == 0:
            logger.info('no nuclei found for current stack')
            return None, None

        labels = morphology.watershed(-distance,
                                      markers,
                                      watershed_line=True,
                                      mask=cleared)
    else:
        labels = cleared

    logger.info('storing nuclei features')

    # store all contours found
    contours = measure.find_contours(labels, 0.9)
    tform = tf.SimilarityTransform(rotation=math.pi / 2)

    _list = list()
    for k, contr in enumerate(contours):
        contr = tform(contr)
        contr[:, 0] *= -1
        pol = Polygon(contr)
        if simp_px is not None:
            pol = pol.simplify(simp_px, preserve_topology=True)
        _list.append({'id': k, 'boundary': pol})

    return labels, _list
Esempio n. 18
0
    def _create_annotations(self):
        # Creates annotations for each isolated mask
        self.annotations = []
        for key, mask in self.isolated_masks.items():
            annotation = dict()
            annotation['segmentation'] = []
            annotation['iscrowd'] = 0
            annotation['image_id'] = self.image_id
            if not self.category_ids.get(key):
                print(
                    f'category color not found: {key}; check for missing category or antialiasing'
                )
                continue
            annotation['category_id'] = self.category_ids[key]
            annotation['id'] = self._next_annotation_id()

            # Find contours in the isolated mask
            contours = measure.find_contours(mask,
                                             0.5,
                                             positive_orientation='low')

            polygons = []
            for contour in contours:
                # Flip from (row, col) representation to (x, y)
                # and subtract the padding pixel
                for i in range(len(contour)):
                    row, col = contour[i]
                    contour[i] = (col - 1, row - 1)

                # Make a polygon and simplify it
                poly = Polygon(contour)
                if (poly.area > 16):  # Ignore tiny polygons
                    poly = poly.simplify(1.0, preserve_topology=False)
                    polygons.append(poly)
                    segmentation = np.array(
                        poly.exterior.coords).ravel().tolist()
                    annotation['segmentation'].append(segmentation)

            if len(polygons) == 0:
                continue

            # Combine the polygons to calculate the bounding box and area
            multi_poly = MultiPolygon(polygons)
            x, y, max_x, max_y = multi_poly.bounds
            self.width = max_x - x
            self.height = max_y - y
            annotation['bbox'] = (x, y, self.width, self.height)
            annotation['area'] = multi_poly.area

            # Finally, add this annotation to the list
            self.annotations.append(annotation)
Esempio n. 19
0
def make_valid(polygon):
    for split in range(1, len(polygon.exterior.coords) - 1):
        if polygon.is_valid or polygon.simplify(polygon.area).is_valid:
            break
        # simplification may not be possible (at all) due to ordering
        # in that case, try another starting point
        polygon = Polygon(polygon.exterior.coords[-split:] +
                          polygon.exterior.coords[:-split])
    for tolerance in range(1, int(polygon.area)):
        if polygon.is_valid:
            break
        # simplification may require a larger tolerance
        polygon = polygon.simplify(tolerance)
    return polygon
Esempio n. 20
0
def make_poly(polygon_points):
    """Instantiate a Polygon from a list of point pairs, or return an error string"""
    if len(polygon_points) < 4:
        return 'has too few points'
    poly = Polygon(polygon_points)
    if POLY_TOLERANCE:
        poly = poly.simplify(POLY_TOLERANCE)
    if not poly.is_valid:
        return explain_validity(poly)
    elif poly.is_empty:
        return 'is empty'
    elif poly.bounds[0] < 0 or poly.bounds[1] < 0:
        return 'is negative'
    return poly
Esempio n. 21
0
def get_tile_geometry(path, origin_espg, tolerance=500):
    """ Calculate the data and tile geometry for sentinel-2 tiles """

    with rasterio.open(path) as src:

        # Get tile geometry
        b = src.bounds
        tile_shape = Polygon([(b[0], b[1]), (b[2], b[1]), (b[2], b[3]), (b[0], b[3]), (b[0], b[1])])
        tile_geojson = mapping(tile_shape)

        # read first band of the image
        image = src.read(1)

        # create a mask of zero values
        mask = image == 0.

        # generate shapes of the mask
        novalue_shape = shapes(image, mask=mask, transform=src.affine)

        # generate polygons using shapely
        novalue_shape = [Polygon(s['coordinates'][0]) for (s, v) in novalue_shape]

        if novalue_shape:

            # Make sure polygons are united
            # also simplify the resulting polygon
            union = cascaded_union(novalue_shape)

            # generates a geojson
            data_shape = tile_shape.difference(union)

            # If there are multipolygons, select the largest one
            if data_shape.geom_type == 'MultiPolygon':
                areas = {p.area: i for i, p in enumerate(data_shape)}
                largest = max(areas.keys())
                data_shape = data_shape[areas[largest]]

            # if the polygon has interior rings, remove them
            if list(data_shape.interiors):
                data_shape = Polygon(data_shape.exterior.coords)

            data_shape = data_shape.simplify(tolerance, preserve_topology=False)
            data_geojson = mapping(data_shape)

        else:
            data_geojson = tile_geojson

        # convert cooridnates to degrees
        return (to_latlon(tile_geojson, origin_espg), to_latlon(data_geojson, origin_espg))
def create_sub_mask_annotation(sub_mask, image_id, category_id, annotation_id,
                               is_crowd):
    # Find contours (boundary lines) around each sub-mask
    # Note: there could be multiple contours if the object
    # is partially occluded. (E.g. an elephant behind a tree)
    imgray = cv2.cvtColor(sub_mask, cv2.COLOR_BGR2GRAY)
    contours, hierarchy = cv2.findContours(imgray, cv2.RETR_TREE,
                                           cv2.CHAIN_APPROX_SIMPLE)

    # For the contours of the instances in the binary images, if its parent is background (hierarchy == 0),
    # then this contour is the mask contour, abandoning the contours whose parent is not background.
    valid_contours = []
    for k in range(len(hierarchy[0])):
        if hierarchy[0][k][3] == 0:
            contour = contours[k].reshape((len(contours[k]), 2))
            valid_contours.append(contour)

    segmentations = []
    polygons = []
    for contour in valid_contours:
        # Subtract the padding pixel
        contour = contour - 1

        # Make a polygon and simplify it
        poly = Polygon(contour)
        poly = poly.simplify(1.0, preserve_topology=True)
        polygons.append(poly)
        segmentation = np.array(poly.exterior.coords).ravel().tolist()
        segmentations.append(segmentation)

    # Combine the polygons to calculate the bounding box and area
    multi_poly = MultiPolygon(polygons)
    x, y, max_x, max_y = multi_poly.bounds
    width = max_x - x
    height = max_y - y
    bbox = (x, y, width, height)
    area = multi_poly.area

    annotation = {
        'segmentation': segmentations,
        'iscrowd': is_crowd,
        'image_id': image_id,
        'category_id': category_id,
        'id': annotation_id,
        'bbox': bbox,
        'area': area
    }

    return annotation
Esempio n. 23
0
def make_submask_annotations(sub_mask, image_id, category_id, annotation_id, is_crowd):
    # Find contours (boundary lines) around each sub-mask
    # Note: there could be multiple contours if the object
    # is partially occluded. (E.g. an elephant behind a tree)
    contours = measure.find_contours(sub_mask, 0.5, positive_orientation='low')

    # Code sourced from:
    # https://www.immersivelimit.com/create-coco-annotations-from-scratch

    segmentations = []
    polygons = []
    for contour in contours:
        # Flip from (row, col) representation to (x, y)
        # and subtract the padding pixel
        for i in range(len(contour)):
            row, col = contour[i]
            contour[i] = (col - 1, row - 1)

        # Make a polygon and simplify it
        # TODO: CHANGE THIS DEPENDING ON ACCURACY TO RESULTS
        poly = Polygon(contour)
        poly = poly.simplify(1.0, preserve_topology=False)
        polygons.append(poly)
        segmentation = np.array(poly.exterior.coords).ravel().tolist()
        segmentations.append(segmentation)

    # Combine the polygons to calculate the bounding box and area
    multi_poly = MultiPolygon(polygons)
    x, y, max_x, max_y = multi_poly.bounds
    width = max_x - x
    height = max_y - y
    bbox = (x, y, width, height)
    area = multi_poly.area

    # TODO: ADD PROPER ANNOTATIONS TO ALIGN WITH COCO STANDARDS
    # TODO: ADD SEGMENTATION SECTION FOR MULTIPLE OBJECTS IN AN IMAGE

    annotation = {
        'segmentation': segmentations,
        'iscrowd': is_crowd,
        'image_id': image_id,
        'category_id': category_id,
        'id': annotation_id,
        'bbox': bbox,
        'area': area
    }

    return annotation
Esempio n. 24
0
def create_sub_mask_annotation(sub_mask, image_id, category_id, annotation_id,
                               is_crowd):
    # Find contours (boundary lines) around each sub-mask
    # Note: there could be multiple contours if the object
    # is partially occluded. (E.g. an elephant behind a tree)
    contours = measure.find_contours(sub_mask, 0.5, positive_orientation='low')
    min_poly_filter = 10  # filter out noises
    segmentations = []
    polygons = []
    num_polys = 0
    for contour in contours:
        # Flip from (row, col) representation to (x, y)
        # and subtract the padding pixel
        for i in range(len(contour)):
            row, col = contour[i]
            contour[i] = (col - 1, row - 1)
        # Make a polygon and simplify it
        poly = Polygon(contour)
        poly = poly.simplify(1.0, preserve_topology=False)
        if (poly.exterior):
            polygons.append(poly)
            segmentation = np.array(poly.exterior.coords).ravel().tolist()
            segmentations.append(segmentation)

    # Combine the polygons to calculate the bounding box and area
    multi_poly = MultiPolygon(polygons)
    num_polys = len(multi_poly.geoms)
    # print(num_polys)
    if len(multi_poly.bounds) == 4:
        x, y, max_x, max_y = multi_poly.bounds
        width = max_x - x
        height = max_y - y
        bbox = (x, y, width, height)
        area = multi_poly.area

        annotation = {
            'segmentation': segmentations,
            'iscrowd': is_crowd,
            'image_id': image_id,
            'category_id': category_id,
            'id': annotation_id,
            'bbox': bbox,
            'area': area
        }

        return annotation, num_polys
    else:
        return None, None
def segment(points):
    # Make a polygon and simplify it
    contour = np.array(points)
    poly = Polygon(contour)
    poly = poly.simplify(1.0, preserve_topology=False)
    segmentation = np.array(poly.exterior.coords).ravel().tolist()
    x, y, max_x, max_y = poly.bounds
    width = max_x - x
    height = max_y - y
    bbox = [x, y, width, height]
    area = poly.area

    segmentation = [int(x) for x in segmentation]
    bbox = [int(x) for x in bbox]
    segm = {'segmentation': [segmentation], 'bbox': bbox, 'area': int(area)}
    return segm
    def _create_sub_mask_annotation(self, sub_mask, image_id, category_id,
                                    annotation_id):
        """
        create COCO.PANOPTIC format annotation(i.e. no contour information here)
        args:
            sub_mask: dict, the submask generated from self._create_sub_masks
            image_id: int, the id of the image
            category_id: int, the id of the category of this piece of submask
            annotation_id: int, the id of this submask
        """
        # Find contours (boundary lines) around each sub-mask
        # Note: there could be multiple contours if the object
        # is partially occluded. (E.g. an elephant behind a tree)
        contours = measure.find_contours(sub_mask,
                                         0.5,
                                         positive_orientation='low')

        segmentations = []
        polygons = []
        for contour in contours:
            # Flip from (row, col) representation to (x, y)
            # and subtract the padding pixel
            for i in range(len(contour)):
                row, col = contour[i]
                contour[i] = (col - 1, row - 1)

            # Make a polygon and simplify it
            poly = Polygon(contour)
            poly = poly.simplify(1.0, preserve_topology=False)
            polygons.append(poly)

        # Combine the polygons to calculate the bounding box and area
        multi_poly = MultiPolygon(polygons)
        x, y, max_x, max_y = multi_poly.bounds
        width = max_x - x
        height = max_y - y

        annotation = {
            'iscrowd': 0,
            'category_id': category_id,
            'id': annotation_id,
            'bbox': (int(x), int(y), int(width), int(height)),
            'area': int(multi_poly.area)
        }
        return annotation
Esempio n. 27
0
def create_sub_mask_annotation(sub_mask, class_id, label_img):

    ###################
    # contours
    ###################

    # Find contours (boundary lines) around each sub-mask
    # Note: there could be multiple contours if the object
    # is partially occluded. (E.g. an elephant behind a tree)
    contours = measure.find_contours(np.array(sub_mask),
                                     0.5,
                                     positive_orientation='low')

    polygons = []
    x_list, y_list = [], []
    for idx, contour in enumerate(contours):
        # Flip from (row, col) representation to (x, y)
        # and subtract the padding pixel
        for i in range(len(contour)):
            row, col = contour[i]
            contour[i] = (col - 1, row - 1)

        # Make a polygon and simplify it
        poly = Polygon(contour)
        poly = poly.simplify(1.0, preserve_topology=False)
        polygons.append(poly)
        # segmentation = np.array(poly.exterior.coords, dtype=np.int).ravel().tolist()
        # segmentations.append(segmentation

        coords = np.array(poly.exterior.coords, dtype=np.int)

        if coords.size != 0:
            x, y = coords[:, 0], coords[:, 1]
            x_list.extend(x.tolist())
            y_list.extend(y.tolist())

    region = {}
    region['region_attributes'] = {}
    region['shape_attributes'] = {}
    region['shape_attributes']["name"] = "polygon"
    region['shape_attributes']["all_points_x"] = x_list
    region['shape_attributes']["all_points_y"] = y_list
    region['shape_attributes']["class_id"] = class_id

    data[obj_name]['regions'][np.str(class_id)] = region
Esempio n. 28
0
def generate_polygon(mask_image, min_area=20):
    """convert the mask to polygon

    Args:
        mask_image (np.array): input mask image
        min_area (int, optional): threshold of area, when area < min_area, filter this object. Defaults to 20.

    Returns:
        list: list of polygons
    """
    contours = measure.find_contours(mask_image,
                                     0.5,
                                     positive_orientation='low')

    polygons = []
    for contour in contours:
        for i in range(len(contour)):
            row, col = contour[i]
            contour[i] = (col - 1, row - 1)

        if contour.shape[0] < 3:
            continue

        poly = Polygon(contour)
        if poly.area < min_area:
            continue
        poly = poly.simplify(1.0, preserve_topology=False)
        if poly.geom_type == 'MultiPolygon':
            for poly_ in poly:
                if poly_.area < min_area:
                    continue
                valid_flag = aitool.single_valid_polygon(poly_)
                if not valid_flag:
                    continue
                polygons.append(poly_)
        elif poly.geom_type == 'Polygon':
            valid_flag = aitool.single_valid_polygon(poly)
            if not valid_flag:
                continue
            polygons.append(poly)
        else:
            continue

    return polygons
Esempio n. 29
0
def create_sub_mask_annotation(sub_mask, image_id, category_id, annotation_id,
                               is_crowd):
    # Find contours (boundary lines) around each sub-mask
    # Note: there could be multiple contours if the object
    # is partially occluded. (E.g. an elephant behind a tree)
    contours = measure.find_contours(sub_mask, 0.5, positive_orientation='low')

    segmentations = []
    polygons = []
    for contour in contours:
        # Flip from (row, col) representation to (x, y)
        # and subtract the padding pixel
        for i in range(len(contour)):
            row, col = contour[i]
            contour[i] = (col - 1, row - 1)

        # Make a polygon and simplify it
        poly = Polygon(contour)
        poly = poly.simplify(1.0, preserve_topology=False)
        polygons.append(poly)
        segmentation = np.array(poly.exterior.coords).ravel().tolist()
        if len(segmentation) > 0:
            segmentations.append(segmentation)

    # Combine the polygons to calculate the bounding box and area
    multi_poly = MultiPolygon(polygons)
    x, y, max_x, max_y = multi_poly.bounds
    width = max_x - x
    height = max_y - y
    bbox = (x, y, width, height)
    area = multi_poly.area

    annotation = {
        'segmentation': segmentations,
        'iscrowd': is_crowd,
        'image_id': image_id,  # both are coming from the k enumerate
        'category_id': category_id,
        'id':
        image_id,  # both are coming from the k enumerate TODO this fixed an issue for what cocovis_custom.py is expecting and that's native coco tools so the original poster was wrong (was using custom display function now makes sense why author just didn't kow about coco tools)
        'bbox': bbox,
        'area': area
    }

    return annotation
Esempio n. 30
0
def get_polygons(folder, currency):

    for apath in tqdm(sorted(glob.glob('{}/{}/images/*.png'.format(folder,currency)))):
        name = pathlib.Path(apath).stem

        img = cv2.imread('{}'.format(apath), 0)
        img2 = cv2.imread('{}'.format(apath), cv2.IMREAD_UNCHANGED)

        img = cv2.medianBlur(img, 5)
        # contours, hierarchy =   cv2.findContours(img.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

        # find contours in the thresholded image
        cnts = cv2.findContours(img.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        cnts = imutils.grab_contours(cnts)

        # cnts = imutils.grab_contours(contours)
        cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:10]

        cnt = cnts[0]
        # print(cnt.shape)
        points, _, _ = cnt.shape

        ncnt = np.reshape(cnt, (points, 2))

        polygon = Polygon(ncnt)

        simplepolygon = polygon.simplify(1.0, preserve_topology=False)

        if simplepolygon.type == 'MultiPolygon':
            points = []
            for polygon in simplepolygon:
                subpoints = list(polygon.exterior.coords)
                for subpoint in subpoints:
                    points.append(subpoint)

        elif simplepolygon.type == 'Polygon':
            points = list(simplepolygon.exterior.coords)

        label = {
            'points' : points
        }

        with open('{}/{}/labels/{}.json'.format(folder,currency,name), 'w') as f:
            json.dump(label, f)
Esempio n. 31
0
def shape_to_polygons(shape):
    def inside(pt):
        return hypot(*pt) <= R
    def adjust(pt):
        x, y = pt
        a = atan2(y, x)
        x = cos(a) * R
        y = sin(a) * R
        return (x, y)
    result = []
    parts = list(shape.parts) + [len(shape.points)]
    for i1, i2 in zip(parts, parts[1:]):
        points = map(tuple, shape.points[i1:i2])
        points = map(laea, points)
        points = filter(None, points)
        p = Polygon(points)
        p = p.buffer(-0.01)
        p = p.buffer(0.01)
        p = p.simplify()
        if p.is_empty:
            continue
        if isinstance(p, Polygon):
            ps = [p]
        else:
            ps = p.geoms
        for p in ps:
            points = list(p.exterior.coords)
            print points
            for a, b in zip(points, points[1:]):
                # if not a[-1] and not b[-1]:
                #     continue
                a = a[:2]
                b = b[:2]
                in1 = inside(a)
                in2 = inside(b)
                if not in1 and not in2:
                    continue
                if in1 and not in2:
                    b = adjust(b)
                if in2 and not in1:
                    a = adjust(a)
                result.append(LineString([a, b]))
    return result
    def _create_sub_mask_annotation(self, sub_mask, image_id, category_id):
        # Find contours (boundary lines) around each sub-mask
        # Note: there could be multiple contours if the object
        # is partially occluded. (E.g. an elephant behind a tree)
        contours = measure.find_contours(sub_mask,
                                         0.5,
                                         positive_orientation='low')

        segmentations = []
        polygons = []
        for contour in contours:
            # Flip from (row, col) representation to (x, y)
            # and subtract the padding pixel
            for i in range(len(contour)):
                row, col = contour[i]
                contour[i] = (col - 1, row - 1)

            # Make a polygon and simplify it
            poly = Polygon(contour)
            poly = poly.simplify(1.0, preserve_topology=False)
            polygons.append(poly)
            segmentation = np.array(poly.exterior.coords).ravel().tolist()
            if len(segmentation) >= 6 and len(segmentation) % 2 == 0:
                segmentations.append(segmentation)

        # Combine the polygons to calculate the bounding box and area
        multi_poly = MultiPolygon(polygons)
        x, y, max_x, max_y = multi_poly.bounds
        bbox = [
            max(0, math.floor(x)),
            max(0, math.floor(y)),
            math.ceil(max_x),
            math.ceil(max_y)
        ]
        annotation = {
            'bbox': bbox,
            'bbox_mode': BoxMode.XYXY_ABS,
            'segmentation': segmentations,
            'category_id': category_id,
        }

        return annotation
def save_geojson(ordered_list, image_src, filename):
    rasterio_object = rasterio.open(image_src)
    features = []

    def pixelcoord_to_geocoord(pixel_coordinate):
        return (rasterio_object.transform * pixel_coordinate)

    for line in ordered_list:
        tuple_of_tuples = tuple((point[1], point[0]) for point in line)
        Lstring = Polygon(list(map(pixelcoord_to_geocoord, tuple_of_tuples)))
        features.append(Feature(geometry=Lstring.simplify(0.00001)))
    crs = {
        "type": "name",
        "properties": {
            "name": "{}".format(str(rasterio_object.crs))
        }
    }
    feature_collection = FeatureCollection(features, crs=crs)
    with open(filename, 'w') as f:
        dump(feature_collection, f)