ocrd_cis/ocropy/common.py
def compute_line_seeds(binary,bottom,top,colseps,scale,
                       threshold=0.2,
                       # use larger scale so broken/blackletter fonts with their large capitals
                       # are not cut into two lines or joined at ascenders/decsenders:
                       vscale=2.0,
                       # more robust top/bottom transition rules:
                       robust=True):
    """Based on gradient maps, compute candidates for baselines and xheights.
    Then, mark the regions between the two as a line seed. Finally, label
    all connected regions (starting with 1, with 0 as background)."""
    vrange = odd(vscale*scale)
    # find (more or less) horizontal lines along the maximum gradient,
    # where it is above (squared) threshold and not crossing columns:
    bmarked = filters.maximum_filter(
        # mark position of maximum gradient every `vrange` pixels:
        bottom==filters.maximum_filter(bottom,(vrange,0)),
        # blur by 2 pixels, then retain only large gradients:
        (2,2)) * (bottom>threshold*np.amax(bottom)*threshold) *(1-colseps)
    tmarked = filters.maximum_filter(
        # mark position of maximum gradient every `vrange` pixels:
        top==filters.maximum_filter(top,(vrange,0)),
        # blur by 2 pixels, then retain only large gradients:
        (2,2)) * (top>threshold*np.amax(top)*threshold/2) *(1-colseps)
    if robust:
        bmarked = filters.maximum_filter(bmarked,(1,odd(scale))) *(1-colseps)
    tmarked = filters.maximum_filter(tmarked,(1,odd(scale))) *(1-colseps)
    ##tmarked = filters.maximum_filter(tmarked,(1,20))
    seeds = np.zeros(binary.shape,'i')
    delta = max(3,int(scale))
    for x in range(bmarked.shape[1]):
        # sort both kinds of mark from bottom to top (i.e. inverse y position)
        transitions = sorted([(y,1) for y in psegutils.find(bmarked[:,x])] +
                             [(y,0) for y in psegutils.find(tmarked[:,x])])[::-1]
        if robust:
            l = 0
            while l < len(transitions):
                y0, s0 = transitions[l]
                if s0: # bmarked?
                    y1 = max(0, y0 - delta) # project seed from bottom
                    if l+1 < len(transitions) and transitions[l+1][0] > y1:
                        y1 = transitions[l+1][0] # fill with seed to next mark
                    seeds[y1:y0, x] = 1
                else: # tmarked?
                    y1 = y0 + delta # project seed from top
                    if l > 0 and transitions[l-1][0] < y1:
                        y1 = transitions[l-1][0] # fill with seed to next mark
                    seeds[y0:y1, x] = 1
                l += 1
        else:
            transitions += [(0,0)]
            for l in range(len(transitions)-1):
                y0,s0 = transitions[l]
                if s0==0:
                    continue # keep looking for next bottom
                seeds[y0-delta:y0,x] = 1 # project seed from bottom
                y1,s1 = transitions[l+1]
                if s1==0 and (y0-y1)<5*scale: # why 5?
                    # consistent next top?
                    seeds[y1:y0,x] = 1 # fill with seed completely
    DSAVE("lineseeds+bmarked+tmarked",[0.4*seeds+0.6*binary, bmarked, tmarked])
    if robust:
        # try to separate lines that already touch:
        seeds = morph.rb_opening(seeds, (odd(scale/2), odd(scale)))
    else:
        # this will smear into neighbouring line components at as/descenders
        # (but horizontal consistency is now achieved by hmerge and spread):
        seeds = filters.maximum_filter(seeds,(1,odd(1+scale)))
    DSAVE("lineseeds", seeds+0.6*binary)
    # interrupt by column separators before labelling:
    seeds = seeds*(1-colseps)
    DSAVE("lineseeds-colseps", seeds+0.6*binary)
    seeds, nlabels = morph.label(seeds)
    DSAVE("lineseeds_labelled", [seeds,binary])
    return seeds
Based on gradient maps, compute candidates for baselines and xheights.
    Then, mark the regions between the two as a line seed. Finally, label
    all connected regions (starting with 1, with 0 as background).
Based on gradient maps, compute candidates for baselines and xheights.
Then, mark the regions between the two as a line seed. Finally, label
all connected regions (starting with 1, with 0 as background).
Based on gradient maps compute candidates for baselines and xheights . Then mark the regions between the two as a line seed . Finally label all connected regions ( starting with 1 with 0 as background ) .
def compute_line_seeds(binary,bottom,top,colseps,scale,
                       threshold=0.2,
                       vscale=2.0,
                       robust=True):
    vrange = odd(vscale*scale)
    bmarked = filters.maximum_filter(
        bottom==filters.maximum_filter(bottom,(vrange,0)),
        (2,2)) * (bottom>threshold*np.amax(bottom)*threshold) *(1-colseps)
    tmarked = filters.maximum_filter(
        top==filters.maximum_filter(top,(vrange,0)),
        (2,2)) * (top>threshold*np.amax(top)*threshold/2) *(1-colseps)
    if robust:
        bmarked = filters.maximum_filter(bmarked,(1,odd(scale))) *(1-colseps)
    tmarked = filters.maximum_filter(tmarked,(1,odd(scale))) *(1-colseps)
    seeds = np.zeros(binary.shape,'i')
    delta = max(3,int(scale))
    for x in range(bmarked.shape[1]):
        transitions = sorted([(y,1) for y in psegutils.find(bmarked[:,x])] +
                             [(y,0) for y in psegutils.find(tmarked[:,x])])[::-1]
        if robust:
            l = 0
            while l < len(transitions):
                y0, s0 = transitions[l]
                if s0: 
                    y1 = max(0, y0 - delta) 
                    if l+1 < len(transitions) and transitions[l+1][0] > y1:
                        y1 = transitions[l+1][0] 
                    seeds[y1:y0, x] = 1
                else: 
                    y1 = y0 + delta 
                    if l > 0 and transitions[l-1][0] < y1:
                        y1 = transitions[l-1][0] 
                    seeds[y0:y1, x] = 1
                l += 1
        else:
            transitions += [(0,0)]
            for l in range(len(transitions)-1):
                y0,s0 = transitions[l]
                if s0==0:
                    continue 
                seeds[y0-delta:y0,x] = 1 
                y1,s1 = transitions[l+1]
                if s1==0 and (y0-y1)<5*scale: 
                    seeds[y1:y0,x] = 1 
    DSAVE("lineseeds+bmarked+tmarked",[0.4*seeds+0.6*binary, bmarked, tmarked])
    if robust:
        seeds = morph.rb_opening(seeds, (odd(scale/2), odd(scale)))
    else:
        seeds = filters.maximum_filter(seeds,(1,odd(1+scale)))
    DSAVE("lineseeds", seeds+0.6*binary)
    seeds = seeds*(1-colseps)
    DSAVE("lineseeds-colseps", seeds+0.6*binary)
    seeds, nlabels = morph.label(seeds)
    DSAVE("lineseeds_labelled", [seeds,binary])
    return seeds
def compute_line_seeds ( binary , bottom , top , colseps , scale , threshold = 0.2 , vscale = 2.0 , robust = True ) : vrange = odd ( vscale * scale ) bmarked = filters . maximum_filter ( bottom == filters . maximum_filter ( bottom , ( vrange , 0 ) ) , ( 2 , 2 ) ) * ( bottom > threshold * np . amax ( bottom ) * threshold ) * ( 1 - colseps ) tmarked = filters . maximum_filter ( top == filters . maximum_filter ( top , ( vrange , 0 ) ) , ( 2 , 2 ) ) * ( top > threshold * np . amax ( top ) * threshold / 2 ) * ( 1 - colseps ) if robust : bmarked = filters . maximum_filter ( bmarked , ( 1 , odd ( scale ) ) ) * ( 1 - colseps ) tmarked = filters . maximum_filter ( tmarked , ( 1 , odd ( scale ) ) ) * ( 1 - colseps ) seeds = np . zeros ( binary . shape , 'i' ) delta = max ( 3 , int ( scale ) ) for x in range ( bmarked . shape [ 1 ] ) : transitions = sorted ( [ ( y , 1 ) for y in psegutils . find ( bmarked [ : , x ] ) ] + [ ( y , 0 ) for y in psegutils . find ( tmarked [ : , x ] ) ] ) [ : : - 1 ] if robust : l = 0 while l < len ( transitions ) : y0 , s0 = transitions [ l ] if s0 : y1 = max ( 0 , y0 - delta ) if l + 1 < len ( transitions ) and transitions [ l + 1 ] [ 0 ] > y1 : y1 = transitions [ l + 1 ] [ 0 ] seeds [ y1 : y0 , x ] = 1 else : y1 = y0 + delta if l > 0 and transitions [ l - 1 ] [ 0 ] < y1 : y1 = transitions [ l - 1 ] [ 0 ] seeds [ y0 : y1 , x ] = 1 l += 1 else : transitions += [ ( 0 , 0 ) ] for l in range ( len ( transitions ) - 1 ) : y0 , s0 = transitions [ l ] if s0 == 0 : continue seeds [ y0 - delta : y0 , x ] = 1 y1 , s1 = transitions [ l + 1 ] if s1 == 0 and ( y0 - y1 ) < 5 * scale : seeds [ y1 : y0 , x ] = 1 DSAVE ( "lineseeds+bmarked+tmarked" , [ 0.4 * seeds + 0.6 * binary , bmarked , tmarked ] ) if robust : seeds = morph . rb_opening ( seeds , ( odd ( scale / 2 ) , odd ( scale ) ) ) else : seeds = filters . maximum_filter ( seeds , ( 1 , odd ( 1 + scale ) ) ) DSAVE ( "lineseeds" , seeds + 0.6 * binary ) seeds = seeds * ( 1 - colseps ) DSAVE ( "lineseeds-colseps" , seeds + 0.6 * binary ) seeds , nlabels = morph . label ( seeds ) DSAVE ( "lineseeds_labelled" , [ seeds , binary ] ) return seeds
Based on gradient maps, compute candidates for baselines and xheights.
Based on gradient maps compute candidates for baselines and xheights .
# use larger scale so broken/blackletter fonts with their large capitals # are not cut into two lines or joined at ascenders/decsenders: # more robust top/bottom transition rules: """Based on gradient maps, compute candidates for baselines and xheights.
    Then, mark the regions between the two as a line seed. Finally, label
    all connected regions (starting with 1, with 0 as background).""" # find (more or less) horizontal lines along the maximum gradient, # where it is above (squared) threshold and not crossing columns: # mark position of maximum gradient every `vrange` pixels: # blur by 2 pixels, then retain only large gradients: # mark position of maximum gradient every `vrange` pixels: # blur by 2 pixels, then retain only large gradients: ##tmarked = filters.maximum_filter(tmarked,(1,20)) # sort both kinds of mark from bottom to top (i.e. inverse y position) # bmarked? # project seed from bottom # fill with seed to next mark # tmarked? # project seed from top # fill with seed to next mark # keep looking for next bottom # project seed from bottom # why 5? # consistent next top? # fill with seed completely # try to separate lines that already touch: # this will smear into neighbouring line components at as/descenders # (but horizontal consistency is now achieved by hmerge and spread): # interrupt by column separators before labelling:
binary
bottom
top
colseps
scale
threshold
vscale
robust