ocrd_cis/ocropy/segment.py
def masks2polygons(bg_labels, fg_bin, name, min_area=None, simplify=False):
    """Convert label masks into polygon coordinates.

    Given a Numpy array of background labels ``bg_labels``,
    and a Numpy array of the foreground ``fg_bin``,
    iterate through all labels (except zero and those labels
    which do not correspond to any foreground at all) to find
    their outer contours. Each contour part which is not too
    small and gives a (simplified) polygon of at least 4 points
    becomes a polygon. (Thus, labels can be split into multiple
    polygons.)

    Return these polygons as a list of label, polygon tuples.
    """
    LOG = getLogger('processor.OcropySegment')
    results = list()
    for label in np.unique(bg_labels):
        if not label:
            # ignore if background
            continue
        bg_mask = np.array(bg_labels == label, np.uint8)
        if not np.count_nonzero(bg_mask * fg_bin):
            # ignore if missing foreground
            LOG.debug('skipping label %d in %s due to empty fg',
                      label, name)
            continue
        # simplify to convex hull
        if simplify:
            bg_mask = convex_hull_image(bg_mask).astype(np.uint8)
        # find outer contour (parts):
        contours, _ = cv2.findContours(bg_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        # determine areas of parts:
        areas = [cv2.contourArea(contour) for contour in contours]
        total_area = sum(areas)
        if not total_area:
            # ignore if too small
            continue
        # sort contours in reading order
        contour_labels = np.zeros_like(bg_mask, np.uint8)
        for i, contour in enumerate(contours):
            cv2.drawContours(contour_labels, contours[i:i+1], -1, i+1, cv2.FILLED)
        order = np.argsort(morph.reading_order(contour_labels)[1:])
        # convert to polygons
        for i in order:
            contour = contours[i]
            area = areas[i]
            if min_area and area < min_area and area / total_area < 0.1:
                LOG.warning('Label %d contour %d is too small (%d/%d) in %s',
                            label, i, area, total_area, name)
                continue
            # simplify shape:
            # can produce invalid (self-intersecting) polygons:
            #polygon = cv2.approxPolyDP(contour, 2, False)[:, 0, ::] # already ordered x,y
            polygon = contour[:, 0, ::] # already ordered x,y
            # simplify and validate:
            polygon = Polygon(polygon)
            for tolerance in range(2, int(area)):
                polygon = polygon.simplify(tolerance)
                if polygon.is_valid:
                    break
            polygon = polygon.exterior.coords[:-1] # keep open
            if len(polygon) < 4:
                LOG.warning('Label %d contour %d has less than 4 points for %s',
                            label, i, name)
                continue
            results.append((label, polygon))
    return results
Convert label masks into polygon coordinates.

    Given a Numpy array of background labels ``bg_labels``,
    and a Numpy array of the foreground ``fg_bin``,
    iterate through all labels (except zero and those labels
    which do not correspond to any foreground at all) to find
    their outer contours. Each contour part which is not too
    small and gives a (simplified) polygon of at least 4 points
    becomes a polygon. (Thus, labels can be split into multiple
    polygons.)

    Return these polygons as a list of label, polygon tuples.
    
Convert label masks into polygon coordinates.

Return these polygons as a list of label, polygon tuples.
Convert label masks into polygon coordinates . Return these polygons as a list of label polygon tuples .
def masks2polygons(bg_labels, fg_bin, name, min_area=None, simplify=False):
    LOG = getLogger('processor.OcropySegment')
    results = list()
    for label in np.unique(bg_labels):
        if not label:
            continue
        bg_mask = np.array(bg_labels == label, np.uint8)
        if not np.count_nonzero(bg_mask * fg_bin):
            LOG.debug('skipping label %d in %s due to empty fg',
                      label, name)
            continue
        if simplify:
            bg_mask = convex_hull_image(bg_mask).astype(np.uint8)
        contours, _ = cv2.findContours(bg_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        areas = [cv2.contourArea(contour) for contour in contours]
        total_area = sum(areas)
        if not total_area:
            continue
        contour_labels = np.zeros_like(bg_mask, np.uint8)
        for i, contour in enumerate(contours):
            cv2.drawContours(contour_labels, contours[i:i+1], -1, i+1, cv2.FILLED)
        order = np.argsort(morph.reading_order(contour_labels)[1:])
        for i in order:
            contour = contours[i]
            area = areas[i]
            if min_area and area < min_area and area / total_area < 0.1:
                LOG.warning('Label %d contour %d is too small (%d/%d) in %s',
                            label, i, area, total_area, name)
                continue
            polygon = contour[:, 0, ::] 
            polygon = Polygon(polygon)
            for tolerance in range(2, int(area)):
                polygon = polygon.simplify(tolerance)
                if polygon.is_valid:
                    break
            polygon = polygon.exterior.coords[:-1] 
            if len(polygon) < 4:
                LOG.warning('Label %d contour %d has less than 4 points for %s',
                            label, i, name)
                continue
            results.append((label, polygon))
    return results
def masks2polygons ( bg_labels , fg_bin , name , min_area = None , simplify = False ) : LOG = getLogger ( 'processor.OcropySegment' ) results = list ( ) for label in np . unique ( bg_labels ) : if not label : continue bg_mask = np . array ( bg_labels == label , np . uint8 ) if not np . count_nonzero ( bg_mask * fg_bin ) : LOG . debug ( 'skipping label %d in %s due to empty fg' , label , name ) continue if simplify : bg_mask = convex_hull_image ( bg_mask ) . astype ( np . uint8 ) contours , _ = cv2 . findContours ( bg_mask , cv2 . RETR_EXTERNAL , cv2 . CHAIN_APPROX_SIMPLE ) areas = [ cv2 . contourArea ( contour ) for contour in contours ] total_area = sum ( areas ) if not total_area : continue contour_labels = np . zeros_like ( bg_mask , np . uint8 ) for i , contour in enumerate ( contours ) : cv2 . drawContours ( contour_labels , contours [ i : i + 1 ] , - 1 , i + 1 , cv2 . FILLED ) order = np . argsort ( morph . reading_order ( contour_labels ) [ 1 : ] ) for i in order : contour = contours [ i ] area = areas [ i ] if min_area and area < min_area and area / total_area < 0.1 : LOG . warning ( 'Label %d contour %d is too small (%d/%d) in %s' , label , i , area , total_area , name ) continue polygon = contour [ : , 0 , : : ] polygon = Polygon ( polygon ) for tolerance in range ( 2 , int ( area ) ) : polygon = polygon . simplify ( tolerance ) if polygon . is_valid : break polygon = polygon . exterior . coords [ : - 1 ] if len ( polygon ) < 4 : LOG . warning ( 'Label %d contour %d has less than 4 points for %s' , label , i , name ) continue results . append ( ( label , polygon ) ) return results
Convert label masks into polygon coordinates.
Convert label masks into polygon coordinates .
"""Convert label masks into polygon coordinates.

    Given a Numpy array of background labels ``bg_labels``,
    and a Numpy array of the foreground ``fg_bin``,
    iterate through all labels (except zero and those labels
    which do not correspond to any foreground at all) to find
    their outer contours. Each contour part which is not too
    small and gives a (simplified) polygon of at least 4 points
    becomes a polygon. (Thus, labels can be split into multiple
    polygons.)

    Return these polygons as a list of label, polygon tuples.
    """ # ignore if background # ignore if missing foreground # simplify to convex hull # find outer contour (parts): # determine areas of parts: # ignore if too small # sort contours in reading order # convert to polygons # simplify shape: # can produce invalid (self-intersecting) polygons: #polygon = cv2.approxPolyDP(contour, 2, False)[:, 0, ::] # already ordered x,y # already ordered x,y # simplify and validate: # keep open
bg_labels
fg_bin
name
min_area
simplify