def extract_candidate_groups(segmentation, min_aspect=0.1, max_aspect=1.8, maxgap=2, maxrange=3): """Select a basic collection of candidate components. Aspect ratios <1 are tall and skinny, >1 are wide. `maxgap` is the maximum gap between bounding boxes. `maxrange` gives the maximum number of compponents to be combined.""" assert morph.ordered_by_xcenter( segmentation), "call morph.sort_by_xcenter first" boxes = [None] + morph.find_objects(segmentation) n = len(boxes) result = [] for i in range(1, n): for r in range(1, maxrange + 1): if i + r > n: continue if r > 1 and max_boxgap(boxes[i:i + r]) > maxgap: continue box = box_union(boxes[i:i + r]) a = sl.aspect(box) if r > 1 and 1.0 / a > max_aspect: continue if 1.0 / a < min_aspect: continue assert sum(segmentation[box]) > 0 j = i + r - 1 seg = segmentation[box] * (segmentation[box] >= i) * (segmentation[box] <= j) result.append(Segment(first=i, last=j, bbox=box)) return result
def extract_candidate_groups(segmentation, min_aspect=0.1, max_aspect=1.8, maxgap=2, maxrange=3): """Select a basic collection of candidate components. Aspect ratios <1 are tall and skinny, >1 are wide. `maxgap` is the maximum gap between bounding boxes. `maxrange` gives the maximum number of compponents to be combined.""" assert morph.ordered_by_xcenter(segmentation), "call morph.sort_by_xcenter first" boxes = [None] + morph.find_objects(segmentation) n = len(boxes) result = [] for i in range(1, n): for r in range(1, maxrange + 1): if i + r > n: continue if r > 1 and max_boxgap(boxes[i : i + r]) > maxgap: continue box = box_union(boxes[i : i + r]) a = sl.aspect(box) if r > 1 and 1.0 / a > max_aspect: continue if 1.0 / a < min_aspect: continue assert sum(segmentation[box]) > 0 j = i + r - 1 seg = segmentation[box] * (segmentation[box] >= i) * (segmentation[box] <= j) result.append(Segment(first=i, last=j, bbox=box)) return result
def setImageMasked(self, image, mask=None, lo=None, hi=None): """Set the image to be iterated over. This should be an RGB image, ndim==3, dtype=='B'. This picks a subset of the segmentation to iterate over, using a mask and lo and hi values. """ # print("$$ setImageMasked: image=%s mask=%s lo=%s hi=%s" % ( # desc(image), hexs(mask), hexs(lo), hexs(hi))) assert image.dtype == dtype('B') or image.dtype == dtype( 'i'), "image must be type B or i" if image.ndim == 3: image = rgb2int(image) imageDescribe("image", image) assert image.ndim == 2, "wrong number of dimensions" self.image = image labels = image if lo is not None: labels[labels < lo] = 0 if hi is not None: labels[labels > hi] = 0 if mask is not None: labels = bitwise_and(labels, mask) imageDescribe("labels", labels) labels, correspondence = morph.renumber_labels_ordered( labels, correspondence=1) self.labels = labels self.correspondence = correspondence self.objects = [None] + morph.find_objects(labels) # print("$$ setImageMasked: objects=%d" % len(self.objects)) sizes = [o for o in self.objects] sizes.sort(key=lambda u: -sliceSize(u)) for i, o in enumerate(sizes[:20]): print("%5d: %s %s %d" % (i, o, sliceDims(o), sliceSize(o)))
def bbox(image): """Compute the bounding box for the pixels in the image.""" assert len(image.shape)==2,"wrong shape: "+str(image.shape) image = array(image!=0,'uint32') cs = morph.find_objects(image) if len(cs)<1: return None c = cs[0] return (c[0].start,c[1].start,c[0].stop,c[1].stop)
def bbox(image): """Compute the bounding box for the pixels in the image.""" assert len(image.shape) == 2, "wrong shape: " + str(image.shape) image = array(image != 0, 'uint32') cs = morph.find_objects(image) if len(cs) < 1: return None c = cs[0] return (c[0].start, c[1].start, c[0].stop, c[1].stop)
def extract_csegs(segmentation,aligned=None): """Given a segmentation, extracts a list of segment objects.""" if aligned is None: aligned = [] def get(c): return aligned[c] if c<len(aligned) else "" boxes = morph.find_objects(segmentation) # n = len(boxes) result = [Segment(first=i+1,last=i+1,bbox=box,out=[(get(i),0.0)], img=1*(segmentation[:,box[1]]==i+1)) \ for i,box in enumerate(boxes) if box is not None] return result
def setImageMasked(self,image,mask=None,lo=None,hi=None): """Set the image to be iterated over. This should be an RGB image, ndim==3, dtype=='B'. This picks a subset of the segmentation to iterate over, using a mask and lo and hi values..""" assert image.dtype==dtype('B') or image.dtype==dtype('i'),"image must be type B or i" if image.ndim==3: image = rgb2int(image) assert image.ndim==2,"wrong number of dimensions" self.image = image labels = image if lo is not None: labels[labels<lo] = 0 if hi is not None: labels[labels>hi] = 0 if mask is not None: labels = bitwise_and(labels,mask) labels,correspondence = morph.renumber_labels_ordered(labels,correspondence=1) self.labels = labels self.correspondence = correspondence self.objects = [None]+morph.find_objects(labels)
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_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 seg_boxes(seg,math=0): """Given a color segmentation, return a list of bounding boxes. Bounding boxes are returned as tuples (y0,y1,x0,x1). With math=0, raster coordinates are used, with math=1, Postscript coordinates are used (however, the order of the values in the tuple doesn't change).""" seg = array(seg,'uint32') slices = morph.find_objects(seg) h = seg.shape[0] result = [] for i in range(len(slices)): if slices[i] is None: continue (ys,xs) = slices[i] if math: result += [(h-ys.stop-1,h-ys.start-1,xs.start,xs.stop)] else: result += [(ys.start,ys.stop,xs.start,xs.stop)] return result
def seg_boxes(seg, math=0): """Given a color segmentation, return a list of bounding boxes. Bounding boxes are returned as tuples (y0,y1,x0,x1). With math=0, raster coordinates are used, with math=1, Postscript coordinates are used (however, the order of the values in the tuple doesn't change).""" seg = array(seg, 'uint32') slices = morph.find_objects(seg) h = seg.shape[0] result = [] for i in range(len(slices)): if slices[i] is None: continue (ys, xs) = slices[i] if math: result += [(h - ys.stop - 1, h - ys.start - 1, xs.start, xs.stop)] else: result += [(ys.start, ys.stop, xs.start, xs.stop)] return result
def extract_chars(segmentation,h=32,w=32,f=0.5,minscale=0.5): """Extract all the characters from the segmentation and yields them as an interator. Also yields a forward and a backwards transformation.""" bin = (segmentation>0) if amax(bin)==0: raise ocrolib.RecognitionError("empty segmentation") ls,ly,lx = vertical_stddev(bin) boxes = morph.find_objects(segmentation) for i,b in enumerate(boxes): sub = (segmentation==i+1) if amax(sub)==amin(sub): continue cs,cy,cx = vertical_stddev(sub) # limit the character sigma to be at least minscale times the # line sigma (this causes dots etc. not to blow up ridiculously large) scale = f*h/(4*max(cs,minscale*ls)) m = diag([1.0/scale,1.0/scale]) offset = array([cy,cx])-dot(m,array([h/2,w/2])) def transform(image,m=m,offset=offset): return interpolation.affine_transform(1.0*image,m,offset=offset,order=1,output_shape=(h,w)) def itransform_add(result,image,m=m,cx=cx,cy=cy): im = inv(m) ioffset = array([h/2,w/2])-dot(im,array([cy,cx])) result += interpolation.affine_transform(1.0*image,im,offset=ioffset,order=1,output_shape=segmentation.shape) cimage = transform(sub) yield cimage,transform,itransform_add
def extract_chars(segmentation, h=32, w=32, f=0.5, minscale=0.5): """Extract all the characters from the segmentation and yields them as an interator. Also yields a forward and a backwards transformation.""" bin = (segmentation > 0) if amax(bin) == 0: raise ocrolib.RecognitionError("empty segmentation") ls, ly, lx = vertical_stddev(bin) boxes = morph.find_objects(segmentation) for i, b in enumerate(boxes): sub = (segmentation == i + 1) if amax(sub) == amin(sub): continue cs, cy, cx = vertical_stddev(sub) # limit the character sigma to be at least minscale times the # line sigma (this causes dots etc. not to blow up ridiculously large) scale = f * h / (4 * max(cs, minscale * ls)) m = diag([1.0 / scale, 1.0 / scale]) offset = array([cy, cx]) - dot(m, array([h / 2, w / 2])) def transform(image, m=m, offset=offset): return interpolation.affine_transform(1.0 * image, m, offset=offset, order=1, output_shape=(h, w)) def itransform_add(result, image, m=m, cx=cx, cy=cy): im = inv(m) ioffset = array([h / 2, w / 2]) - dot(im, array([cy, cx])) result += interpolation.affine_transform( 1.0 * image, im, offset=ioffset, order=1, output_shape=segmentation.shape) cimage = transform(sub) yield cimage, transform, itransform_add
def binary_objects(binary): labels, n = morph.label(binary) objects = morph.find_objects(labels) return objects
def binary_objects(binary): labels,n = morph.label(binary) objects = morph.find_objects(labels) return objects