예제 #1
0
def crop(im, bw, split=True):
    im_h, im_w = im.shape[:2]

    all_letters = algorithm.all_letters(bw)
    AH = algorithm.dominant_char_height(bw, letters=all_letters)
    letters = algorithm.filter_size(AH, bw, letters=all_letters)
    all_lines = collate.collate_lines(AH, letters)
    combined = algorithm.combine_underlined(AH, bw, all_lines, all_letters)
    lines = algorithm.remove_stroke_outliers(bw, combined)

    if not lines:
        print('WARNING: no lines in image.')
        return AH, []

    lines = filter_position(AH, bw, lines, split)
    lines = [
        line for line in lines if not np.all(line.crop().apply(bw) == 255)
    ]

    if not lines:
        print('WARNING: eliminated all lines.')
        return AH, []

    if split and im_w > im_h:  # two pages
        line_sets = split_lines(lines)
    else:
        line_sets = [lines]

    return AH, line_sets
예제 #2
0
def get_AH_lines(im):
    all_letters = algorithm.all_letters(im)
    # AH == average character height
    AH = algorithm.dominant_char_height(im, letters=all_letters)
    if lib.debug: print('AH =', AH)
    letters = algorithm.filter_size(AH, im, letters=all_letters)
    all_lines = collate.collate_lines(AH, letters)
    # From up to down
    all_lines.sort(key=lambda l: l[0].y)

    combined = algorithm.combine_underlined(AH, im, all_lines, all_letters)

    filtered = algorithm.remove_stroke_outliers(im, combined, k=2.0)
    # filtered = algorithm.filter_spacing_deviation(im, AH, filtered)

    lines = remove_outliers(im, AH, filtered)
    # lines = combined

    # if lib.debug:
    #     debug = cv2.cvtColor(bw, cv2.COLOR_GRAY2BGR)
    #     for l in all_lines:
    #         for l1, l2 in zip(l, l[1:]):
    #             cv2.line(debug, tuple(l1.base_point().astype(int)),
    #                     tuple(l2.base_point().astype(int)), RED, 2)
    #     lib.debug_imwrite('all_lines.png', debug)

    return AH, lines, all_lines
예제 #3
0
def ntirogiannis2014(im):
    lib.debug_prefix.append('ng2014')

    debug_imwrite('input.png', im)
    im_h, _ = im.shape
    N, BG_prime = ng2014_normalize(im)
    O = otsu(N)

    debug_imwrite('O.png', O)
    letters = algorithm.all_letters(O)
    height_map = HeightMap(letters)

    ratio_sum = 0
    for h in range(1, height_map.max_height() + 1):
        if len(height_map[h]) == 0: continue
        ratio_sum += height_map.ratio_pixels(h) / height_map.ratio_components(
            h)
        if ratio_sum > 1:
            break

    min_height = h

    if lib.debug: print('Accept components only >= height', h)

    OP = O.copy()
    for h in range(1, min_height):
        for letter in height_map[h]:
            sliced = letter.slice(OP)
            np.place(sliced, letter.raster(), 255)
    debug_imwrite('OP.png', OP)

    strokes = fast_stroke_width(OP)
    debug_imwrite('strokes.png', normalize_u8(strokes.clip(0, 10)))
    SW = int(round(strokes.sum() / np.count_nonzero(strokes)))
    if lib.debug: print('SW =', SW)

    S = skeleton(OP)
    debug_imwrite('S.png', S)

    S_inv = ~S
    # S_inv_32 = S_inv.astype(np.int32)

    # FG_count = np.count_nonzero(S_inv)
    FG_pos = im[S_inv.astype(bool)]
    FG_avg = FG_pos.mean()
    FG_std = FG_pos.std()
    # FG = (S_inv & im).astype(np.int32)
    # FG_avg = FG.sum() / float(FG_count)
    # FG_std = np.sqrt(((S_inv_32 & (FG - FG_avg)) ** 2).sum() / float(FG_count))
    if lib.debug: print('FG:', FG_avg, FG_std)

    BG_avg = BG_prime.mean()
    BG_std = BG_prime.std()
    if lib.debug: print('BG:', BG_avg, BG_std)

    if FG_avg + FG_std != 0:
        C = -50 * np.log10((FG_avg + FG_std) / (BG_avg - BG_std))
        k = -0.2 - 0.1 * C / 10
    else:  # This is the extreme case when the FG is 100% black, check the article explaination page before equation 5
        C = -50 * np.log10((2.5) / (BG_avg - BG_std))
        k = -0.2 - 0.1 * C / 10

    if lib.debug: print('niblack:', C, k)
    local = niblack(N, window_size=(2 * SW) | 1, k=k)
    debug_imwrite('local.png', local)
    local_CCs = algorithm.all_letters(local)

    # NB: paper uses OP here, which results in neglecting all small components.
    O_inv = ~O
    O_inv_32 = O_inv.astype(np.int8,
                            copy=False).astype(np.int32).astype(np.uint32,
                                                                copy=False)
    label_map_O_inv = O_inv_32 & local_CCs[0].label_map
    CO_inv = np.zeros(im.shape, dtype=np.uint8)
    for cc in local_CCs:
        if np.count_nonzero(cc.slice(label_map_O_inv) == cc.label) / float(
                cc.area()) >= C / 100:
            CO_sliced = cc.slice(CO_inv)
            np.place(CO_sliced, cc.raster(), 255)

    CO = ~CO_inv
    debug_imwrite('CO.png', CO)

    CO_inv_dilated = cv2.dilate(CO_inv, rect33)
    FB = ~(CO_inv | ((~O) & CO_inv_dilated))
    debug_imwrite('FB.png', FB)

    lib.debug_prefix.pop()

    return FB