def parse_bbox(stringIn): from gamera.core import Rect from gamera.core import Point dimensions = stringIn.split() if not dimensions[0] == 'bbox' or not len(dimensions) == 5: raise ValueError('bounding box not in proper format: "%s"'%dimensions) a_rect = Rect(Point(int(dimensions[1]),int(dimensions[2])),Point(int(dimensions[3]),int(dimensions[4]))) return (a_rect)#dimensions[1:])
def to_polygon(self, tolerance=0): """Converts to ``StafflinePolygon``. The optional parameter *tolerance* is offered for compatibility to ``StafflineSkeleton``, but has no effect on the return value. """ pg = StafflinePolygon() pg.vertices += [ Point(self.left_x, self.average_y), Point(self.right_x, self.average_y) ] return pg
def __call__(current, parameters, t_end, dt_end=0.0, direction=1): from gamera.core import Point fv = _skeleton_utilities.estimate_next_point(current, parameters,\ t_end, dt_end, direction) p = Point(int(fv[0]), int(fv[1])) return [p, fv[2], fv[3]]
def extend(self, Ex, Ey, img): ul_y = max(0, self.rect.ul_y - Ey) ul_x = max(0, self.rect.ul_x - Ex) lr_y = min(img.lr_y, self.rect.lr_y + Ey) lr_x = min(img.lr_x, self.rect.lr_x + Ex) nrows = lr_y - ul_y + 1 ncols = lr_x - ul_x + 1 self.rect = Rect(Point(ul_x, ul_y), Dim(ncols, nrows))
def __call__(array, offset=None): from gamera.plugins import _string_io from gamera.core import Point, Dim if offset is None: offset = Point(0, 0) pixel_type = from_numarray._check_input(array) return _string_io._from_raw_string( offset, Dim(array.shape[1], array.shape[0]), pixel_type, DENSE, array.tostring())
def Fudge(o, amount=FUDGE_AMOUNT): # For rectangles, just return a new rectangle that is slightly larger if isinstance(o, Rect): return Rect(Point(int(o.ul_x - amount), int(o.ul_y - amount)), Dim(int(o.ncols + amount * 2), int(o.nrows + amount * 2))) # For integers, return one of our "fudge number proxies" elif isinstance(o, int): return FudgeInt(o, amount) elif isinstance(o, float): return FudgeFloat(o, amount)
class estimate_next_point(PluginFunction): """Estimates the next point on a given parabola. Arguments: *current* The current point, which has to lie on the parabola. *parameters* The parameters [ax, ay, bx, by, cx, cy] that describe a parametric parabola (see parabola_). *t_end* The distance of the current point to the first point (see parabola_ for a possible computation). *dt_end* The distance of the current point to the previous one. When set to the default value, it will be estimated automatically. *direction* The direction where to go. This option is not supported yet. The return value is the vector [p, t_end, dt_end] where *p* is the estimated point, *t_end* is the distance of the estimated point to the first point, *dt_end* is the distance of the estimated point to the current point. .. code:: Python # calculate the parameters of the parabola and estimate the following point parameters, t_end = parabola(points) next_point, t_new, dt_new = estimate_next_point(points[-1], parameters, t_end) """ category = "MusicStaves/Skeleton_utilities" self_type = None args = Args([Point('current'), FloatVector('parameters'), Float('t_end'),\ Float('dt_end', default=0.0), Int('direction', default=1)]) return_type = FloatVector('ret_value') author = "Thomas Karsten" def __call__(current, parameters, t_end, dt_end=0.0, direction=1): from gamera.core import Point fv = _skeleton_utilities.estimate_next_point(current, parameters,\ t_end, dt_end, direction) p = Point(int(fv[0]), int(fv[1])) return [p, fv[2], fv[3]] __call__ = staticmethod(__call__)
def __call__(self, im_staffonly, ratio): from gamera.core import Image, RGBPixel, Point from gamera.toolkits.musicstaves.stafffinder import StafflineSkeleton im_full = self im_staffless = im_full.xor_image(im_staffonly) [first_x, last_x, stafflines, thickness] = find_stafflines_int(im_staffonly) # ratio=staffline_height/staffspace_height thickness = (stafflines[1] - stafflines[0]) / (1 / ratio + 1) im_newlines = Image(im_full.ul, im_full.size) # we just draw the lines ourselves for y in stafflines: im_newlines.draw_line(Point(first_x, y), Point(last_x, y), RGBPixel(255, 255, 255), thickness) # new full: lines OR symbols def_full = im_staffless.or_image(im_newlines) # new staffonly: lines AND NOT symbols def_staffonly = im_staffless.image_copy() def_staffonly.invert() def_staffonly.and_image(im_newlines, True) # staffless image doesn't change def_staffless = im_staffless.image_copy() # construct skeletons staffline_skel = [] for y in stafflines: skel = StafflineSkeleton() skel.left_x = first_x # all stafflines are completely straight skel.y_list = (last_x - first_x + 1) * [y] staffline_skel.append(skel) return [def_full, def_staffonly, staffline_skel]
def __call__(image, offset=None): from gamera.plugins import _string_io from gamera.core import Dim, Point typecode = image.mode if offset is None: offset = Point(0, 0) if _inverse_modes.has_key(typecode): pixel_type = _inverse_modes[typecode] else: raise ValueError( "Only RGB and 8-bit Greyscale 'L' PIL image modes are supported." ) return _string_io._from_raw_string( offset, Dim(image.size[0], image.size[1]), pixel_type, DENSE, image.tostring())
def __call__(image, offset=None): from gamera.plugins import _string_io from gamera.core import Dim, Point typecode = image.mode if offset is None: offset = Point(0, 0) if typecode in _inverse_modes: pixel_type = _inverse_modes[typecode] else: raise ValueError( "Only RGB and 8-bit Greyscale 'L' PIL image modes are supported." ) try: return _string_io._from_raw_string( offset, Dim(image.size[0], image.size[1]), pixel_type, DENSE, image.tobytes()) except Exception: # for compatibility with pil 1.1.7 and earlier return _string_io._from_raw_string( offset, Dim(image.size[0], image.size[1]), pixel_type, DENSE, image.tostring())
def __call__(image, offset=None): from gamera.plugins import _string_io from gamera.core import Dim, Point, RGBPixel if offset is None: offset = Point(0, 0) if isinstance(image, cv.cvmat): imgcv = cv.CloneMat(image) cv.CvtColor(image, imgcv, cv.CV_BGR2RGB) return _string_io._from_raw_string(offset, Dim(imgcv.cols, imgcv.rows), RGB, DENSE, imgcv.tostring()) elif isinstance(image, cv.iplimage): imgcv = cv.CreateImage(cv.GetSize(image), image.depth, image.channels) cv.CvtColor(image, imgcv, cv.CV_BGR2RGB) return _string_io._from_raw_string(offset, Dim(imgcv.width, imgcv.height), RGB, DENSE, imgcv.tostring()) else: raise TypeError("Image must be of type cv.cvmat or cv.iplimage")
def get_control(self, parent, locals=None): from gamera.core import Point default = Point(self.default) self.control = wx.BoxSizer(wx.HORIZONTAL) self.control.Add(wx.StaticText(parent, -1, "x:")) self.control_x = wx.SpinCtrl(parent, -1, value=str(default.x), min=-DEFAULT_MAX_ARG_NUMBER, max=DEFAULT_MAX_ARG_NUMBER, initial=default.x) self.control_x.SetValidator(_IntValidator(name=self.name)) self.control.Add(self.control_x, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 5) self.control.Add(wx.StaticText(parent, -1, "y:")) self.control_y = wx.SpinCtrl(parent, -1, value=str(default.y), min=-DEFAULT_MAX_ARG_NUMBER, max=DEFAULT_MAX_ARG_NUMBER, initial=default.y) self.control_y.SetValidator(_IntValidator(name=self.name)) self.control.Add(self.control_y, 1, wx.EXPAND | wx.LEFT, 5) return self
def set_stafflines(self, stafflines): new_rect = self.union_rects(stafflines) self.rect_set(Point(new_rect.ul_x, new_rect.ul_y), Dim(new_rect.ncols, new_rect.nrows)) self.stafflines = stafflines for staffline in stafflines: staffline.set_as_staffline()
def expand_ccs(image,ccs,Ex,Ey): # two helper functions for merging rectangles def find_intersecting_rects(glyphs, index): g = glyphs[index] inter = [] for i in range(len(glyphs)): if i == index: continue if g.intersects(glyphs[i]): inter.append(i) return inter def list_union_rects(big_rects): current = 0 rects = big_rects while(1): inter = find_intersecting_rects(rects, current) 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 else: current += 1 if(current >= len(rects)): break return rects # the actual plugin from gamera.core import Dim, Rect, Point, Cc from gamera.plugins.image_utilities import union_images page = image # extend CC bounding boxes big_rects = [] for c in ccs: ul_y = max(0, c.ul_y - Ey) ul_x = max(0, c.ul_x - Ex) lr_y = min(page.lr_y, c.lr_y + Ey) lr_x = min(page.lr_x, c.lr_x + Ex) nrows = lr_y - ul_y + 1 ncols = lr_x - ul_x + 1 big_rects.append(Rect(Point(ul_x, ul_y), Dim(ncols, nrows))) extended_segs = list_union_rects(big_rects) # build new merged CCs tmplist = ccs[:] dellist = [] seg_ccs = [] seg_cc = [] if(len(extended_segs) > 0): label = 1 for seg in extended_segs: label += 1 for cc in tmplist: if(seg.intersects(cc)): # mark original image with segment label #self.highlight(cc, label) seg_cc.append(cc) dellist.append(cc) if len(seg_cc) == 0: continue seg_rect = seg_cc[0].union_rects(seg_cc) new_seg = Cc(image, label, seg_rect.ul, seg_rect.lr) seg_cc = [] for item in dellist: tmplist.remove(item) dellist = [] seg_ccs.append(new_seg) return seg_ccs
def get(self): from gamera.core import Point return Point(int(self.control_x.GetValue()), int(self.control_y.GetValue()))
def generateCCsFromHocr(parser, image): from gamera.core import Point, Cc, Rect extended_segs = [] for span in parser.spans: ## print "line_span found:", span boxes = span.split(';')[0].split() point1 = Point(int(boxes[1]), int(boxes[2])) point2 = Point(int(boxes[3]), int(boxes[4])) try: extended_segs.append(Rect(point1, point2)) except RuntimeError as e: #TODO we should do something here print e print "failed to make Cc from Hocr box: " print boxes pass page = image.image_copy() ccs = page.cc_analysis() #The following copied from bbox_merging. Simply making Ccs with #the appropriate dimensions does not seem to work, but did in a #previous version... #extended_segs are the line bboxes; ccs are the glyphs #found by page analysis # build new merged CCs tmplist = ccs[:] dellist = [] seg_ccs = [] seg_cc = [] if (len(extended_segs) > 0): label = 1 for seg in extended_segs: label += 1 # print "new line!" for cc in tmplist: #changed in this revision; the divisor used to be seg.height, that is, the line's height #avoid divbyzero error if cc.height > 0: descender = (float(cc.lr_y - seg.lr_y) / float(cc.height)) else: descender = float(0) # print "desc: ", str(descender), " downness: ", str(downness), " ccheight: ", str(cc.height) #for more closed texts: #this matches if: # 1. the character's bottom is above the lines, or; # 2. if the character is higher than half the line height # AND the portion of the character that goes below the line is less # than 20% of its total height. #if(seg.intersects(cc) and ((cc.lr_y < seg.lr_y) or ((float(cc.height) > float(seg.height)/2.0) and (descender < 0.2) )): #for more open texts: #if(seg.intersects(cc) and ((cc.lr_y < seg.lr_y) or (descender < 0.4)) ): # mark original image with segment label #new, experimental universal solution: #This matches if: #1. the character's bottom is above the line, or; #2. The character's bottom is below the line, and the amount of the character that is below the line is less than 40% of its height if (seg.intersects(cc) and ((cc.lr_y <= seg.lr_y) or ((cc.lr_y > seg.lr_y) and (descender < 0.3)))): # print "\tpassed" image.highlight(cc, label) seg_cc.append(cc) dellist.append(cc) if len(seg_cc) == 0: #continue #try to output, rather than ignore, empty line #this should make alignment easier, but is it wise? seg_rect = seg else: seg_rect = seg_cc[0].union_rects(seg_cc) #TODO fix these errors, caused by new_seg being beyond the bounds of the image, I believe #They seem to appear with tesseract hocr output try: new_seg = Cc(image, label, seg_rect.ul, seg_rect.lr) seg_ccs.append(new_seg) except RuntimeError as e: print "HOCR ERROR -- failed to append segment" print e seg_cc = [] for item in dellist: tmplist.remove(item) dellist = [] #seg_ccs.append(new_seg) return seg_ccs
def __call__(self, im_staffonly, n_gap, p_gap, n_shift, random_seed=0, add_noshift=False): from gamera.core import RGBPixel, Point, FloatPoint, Rect from gamera.toolkits.musicstaves.stafffinder import StafflineSkeleton seed(random_seed) bnp_gap = binomial(n_gap, p_gap) bnp_shift = binomial(n_shift, 0.5) im_full = self.image_copy() im_staffless = im_full.xor_image(im_staffonly) im_staffonly = im_staffonly.image_copy() il_shifts = [im_staffless, im_staffonly, im_full] il_breaks = il_shifts if add_noshift: ns_full = im_full.image_copy() ns_staffonly = im_staffonly.image_copy() il_breaks = [ im_staffless, im_staffonly, im_full, ns_full, ns_staffonly ] #find stafflines [first_x, last_x, stafflines, thickness] = find_stafflines_int(im_staffonly) #find breaks (where are the symbols?) stafflinedist = stafflines[1] - stafflines[0] staffline_skel = [] for sl in range(len(stafflines)): if sl == 0 or stafflines[sl] - stafflines[sl - 1] > 3 * stafflinedist: #first staffline of a system first_line = stafflines[sl] lines_per_system = 0 lines_per_system = lines_per_system + 1 if sl == len(stafflines) - 1 or stafflines[ sl + 1] - stafflines[sl] > 3 * stafflinedist: #last staffline of a system last_line = stafflines[sl] # a hoizontal projection of the symbols helps us to find the x positions of the symbols. syst = im_staffless.subimage( Point(0, max((0, first_line - 3 * stafflinedist))), Point( im_staffless.width, min((last_line + 3 * stafflinedist, im_full.lr_y - 1)))) symbolcols = syst.projection_cols() # collect the breaks, i.e. the mid of the white spaces between two symbols breaks = [] whiterun = False for col in range(len(symbolcols)): if (not whiterun) and symbolcols[col] == 0: whiterun = True runbegin = col else: if whiterun and symbolcols[col] > 0: whiterun = False br = [(runbegin + col) / 2, col - runbegin] if br[0] >= first_x: breaks.append(br) # replace the first break (before the first symbol) with a break at the beginning of the stafflines breaks[0] = [first_x, 1] # and append a break after the last symbol if whiterun: breaks.append([(last_x + runbegin) / 2, last_x - runbegin]) else: breaks.append([last_x, 1]) # draw white lines at the breaks new_breaks = [] for br in breaks: w = bnp_gap.random() # draw line if it fits only if w < br[1]: for im in il_breaks: im.draw_line( FloatPoint(br[0], first_line - stafflinedist), FloatPoint(br[0], last_line + stafflinedist), RGBPixel(0, 0, 0), w) new_breaks.append(br) breaks = new_breaks skeleton = [] # do the vertical shift by making a temporary copy (orig_type), white them out (draw_filled_rect) and "or" them again in with a new y-position for t in range(len(breaks) - 1): vertical_shift = bnp_shift.random() - n_shift / 2 typerect = Rect( Point(breaks[t][0], max((first_line - 3 * stafflinedist, 0))), Point( breaks[t + 1][0], min((last_line + 3 * stafflinedist, im_full.lr_y)))) moveto = Rect( Point(typerect.ul_x, typerect.ul_y + vertical_shift), typerect.size) if moveto.ul_y < 0: typerect.ul_y = typerect.ul_y - moveto.ul_y moveto.ul_y = 0 if moveto.lr_y > im_full.lr_y: typerect.lr_y = typerect.lr_y - (moveto.lr_y - im_full.lr_y) moveto.lr_y = im_full.lr_y for im in il_shifts: orig_type = im.subimage(typerect) orig_type = orig_type.image_copy() im.draw_filled_rect(typerect, RGBPixel(0, 0, 0)) im.subimage(moveto).or_image(orig_type, True) # collect data for later construction of the skeletons for line in range(lines_per_system): if len(skeleton) <= line: skeleton.append([]) st_line = stafflines[sl - lines_per_system + 1 + line] y = st_line + vertical_shift skeleton[line].append(Point(typerect.ul_x, y)) skeleton[line].append(Point(typerect.ur_x, y)) # now construct the skeletons for sk in skeleton: x = sk[0].x y = sk[0].y left_x = x y_list = [] i = 1 while i < len(sk): y_list.append(y) if x >= sk[i].x: y = sk[i].y i = i + 1 x = x + 1 o = StafflineSkeleton() o.left_x = left_x o.y_list = y_list staffline_skel.append(o) if add_noshift: return [ im_full, im_staffonly, staffline_skel, ns_full, ns_staffonly ] else: return [im_full, im_staffonly, staffline_skel]
def show_result(self, highlight_groups=True): """Returns an RGB image with the found staff lines highlighted. Parameters: *highlight_groups*: when *True* (default), each stave system is underlayed in a different color. When false, only the edge points are marked in different colors, which is less visible for skeleton or average staff line representation. """ rgb = Image(self.image, RGB) if highlight_groups: # highlight staff systems for staffno, staff in enumerate(self.linelist): if not staff: continue staffcolor = RGBPixel(190 + (11*staffno) % 66, \ 190 + (31*(staffno + 1)) % 66, \ 190 + (51*(staffno + 2)) % 66) topline = staff[0].to_average() botline = staff[-1].to_average() leftx = min([topline.left_x, botline.left_x]) rightx = max([topline.right_x, botline.right_x]) topy = topline.average_y boty = botline.average_y border = max( [self.staffspace_height / 2, self.staffline_height * 4]) if leftx - border > 0: leftx -= border if rightx + border < rgb.ncols: rightx += border if topy - border > 0: topy -= border if boty + border < rgb.nrows: boty += border rgb.draw_filled_rect((leftx, topy), (rightx, boty), staffcolor) # draw original image rgb.highlight(self.image, RGBPixel(0, 0, 0)) for staffno, staff in enumerate(self.linelist): if not staff: continue if highlight_groups: staffcolor = RGBPixel(255, 0, 0) else: staffcolor = RGBPixel((53*(staffno)) % 256,\ (111*(staffno+1)) % 256,\ (111*(staffno+2)) % 256) for line in staff: if isinstance(line, StafflinePolygon): lastp = None for p in line.vertices: rgb.draw_marker(p,self.staffline_height*2,3,\ staffcolor) if lastp: rgb.draw_line(lastp, p, RGBPixel(255, 0, 0)) lastp = p elif isinstance(line, StafflineAverage): rgb.draw_line(Point(0,line.average_y),\ Point(rgb.ncols,line.average_y),\ RGBPixel(255,0,0)) rgb.draw_marker(Point(line.left_x,line.average_y),\ self.staffline_height*2,3,\ staffcolor) rgb.draw_marker(Point(line.right_x,line.average_y),\ self.staffline_height*2,3,\ staffcolor) elif isinstance(line, StafflineSkeleton): # doing this in Python might be too slow, # implement it in C++ later x = line.left_x for y in line.y_list: rgb.set(Point(x, y), RGBPixel(255, 0, 0)) x += 1 if len(line.y_list) > 0: rgb.draw_marker(Point(line.left_x,line.y_list[0]),\ self.staffline_height*2,3,\ staffcolor) rgb.draw_marker(Point(x-1,line.y_list[-1]),\ self.staffline_height*2,3,\ staffcolor) return rgb