Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

split functions from nlbin #244

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 76 additions & 40 deletions ocropus-nlbin
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,86 @@ def dshow(image,info):
if args.debug<=0: return
ion(); gray(); imshow(image); title(info); ginput(1,args.debug)


def normalize(raw):
''' perform image normalization '''
image = raw-amin(raw)
if amax(image)==amin(image):
print_info("# image is empty: %s" % (fname))
return None
image /= amax(image)
return image


def estimate_local_whitelevel(image, zoom=0.5, perc=80, range=20, debug=0):
'''flatten it by estimating the local whitelevel
zoom for page background estimation, smaller=faster, default: %(default)s
percentage for filters, default: %(default)s
range for filters, default: %(default)s
'''
m = interpolation.zoom(image,zoom)
m = filters.percentile_filter(m,perc,size=(range,2))
m = filters.percentile_filter(m,perc,size=(2,range))
m = interpolation.zoom(m,1.0/zoom)
if debug>0: clf(); imshow(m,vmin=0,vmax=1); ginput(1,debug)
w,h = minimum(array(image.shape),array(m.shape))
flat = clip(image[:w,:h]-m[:w,:h]+1,0,1)
if debug>0: clf(); imshow(flat,vmin=0,vmax=1); ginput(1,debug)
return flat


def estimate_skew(flat, bignore=0.1, maxskew=2, skewsteps=8):
''' estimate skew angle and rotate'''
d0,d1 = flat.shape
o0,o1 = int(bignore*d0),int(bignore*d1) # border ignore
flat = amax(flat)-flat
flat -= amin(flat)
est = flat[o0:d0-o0,o1:d1-o1]
ma = maxskew
ms = int(2*maxskew*skewsteps)
# print(linspace(-ma,ma,ms+1))
angle = estimate_skew_angle(est,linspace(-ma,ma,ms+1))
flat = interpolation.rotate(flat,angle,mode='constant',reshape=0)
flat = amax(flat)-flat
return flat, angle



def estimate_thresholds(flat, bignore=0.1, escale=1.0, lo=5, hi=90, debug=0):
'''# estimate low and high thresholds
ignore this much of the border for threshold estimation, default: %(default)s
scale for estimating a mask over the text region, default: %(default)s
lo percentile for black estimation, default: %(default)s
hi percentile for white estimation, default: %(default)s
'''
d0,d1 = flat.shape
o0,o1 = int(bignore*d0),int(bignore*d1)
est = flat[o0:d0-o0,o1:d1-o1]
if escale>0:
# by default, we use only regions that contain
# significant variance; this makes the percentile
# based low and high estimates more reliable
e = escale
v = est-filters.gaussian_filter(est,e*20.0)
v = filters.gaussian_filter(v**2,e*20.0)**0.5
v = (v>0.3*amax(v))
v = morphology.binary_dilation(v,structure=ones((int(e*50),1)))
v = morphology.binary_dilation(v,structure=ones((1,int(e*50))))
if debug>0: imshow(v); ginput(1,debug)
est = est[v]
lo = stats.scoreatpercentile(est.ravel(),lo)
hi = stats.scoreatpercentile(est.ravel(),hi)
return lo, hi


def process1(job):
fname,i = job
print_info("# %s" % (fname))
if args.parallel<2: print_info("=== %s %-3d" % (fname, i))
raw = ocrolib.read_image_gray(fname)
dshow(raw,"input")
# perform image normalization
image = raw-amin(raw)
if amax(image)==amin(image):
print_info("# image is empty: %s" % (fname))
return
image /= amax(image)
image = normalize(raw)

if not args.nocheck:
check = check_page(amax(image)-image)
Expand All @@ -114,50 +182,18 @@ def process1(job):
comment = ""
# if not, we need to flatten it by estimating the local whitelevel
if args.parallel<2: print_info("flattening")
m = interpolation.zoom(image,args.zoom)
m = filters.percentile_filter(m,args.perc,size=(args.range,2))
m = filters.percentile_filter(m,args.perc,size=(2,args.range))
m = interpolation.zoom(m,1.0/args.zoom)
if args.debug>0: clf(); imshow(m,vmin=0,vmax=1); ginput(1,args.debug)
w,h = minimum(array(image.shape),array(m.shape))
flat = clip(image[:w,:h]-m[:w,:h]+1,0,1)
if args.debug>0: clf(); imshow(flat,vmin=0,vmax=1); ginput(1,args.debug)
flat = estimate_local_whitelevel(image, args.zoom, args.perc, args.range, args.debug)

# estimate skew angle and rotate
if args.maxskew>0:
if args.parallel<2: print_info("estimating skew angle")
d0,d1 = flat.shape
o0,o1 = int(args.bignore*d0),int(args.bignore*d1)
flat = amax(flat)-flat
flat -= amin(flat)
est = flat[o0:d0-o0,o1:d1-o1]
ma = args.maxskew
ms = int(2*args.maxskew*args.skewsteps)
angle = estimate_skew_angle(est,linspace(-ma,ma,ms+1))
flat = interpolation.rotate(flat,angle,mode='constant',reshape=0)
flat = amax(flat)-flat
flat, angle = estimate_skew(flat, args.bignore, args.maxskew, args.skewsteps)
else:
angle = 0

# estimate low and high thresholds
if args.parallel<2: print_info("estimating thresholds")
d0,d1 = flat.shape
o0,o1 = int(args.bignore*d0),int(args.bignore*d1)
est = flat[o0:d0-o0,o1:d1-o1]
if args.escale>0:
# by default, we use only regions that contain
# significant variance; this makes the percentile
# based low and high estimates more reliable
e = args.escale
v = est-filters.gaussian_filter(est,e*20.0)
v = filters.gaussian_filter(v**2,e*20.0)**0.5
v = (v>0.3*amax(v))
v = morphology.binary_dilation(v,structure=ones((int(e*50),1)))
v = morphology.binary_dilation(v,structure=ones((1,int(e*50))))
if args.debug>0: imshow(v); ginput(1,args.debug)
est = est[v]
lo = stats.scoreatpercentile(est.ravel(),args.lo)
hi = stats.scoreatpercentile(est.ravel(),args.hi)
lo, hi = estimate_thresholds(flat, args.bignore, args.escale, args.lo, args.hi, args.debug)
# rescale the image to get the gray scale image
if args.parallel<2: print_info("rescaling")
flat -= lo
Expand Down