def strip_projections(image, num_strips=30): newimg = image.image_copy() bottom_contour = image.contour_bottom() left_side = min([ i for i in range(len(bottom_contour) - 1) if bottom_contour[i + 1] != np.inf and bottom_contour[i] == np.inf ]) right_side = max([ i for i in range(len(bottom_contour) - 1) if bottom_contour[i + 1] == np.inf and bottom_contour[i] != np.inf ]) vert_strips = [] strip_dim = gc.Dim(1 + (right_side - left_side) // num_strips, image.height) for i in range(num_strips): ul = gc.Point(left_side + strip_dim.ncols * i, 0) subimg = image.subimage(ul, strip_dim) vert_strips.append(subimg) strip_centers = [ int((x + 0.5) * strip_dim.ncols + left_side) for x in range(num_strips) ] strip_projections = [x.projection_rows() for x in vert_strips] strip_proj_smooth = [moving_avg_filter(x) for x in strip_projections] strip_log = [np.log(x / (max(x) + 1) + 1) for x in strip_proj_smooth] anchor_points = [] # find runs of consecutive zeroes and take points in middle of these runs: anchors for s in strip_log: iszero = np.concatenate(([0], np.less(s, 0.2).view(np.int8), [0])) absdiff = np.abs(np.diff(iszero)) ranges = np.where(absdiff == 1)[0].reshape(-1, 2) anchors = [int((x[0] + x[1]) / 2) for x in ranges] anchor_points.append(anchors) for i, x in enumerate(strip_centers): for y in anchor_points[i]: newimg.draw_marker(gc.Point(x, y), 10, 3, 1) newimg.to_rgb().to_pil().save('aaaaaaa.png')
def display_lines(self, clear=1): """Display the lines found by placing a box around them in a display. If clear is true then any boxes already on the displayed are cleared first.""" if self.image._display is None: self.image.display() display = self.image._display if clear: display.clear_all_boxes() for s in self.sections: for line in s.lines: b = line.bbox display.add_box( core.Rect(core.Point(b.ul_x, b.ul_y), core.Dim(b.ncols, b.nrows)))
def display_sections(self, clear=1): """Display the sections found by placing a box around them in a display. If clear is true then any boxes already on the displayed are cleared first.""" # display the sections result = self.sections if self.image._display is None: self.image.display() display = self.image._display if clear: display.clear_all_boxes() for rect in result: b = rect.bbox display.add_box( core.Rect(core.Point(b.ul_x, b.ul_y), core.Dim(b.ncols, b.nrows)))
def rotate_bbox(cbox, angle, orig_dim, target_dim, radians=False): pivot = gc.Point(orig_dim.ncols / 2, orig_dim.nrows / 2) # amount to translate to compensate for padding added by gamera's rotation in preprocessing. # i am pretty sure this is the most "correct" amount. my math might be off. dx = (orig_dim.ncols - target_dim.ncols) / 2 dy = (orig_dim.nrows - target_dim.nrows) / 2 if not radians: angle = angle * np.pi / 180 s = np.sin(angle) c = np.cos(angle) # move to origin old_ulx = cbox.ulx - pivot.x old_uly = cbox.uly - pivot.y old_lrx = cbox.lrx - pivot.x old_lry = cbox.lry - pivot.y # rotate using a 2d rotation matrix new_ulx = (old_ulx * c) - (old_uly * s) new_uly = (old_ulx * s) + (old_uly * c) new_lrx = (old_lrx * c) - (old_lry * s) new_lry = (old_lrx * s) + (old_lry * c) # move back to original position adjusted for padding new_ulx += (pivot.x - dx) new_uly += (pivot.y - dy) new_lrx += (pivot.x - dx) new_lry += (pivot.y - dy) new_ul = np.round([new_ulx, new_uly]).astype('int16') new_lr = np.round([new_lrx, new_lry]).astype('int16') return CharBox(cbox.char, new_ul, new_lr)
def __init__(self, glyph): self.center = 0 self.bbox = core.Rect(core.Point(glyph.ul_x, glyph.ul_y), core.Dim(glyph.ncols, glyph.nrows)) self.glyphs = [] self.add_glyph(glyph)
def find_sections(self): """Find the sections within an image - this finds large blocks of text making it possible to find the lines within complex text layouts.""" glyphs = self.glyphs FUDGE = self.__avg_glyph_size(glyphs) * self.section_search_size # remove noise and large objects self.__noise_size = FUDGE self.__large_size = FUDGE * 20 new_glyphs = [] for g in glyphs: if self.__section_size_test(g): new_glyphs.append(g) else: if self.__fill: g.fill_white() glyphs = new_glyphs # Sort the glyphs left-to-right and top-to-bottom glyphs.sort(lambda x, y: cmp(x.ul_x, y.ul_x)) glyphs.sort(lambda x, y: cmp(x.ul_y, y.ul_y)) # Create rectangles for each glyph that are bigger by FUDGE big_rects = [] for g in glyphs: ul_y = max(0, g.ul_y - FUDGE) ul_x = max(0, g.ul_x - FUDGE) lr_y = min(self.image.lr_y, g.lr_y + FUDGE) lr_x = min(self.image.lr_x, g.lr_x + FUDGE) ul_x = int(ul_x) ul_y = int(ul_y) nrows = int(lr_y - ul_y + 1) ncols = int(lr_x - ul_x + 1) big_rects.append( core.Rect(core.Point(ul_x, ul_y), core.Dim(ncols, nrows))) # Search for intersecting glyphs and merge them. This is # harder than it seems at first because we want everything # to merge together that intersects regardless of the order # in the list. It ends up being similar to connected-component # labeling. This is prone to be kind-of slow. current = 0 rects = big_rects while (1): # Find the indexexes of any rects that interesect with current inter = self.__find_intersecting_rects(rects, current) # If we found intersecting rectangles merge them with them current # rect, remove them from the list, and start the whole process # over. We start over to make certain that everything that should # be merged is. if len(inter): g = rects[current] new_rects = [g] for i in range(len(rects)): if i == current: continue if i in inter: g.union(rects[i]) else: new_rects.append(rects[i]) rects = new_rects current = 0 # If we didn't find anything that intersected move on to the next # rectangle. else: current += 1 # Bail when we are done. if current >= len(rects): break # Create the sections sections = [] for rect in rects: sections.append(Section(rect)) # Place the original (small) glyphs into the sections for glyph in self.glyphs: if self.__section_size_test(glyph): for s in sections: if s.bbox.intersects(glyph): s.add_glyph(glyph) break # Fix up the bounding boxes for s in sections: s.calculate_bbox() self.sections = sections