def firstAnalyse(binary): binaryary = morph.r_closing(binary.astype(bool), (1,1)) labels,_ = morph.label(binaryary) objects = morph.find_objects(labels) ### <<<==== objects here bysize = sorted(range(len(objects)), key=lambda k: sl.area(objects[k])) # bysize = sorted(objects,key=sl.area) scalemap = zeros(binaryary.shape) smalldot = zeros(binaryary.shape, dtype=binary.dtype) for i in bysize: o = objects[i] if amax(scalemap[o])>0: # mask = where(labels[o] != (i+1),uint8(255),uint8(0)) # binary[o] = cv2.bitwise_and(binary[o],binary[o],mask=mask) continue scalemap[o] = sl.area(o)**0.5 scale = median(scalemap[(scalemap>3)&(scalemap<100)]) ### <<<==== scale here for i,o in enumerate(objects): if (sl.width(o) < scale/2) or (sl.height(o) < scale/2): smalldot[o] = binary[o] if sl.dim0(o) > 3*scale: mask = where(labels[o] != (i+1),uint8(255),uint8(0)) binary[o] = cv2.bitwise_and(binary[o],binary[o],mask=mask) continue return objects, smalldot, scale
def calc_typo_metric(binline): labels,n = morph.label(binline) objects = morph.find_objects(labels) filtered = [] max_h = 0 for o in objects: h = sl.dim0(o) w = sl.dim1(o) if h > binline.shape[0]*0.98: continue if h < 3 or w < 3: continue if (h > binline.shape[0]*0.2 and w > binline.shape[0]*0.2) or \ (o[0].start > binline.shape[0]/2 and o[1].stop > binline.shape[1]/4 and o[1].stop < 3*binline.shape[1]/4 and o[0].stop < binline.shape[0]*0.98): filtered.append(o) if h > max_h: max_h = h filtered.sort(key=lambda x:x[1].start) prech = None zoomforsee = 4 infoheight=50 info = np.zeros((infoheight*2+binline.shape[0]*zoomforsee,binline.shape[1]*zoomforsee)) for ch in filtered: h = sl.dim0(ch) w = sl.dim1(ch) if prech is not None and ch[1].start < (prech[1].start + prech[1].stop)/2: continue cv2.putText(info,'{:3.2f}'.format(1.0*w/max_h),\ ((ch[1].start)*zoomforsee, int(infoheight*0.4)), cv2.FONT_HERSHEY_SIMPLEX, \ 0.5,1.0,1) if prech is None: cv2.putText(info,'{:3d}'.format(max_h),\ ((ch[1].start)*zoomforsee, int(infoheight*0.9)), cv2.FONT_HERSHEY_SIMPLEX, \ 0.5,1.0,1) else: space = ch[1].start - prech[1].stop dist = ch[1].stop - prech[1].stop cv2.putText(info,'{:3.2f}'.format(1.0*space/max_h),\ ((prech[1].stop)*zoomforsee, int(infoheight*0.9)), cv2.FONT_HERSHEY_SIMPLEX, \ 0.5,1.0,1) cv2.putText(info,'({:3.2f})'.format(1.0*dist/max_h),\ ((prech[1].stop)*zoomforsee, int(infoheight*1.4)), cv2.FONT_HERSHEY_SIMPLEX, \ 0.5,1.0,1) prech = ch info[infoheight*2:,:] = cv2.resize(binline, (zoomforsee*binline.shape[1], zoomforsee*binline.shape[0])) return (info*250).astype(np.uint8), filtered
def simplefirstAnalyse(binary): binaryary = morph.r_closing(binary.astype(bool), (1,1)) labels,_ = morph.label(binaryary) objects = morph.find_objects(labels) ### <<<==== objects here smalldot = zeros(binaryary.shape, dtype=binary.dtype) scale = int(binary.shape[0]*0.7) for i,o in enumerate(objects): if (sl.width(o) < scale/2) or (sl.height(o) < scale/2): smalldot[o] = binary[o] if sl.dim0(o) > 3*scale: mask = where(labels[o] != (i+1),uint8(255),uint8(0)) binary[o] = cv2.bitwise_and(binary[o],binary[o],mask=mask) continue return objects, smalldot, scale
def compute_lines(segmentation,scale): """Given a line segmentation map, computes a list of tuples consisting of 2D slices and masked images.""" lobjects = morph.find_objects(segmentation) lines = [] for i,o in enumerate(lobjects): if o is None: continue if sl.dim1(o)<2*scale or sl.dim0(o)<scale: continue mask = (segmentation[o]==i+1) if np.amax(mask)==0: continue result = record() result.label = i+1 result.bounds = o result.mask = mask lines.append(result) return lines
def compute_lines(segmentation,scale): """Given a line segmentation map, computes a list of tuples consisting of 2D slices and masked images.""" lobjects = morph.find_objects(segmentation) lines = [] for i,o in enumerate(lobjects): if o is None: continue if sl.dim1(o)<2*scale or sl.dim0(o)<scale: continue mask = (segmentation[o]==i+1) if amax(mask)==0: continue result = record() result.label = i+1 result.bounds = o result.mask = mask lines.append(result) return lines
def compute_boxmap(binary, scale, oriimg, threshold=(.5, 4), dtype='i'): labels, n = morph.label(binary) objects = morph.find_objects(labels) boxmap = zeros(binary.shape, dtype) for i, o in enumerate(objects): h = sl.dim0(o) w = sl.dim1(o) ratio = float(h) / w if h > w else float(w) / h if h > 2 * scale or h < scale / 3: continue if ratio > 8: continue # if sl.area(o)**.5<threshold[0]*scale: continue # if sl.area(o)**.5>threshold[1]*scale: continue boxmap[o] = 1 return boxmap
def show_lines(image, lines, lsort): """Overlays the computed lines on top of the image, for debugging purposes.""" ys, xs = [], [] plt.clf() plt.cla() plt.imshow(image) for i in range(len(lines)): l = lines[lsort[i]] y, x = sl.center(l.bounds) xs.append(x) ys.append(y) o = l.bounds r = mpatches.Rectangle((o[1].start, o[0].start), edgecolor='r', fill=0, width=sl.dim1(o), height=sl.dim0(o)) plt.gca().add_patch(r) h, w = image.shape plt.ylim(h, 0) plt.xlim(0, w) plt.plot(xs, ys)
def extractLines(imgpath, param): img_grey = ocrolib.read_image_gray(imgpath) (h, w) = img_grey.shape[:2] img00 = cv2.resize(img_grey[h / 4:3 * h / 4, w / 4:3 * w / 4], None, fx=0.5, fy=0.5) angle = estimate_skew_angle(img00, linspace(-5, 5, 42)) print 'goc', angle rotM = cv2.getRotationMatrix2D((w / 2, h / 2), angle, 1) img_grey = cv2.warpAffine(img_grey, rotM, (w, h)) h, w = img_grey.shape img_grey = cv2.normalize(img_grey.astype(float32), None, 0.0, 0.999, cv2.NORM_MINMAX) binary = sauvola(img_grey, w=param.w, k=param.k, scaledown=0.2, reverse=True) ### PARAM binary = morph.r_closing(binary.astype(bool), (args.connect, 1)) binaryary = binary[h / 4:3 * h / 4, w / 4:3 * w / 4] binary = binary.astype(np.uint8) labels, n = morph.label(binaryary) objects = morph.find_objects(labels) bysize = sorted(objects, key=sl.area) scalemap = zeros(binaryary.shape) for o in bysize: if amax(scalemap[o]) > 0: continue scalemap[o] = sl.area(o)**0.5 scale = median(scalemap[(scalemap > 3) & (scalemap < 100)]) objects = psegutils.binary_objects(binary) boxmap = zeros(binary.shape, dtype=np.uint8) imgwidth = binary.shape[1] imgheight = binary.shape[0] cellwidth = 6 * scale cellheight = 2.5 * scale N_x = int(round(imgwidth / cellwidth)) cellwidth = int(round(imgwidth / N_x)) N_y = int(round(imgheight / cellheight)) cellheight = int(round(imgheight / N_y)) cells_list = [{}, {}, {}, {}] def pixel2cell2id(pixel_x, pixel_y, CELLTYPE): dx = 0 dy = 0 if CELLTYPE == 3: pixel_x -= cellwidth / 2 pixel_y -= cellheight / 2 dx = cellwidth / 2 dy = cellheight / 2 if CELLTYPE == 2: pixel_x -= cellwidth / 2 dx = cellwidth / 2 if CELLTYPE == 1: pixel_y -= cellheight / 2 dy = cellheight / 2 if pixel_x <= 0 or pixel_y <= 0: return None, None cellcoord = (pixel_x / cellwidth, pixel_y / cellheight) cellid = cellcoord[0] + cellcoord[1] * N_x cellcoord = (cellcoord[0] * cellwidth + dx, cellcoord[1] * cellheight + dy) return cellcoord, cellid def id2cell2pixel(cellid, x, y, CELLTYPE): cellcoord = (cellid % N_x, cellid / N_x) pixel_x = cellcoord[0] * cellwidth + x pixel_y = cellcoord[1] * cellheight + y if CELLTYPE == 3: pixel_x += cellwidth / 2 pixel_y += cellheight / 2 return cellcoord, pixel_x, pixel_y img_grey = (cv2.cvtColor(img_grey, cv2.COLOR_GRAY2BGR) * 255).astype( np.uint8) for o in objects: h = sl.dim0(o) w = sl.dim1(o) ratio = float(w) / h ### Dirty cheat if ratio > 1 and ratio < 6: recommended_width = max(int(0.6 * (o[0].stop - o[0].start)), int(scale * 0.6), 5) for pos in range(o[1].start + recommended_width, o[1].stop, recommended_width): binary[o[0].start:o[0].stop, pos:pos + 1] = np.uint8(0) objects = psegutils.binary_objects(binary) for o in objects: h = sl.dim0(o) w = sl.dim1(o) a = h * w # black = float(sum(binary[o]))/a # if sl.area(o)**.5<threshold[0]*scale: continue # if sl.area(o)**.5>threshold[1]*scale: continue if h > 5 * scale: continue # if h < 0.4*scale: continue if w > 4 * scale and (h > 2 * scale or h < 0.5 * scale): continue if a < 0.25 * scale * scale: continue if float(h) / w > 10: continue ratio = float(w) / h if ratio > 10: continue ### Add object as candidate character pixel_x, pixel_y = (o[1].start + o[1].stop) / 2, o[0].stop for celltype in range(4): cellcoord, cellid = pixel2cell2id(pixel_x, pixel_y, CELLTYPE=celltype) if cellcoord is None or cellid is None: continue cellbound = slice(cellcoord[1], cellcoord[1] + cellheight, None), slice(cellcoord[0], cellcoord[0] + cellwidth, None) if cellid not in cells_list[celltype]: cells_list[celltype][cellid] = SubLineFinder( window_size=max(3, scale / 6), cellbound=cellbound, initChar=o) else: cells_list[celltype][cellid].addChar(o) y0 = o[0].start y1 = o[0].stop - 3 if o[0].stop - o[0].start > 8 else o[0].start + 5 x0 = o[1].start x1 = o[1].stop - 3 if o[1].stop - o[1].start > 8 else o[1].start + 5 boxmap[y0:y1, x0:x1] = 1 for celltype in range(4): if celltype == 0: col = (255, 0, 0) if celltype == 1: col = (0, 255, 0) if celltype == 2: col = (255, 255, 0) if celltype == 3: col = (0, 0, 255) for cellid, subline in cells_list[celltype].iteritems(): # cv2.rectangle(img_grey, (subline.cellbound[1].start+celltype, subline.cellbound[0].start+celltype), (subline.cellbound[1].stop+celltype, subline.cellbound[0].stop+celltype), col,1) line = subline.subline() if line is not None: pos1 = (int(line[0][0]), int(line[0][1])) pos2 = (int(line[1][0]), int(line[1][1])) # print cellid, pos1, pos2 cv2.line(img_grey, pos1, pos2, col, 1) ### illustrate/debug first round return binary, cv2.add(img_grey, (boxmap[:, :, np.newaxis] * np.array([0, 50, 50])).astype(np.uint8))