annotate Preprocessing/preomr.py @ 2:46fb79167a61 tip

Main Code
author Victor Padilla <victor.padilla.mc@gmail.com>
date Mon, 04 May 2015 22:56:18 +0200
parents
children
rev   line source
victor@2 1 import sys
victor@2 2 import cv2
victor@2 3 import numpy as np
victor@2 4 import math
victor@2 5 import copy
victor@2 6
victor@2 7 from gamera.core import *
victor@2 8 from gamera.toolkits.musicstaves import musicstaves_rl_roach_tatem
victor@2 9 from gamera.toolkits.musicstaves import musicstaves_rl_fujinaga
victor@2 10 from gamera.toolkits.musicstaves import stafffinder_miyao
victor@2 11 from gamera.toolkits.musicstaves import stafffinder_dalitz
victor@2 12 from gamera.toolkits.musicstaves import stafffinder_projections
victor@2 13 from gamera.plugins import numpy_io
victor@2 14 init_gamera()
victor@2 15
victor@2 16 #import ossiafinder_dalitz
victor@2 17
victor@2 18 def intersect(r1,r2):
victor@2 19 """Returns the intersection of two rectangles"""
victor@2 20 x1 = max(r1['x'], r2['x'])
victor@2 21 y1 = max(r1['y'], r2['y'])
victor@2 22 x2 = min(r1['x'] + r1['width'], r2['x'] + r2['width'])
victor@2 23 y2 = min(r1['y'] + r1['height'], r2['y'] + r2['height'])
victor@2 24 result = {"x": x1, "y": y1, "width": x2 - x1, "height": y2-y1}
victor@2 25 result['area'] = result['width'] * result['height']
victor@2 26 return(result)
victor@2 27
victor@2 28 def ydist(r1,r2):
victor@2 29 """distance on y-axis between two non-interecting rectangles"""
victor@2 30 top1 = r1['y']
victor@2 31 bottom1 = r1['y'] + r1['height']
victor@2 32
victor@2 33 top2 = r2['y']
victor@2 34 bottom2 = r2['y'] + r2['height']
victor@2 35 return(min(abs(top1-bottom2), abs(top2-bottom1)))
victor@2 36
victor@2 37
victor@2 38 def show(img, factor=0.5):
victor@2 39 """ show an image until the escape key is pressed
victor@2 40 :param factor: scale factor (default 0.5, half size)
victor@2 41 """
victor@2 42 if factor != 1.0:
victor@2 43 img = cv2.resize(img, (0,0), fx=factor, fy=factor)
victor@2 44
victor@2 45 cv2.imwrite('show.png',img)
victor@2 46 # while(1):
victor@2 47 # k = cv2.waitKey(0)
victor@2 48 # if k==27: # Esc key to quit
victor@2 49 # cv2.destroyAllWindows()
victor@2 50 # exit()
victor@2 51 # if k==32: # Space to stop
victor@2 52 # cv2.destroyAllWindows()
victor@2 53 # break
victor@2 54
victor@2 55
victor@2 56 def max_staff_height(blob):
victor@2 57 result = 0
victor@2 58 for staff in blob['staves']:
victor@2 59 top = staff[0].y_list[0]
victor@2 60 bottom = staff[-1].y_list[0]
victor@2 61 result = max(result, bottom-top)
victor@2 62 return(result)
victor@2 63
victor@2 64
victor@2 65 def deskew(img):
victor@2 66 """Deskews the given image based on lines detected with opencv's
victor@2 67 HoughLines function."""
victor@2 68 print "Deskewing."
victor@2 69 imgHeight, imgWidth, imgDepth = img.shape
victor@2 70 img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
victor@2 71 img_edges = cv2.Canny(img_gray,50,150,apertureSize = 3)
victor@2 72 minLineLength = int(imgWidth*0.5)
victor@2 73 houghThresh = int(imgWidth*0.15)
victor@2 74 maxLineGap = 10
victor@2 75 #lines = cv2.HoughLinesP(img_edges,1,np.pi/(180*1),houghThresh,minLineLength,maxLineGap)
victor@2 76 lines = cv2.HoughLines(img_edges,1,np.pi/(180*3),houghThresh)
victor@2 77
victor@2 78 angles = []
victor@2 79 for rho,theta in lines[0]:
victor@2 80 angles.append((theta - (np.pi / 2)))
victor@2 81
victor@2 82 a = np.cos(theta)
victor@2 83 b = np.sin(theta)
victor@2 84 x0 = a*rho
victor@2 85 y0 = b*rho
victor@2 86 x1 = int(x0 + imgWidth*(-b))
victor@2 87 y1 = int(y0 + imgWidth*(a))
victor@2 88 x2 = int(x0 - imgWidth*(-b))
victor@2 89 y2 = int(y0 - imgWidth*(a))
victor@2 90 #cv2.line(img,(x1,y1),(x2,y2),(255,0,0),2)
victor@2 91
victor@2 92 middle = np.median(angles)
victor@2 93 middle_deg = middle * (180/np.pi)
victor@2 94
victor@2 95 rotation = cv2.getRotationMatrix2D((imgWidth/2,imgHeight/2),middle_deg,1.0)
victor@2 96
victor@2 97 # rotate while inverted. the background is filled with zeros
victor@2 98 # (black), this inversion means that ends up white
victor@2 99 deskewed = cv2.bitwise_not(cv2.warpAffine(cv2.bitwise_not(img),
victor@2 100 rotation,
victor@2 101 (imgWidth,imgHeight))
victor@2 102 )
victor@2 103 return(deskewed)
victor@2 104
victor@2 105 class PreOMR(object):
victor@2 106 stavelineWidthThresh = 0.5
victor@2 107
victor@2 108 def __init__(self, infile, deskew=False):
victor@2 109 self.debug = True
victor@2 110 self.infile = infile
victor@2 111 self.img = cv2.imread(self.infile)
victor@2 112 if deskew:
victor@2 113 self.img = deskew(self.img)
victor@2 114 self.original = self.img
victor@2 115 self.imgHeight, self.imgWidth, self.imgDepth = self.img.shape
victor@2 116 self.img_gray = cv2.cvtColor(self.img,cv2.COLOR_BGR2GRAY)
victor@2 117 if self.debug:
victor@2 118 self.debug_img = self.img.copy()
victor@2 119 ret2,self.img_binary = cv2.threshold(self.img_gray,
victor@2 120 0,255,cv2.
victor@2 121 THRESH_BINARY+cv2.
victor@2 122 THRESH_OTSU)
victor@2 123
victor@2 124 def staffline_removal(self):
victor@2 125 gamera_img = numpy_io.from_numpy(self.img)
victor@2 126 #self.save('tmp.png')
victor@2 127 #gamera_img = load_image('tmp.png')
victor@2 128
victor@2 129 #ms = musicstaves_rl_roach_tatem.MusicStaves_rl_roach_tatem(gamera_img)
victor@2 130 ms = musicstaves_rl_fujinaga.MusicStaves_rl_fujinaga(gamera_img)
victor@2 131 cv2.imwrite('tmp.png', self.img)
victor@2 132 ms.remove_staves(crossing_symbols = 'bars')
victor@2 133 ms.image.save_PNG("tmpb.png")
victor@2 134 staffless = cv2.imread("tmp.png", cv2.CV_LOAD_IMAGE_GRAYSCALE)
victor@2 135 return(staffless)
victor@2 136
victor@2 137 def find_staves(self, img):
victor@2 138 gamera_img = numpy_io.from_numpy(img)
victor@2 139 #sf = stafffinder_projections.StaffFinder_projections(gamera_img)
victor@2 140 #sf.find_staves(follow_wobble=True,preprocessing=0)
victor@2 141 #sf = stafffinder_dalitz.StaffFinder_dalitz(gamera_img)
victor@2 142 sf = stafffinder_miyao.StaffFinder_miyao(gamera_img)
victor@2 143 sf.find_staves()
victor@2 144 #sf.find_staves(debug=2)
victor@2 145
victor@2 146 staves = sf.get_skeleton()
victor@2 147 # if self.debug:
victor@2 148 # for i, staff in enumerate(staves):
victor@2 149 # print "Staff %d has %d staves:" % (i+1, len(staff))
victor@2 150 # for j, line in enumerate(staff):
victor@2 151 # print(" %d. line at (%d,%d)" % (j+1,line.left_x,line.y_list[0]))
victor@2 152 return(staves)
victor@2 153
victor@2 154 def find_blobs(self, img_binary):
victor@2 155 """Find blobs in the given image, returned as a list of associative
victor@2 156 lists containing various cheap metrics for each blob."""
victor@2 157
victor@2 158 blobs = []
victor@2 159 img_inverted = cv2.bitwise_not(img_binary)
victor@2 160 contours, hierarchy = cv2.findContours(img_inverted,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
victor@2 161 for (i, c) in enumerate(contours):
victor@2 162 blob = {}
victor@2 163 blobs.append(blob)
victor@2 164
victor@2 165 blob['area'] = cv2.contourArea(c)
victor@2 166
victor@2 167 m = cv2.moments(c)
victor@2 168 if m['m00'] == 0: # When would this be true?
victor@2 169 blob['x'] = 0
victor@2 170 blob['y'] = 0
victor@2 171 else:
victor@2 172 blob['x'] = m['m10'] / m['m00']
victor@2 173 blob['y'] = m['m01'] / m['m00']
victor@2 174
victor@2 175 blob['contour'] = c
victor@2 176
victor@2 177 rect = cv2.boundingRect(c)
victor@2 178 blob['rect'] = {'x': rect[0],
victor@2 179 'y': rect[1],
victor@2 180 'width': rect[2],
victor@2 181 'height': rect[3]
victor@2 182 }
victor@2 183 blob['boundingRect'] = rect
victor@2 184 blob['hull'] = hull = cv2.convexHull(c)
victor@2 185 blob['hull_area'] = abs(cv2.contourArea(hull))
victor@2 186 blob['system'] = False
victor@2 187 blob['parent'] = None
victor@2 188 #blob['perimeter'] = perimeter = cv2.arcLength(c, True)
victor@2 189 #blob['roundness'] = (perimeter * 0.282) / math.sqrt(area)
victor@2 190 #(centre, axes, orientation) = cv2.fitEllipse(c)
victor@2 191 #blob['orientation'] = orientation / 180
victor@2 192 #print "orientation: %f" % orientation
victor@2 193 #blob['aspect'] = float(rect[1]) / float(rect[3])
victor@2 194
victor@2 195 return blobs
victor@2 196
victor@2 197 def find_bars(self, system):
victor@2 198 staffless = self.staffline_removal()
victor@2 199 blobs = self.blobs
victor@2 200
victor@2 201 """Finds the barlines in the system, given a binary image, a hash of
victor@2 202 info about the system, and blobs detected in the image.
victor@2 203
victor@2 204 """
victor@2 205 img = system['image']
victor@2 206
victor@2 207 for staff in system['staves']:
victor@2 208 min_x = 0
victor@2 209 max_x = self.imgWidth
victor@2 210
victor@2 211 for line in staff:
victor@2 212 min_x = max(min_x, line.left_x)
victor@2 213 max_x = min(max_x, line.left_x + len(line.y_list))
victor@2 214
victor@2 215 if self.debug:
victor@2 216 for (i,y) in enumerate(line.y_list):
victor@2 217 x = line.left_x + i
victor@2 218 cv2.line(self.debug_img,(x,y),(x,y),(0,255,0),3)
victor@2 219
victor@2 220 # cv2.line(img,(0,int(start)),(imgWidth,int(start)),(0,255,255),3)
victor@2 221 # cv2.line(img,(0,int(stop)),(imgWidth,int(stop)),(0,255,255),3)
victor@2 222 # cv2.line(img,(0,int(first_staveline)),(imgWidth,int(first_staveline)),(255,255,0),3)
victor@2 223 # cv2.line(img,(0,int(last_staveline)),(imgWidth,int(last_staveline)),(255,255,0),3)
victor@2 224
victor@2 225 # assuming single staff for now..
victor@2 226 barlines = [0]
victor@2 227 system['barlines'] = barlines
victor@2 228
victor@2 229 x_projection = []
victor@2 230
victor@2 231 for x in range(min_x, max_x):
victor@2 232 first_staveline = staff[0].y_list[x - staff[0].left_x]
victor@2 233 last_staveline = staff[-1].y_list[x - staff[-1].left_x]
victor@2 234
victor@2 235 #print("Stavelines: first %d last %d" % (first_staveline, last_staveline))
victor@2 236 stave_height = last_staveline - first_staveline
victor@2 237
victor@2 238 # mean distance between stavelines
victor@2 239 avg_inter = float(stave_height) / float(len(staff)-1)
victor@2 240 #print("avg_inter: %f" % (avg_inter,))
victor@2 241
victor@2 242 # where to look a bit above and below the stave for whitespace
victor@2 243 # above a barline
victor@2 244 gap = avg_inter / 2.0
victor@2 245 start = first_staveline - gap
victor@2 246 stop = last_staveline + gap
victor@2 247
victor@2 248 # above stave, stave and below stave
victor@2 249 top = float(gap -
victor@2 250 cv2.countNonZero(staffless[start:first_staveline,
victor@2 251 x:x+1])) / float(gap)
victor@2 252 mid = float(stave_height -
victor@2 253 cv2.countNonZero(staffless[first_staveline:last_staveline,
victor@2 254 x:x+1])
victor@2 255 ) / float(stave_height)
victor@2 256 bot = float(gap -
victor@2 257 cv2.countNonZero(staffless[last_staveline:stop, x:x+1])
victor@2 258 ) / float(gap)
victor@2 259 x_projection.append((top,mid,bot))
victor@2 260
victor@2 261 barline_start = -1
victor@2 262 gap_dist = avg_inter/4
victor@2 263 gap_min = (avg_inter/float(stave_height)) * 0.3
victor@2 264 gap_tolerance = int(avg_inter/10)
victor@2 265
victor@2 266 margin = int(avg_inter*2)
victor@2 267
victor@2 268 for x in range(min_x+margin, max_x-margin):
victor@2 269 (top,mid,bot) = x_projection[x - min_x]
victor@2 270 #if self.debug:
victor@2 271 #cv2.line(system['image'],(x,first_staveline),(x,int(first_staveline+((last_staveline-first_staveline)*mid))),(255,255,0),1)
victor@2 272
victor@2 273 # found start of barline candidate
victor@2 274 if top < 0.6 and bot < 0.6 and mid > 0.95:
victor@2 275 if barline_start < 0:
victor@2 276 barline_start = x
victor@2 277 else:
victor@2 278 if barline_start > 0:
victor@2 279 # check there is nothing either side of 'barline'
victor@2 280 barline_stop = x-1
victor@2 281 barline_mid = barline_stop - ((barline_stop - barline_start)/2)
victor@2 282 #print("barline start %d stop %d mid %d" % (barline_start, barline_stop, barline_mid))
victor@2 283 left = int(max(0,barline_start-gap_dist))
victor@2 284 right = int(min(system['width']-1,(x-1)+gap_dist))
victor@2 285
victor@2 286 total = 0
victor@2 287 for i in range(left-gap_tolerance, left+gap_tolerance+1):
victor@2 288 total = total + x_projection[i-min_x][1]
victor@2 289 left_avg = total / ((gap_tolerance*2)+1)
victor@2 290
victor@2 291 total = 0
victor@2 292 for i in range(right-gap_tolerance, right+gap_tolerance+1):
victor@2 293 total = total + x_projection[i-min_x][1]
victor@2 294 right_avg = total / ((gap_tolerance*2)+1)
victor@2 295
victor@2 296 cv2.line(img,(left,first_staveline),(left,last_staveline),(255,0,255),1)
victor@2 297 cv2.line(img,(right,first_staveline),(right,last_staveline),(255,0,255),1)
victor@2 298
victor@2 299 if (left_avg <= gap_min and right_avg <= gap_min):
victor@2 300 #print("success: left_avg %f right_avg %f" % (left_avg, right_avg))
victor@2 301 cv2.line(img,(barline_mid,first_staveline),(barline_mid,last_staveline),(255,0,0),3)
victor@2 302 barlines.append(barline_mid)
victor@2 303 else:
victor@2 304 #print("fail: left_avg %f right_avg %f" % (left_avg, right_avg))
victor@2 305 cv2.line(img,(barline_mid,first_staveline),(barline_mid,last_staveline),(0,255,0),3)
victor@2 306 #show(img)
victor@2 307 barline_start = -1
victor@2 308 (x1, y1, x2, y2) = system['location']
victor@2 309 #show(system['image'][y1:y2, x1:x2])
victor@2 310
victor@2 311 def extract_bars(self, system, blobs):
victor@2 312 """Given information about a system (including identified barlines),
victor@2 313 and all the blobs on a page returns a list of bars in the system,
victor@2 314 each an associative array containing image and location.
victor@2 315
victor@2 316 """
victor@2 317
victor@2 318 img = system['image']
victor@2 319
victor@2 320 barlines = system['barlines']
victor@2 321
victor@2 322 result = []
victor@2 323
victor@2 324 for i in range(0,len(barlines)):
victor@2 325 barstart = barlines[i]
victor@2 326 if i == (len(barlines)-1):
victor@2 327 barstop = system['width']
victor@2 328 else:
victor@2 329 barstop = barlines[i+1]
victor@2 330 #print("barstart %d barstop %d" % (barstart, barstop))
victor@2 331 contours = [system['contour']]
victor@2 332 x1 = barstart
victor@2 333 y1 = system['location'][1]
victor@2 334 x2 = barstop
victor@2 335 y2 = system['location'][3]
victor@2 336 h = y2 - y1
victor@2 337 w = x2 - x1
victor@2 338 #print("height %d width %d" % (h, w))
victor@2 339 for blob in blobs:
victor@2 340 if blob['parent'] == system:
victor@2 341 if blob['rect']['x'] >= barstart and blob['rect']['x'] + blob['rect']['width'] <= barstop:
victor@2 342 contours.append(blob['contour'])
victor@2 343
victor@2 344 mask = np.zeros((self.imgHeight,self.imgWidth,1), np.uint8)
victor@2 345
victor@2 346 cv2.drawContours(mask, contours, -1, 255, -1);
victor@2 347
victor@2 348 inv = cv2.bitwise_not(img)
victor@2 349 dest = cv2.bitwise_and(inv,inv,mask = mask)
victor@2 350 dest = cv2.bitwise_not(dest)
victor@2 351 img_bar = dest[y1:y2, x1:x2]
victor@2 352 bar = {'image': img_bar,
victor@2 353 'page': dest,
victor@2 354 'location': [x1,y1,x2,y2]
victor@2 355 }
victor@2 356 result.append(bar)
victor@2 357 #show(img_bar)
victor@2 358 return(result)
victor@2 359
victor@2 360
victor@2 361
victor@2 362 def find_staveblobs(self, cutstaves=False,img=None):
victor@2 363 if img == None:
victor@2 364 img = self.img
victor@2 365 img_binary = self.img_binary
victor@2 366 else:
victor@2 367 img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
victor@2 368 ret2,img_binary = cv2.threshold(img_gray,
victor@2 369 0,255,cv2.
victor@2 370 THRESH_BINARY+cv2.
victor@2 371 THRESH_OTSU)
victor@2 372
victor@2 373 staves = self.find_staves(img)
victor@2 374 blobs = self.find_blobs(img_binary)
victor@2 375
victor@2 376 staveblobs = []
victor@2 377 otherblobs = []
victor@2 378
victor@2 379 if self.debug:
victor@2 380 for staff in staves:
victor@2 381 for line in staff:
victor@2 382 y = line.y_list[0]
victor@2 383 cv2.line(self.debug_img,(0,y),(self.imgWidth,y),(0,255,0),3)
victor@2 384 for blob in blobs:
victor@2 385 rect = blob['rect']
victor@2 386 blob['staves'] = []
victor@2 387 blob['system'] = False
victor@2 388 # large enough to contain a stave?
victor@2 389 blob['large'] = False
victor@2 390 if rect['width'] > (self.imgWidth * self.stavelineWidthThresh):
victor@2 391 blob['large'] = True
victor@2 392 if self.debug:
victor@2 393 cv2.drawContours(self.debug_img,[blob['contour']],-1, (0, 255,255),2)
victor@2 394 for staff in staves:
victor@2 395 inside = True
victor@2 396 for staveline in staff:
victor@2 397 leftmost = staveline.y_list[0]
victor@2 398 # all stafflines have to be in blob
victor@2 399 if leftmost < rect['y'] or leftmost > (rect['y'] + rect['height']):
victor@2 400 inside = False
victor@2 401 break
victor@2 402 if inside:
victor@2 403 blob['system'] = True
victor@2 404 blob['staves'].append(staff)
victor@2 405 if blob['system']:
victor@2 406 staveblobs.append(blob)
victor@2 407 print("found system with %d staves" % len(blob['staves']))
victor@2 408 if self.debug:
victor@2 409 cv2.drawContours(self.debug_img,[blob['contour']],-1, (0, 0,255), 2)
victor@2 410 else:
victor@2 411 otherblobs.append(blob)
victor@2 412
victor@2 413 return(staveblobs, otherblobs)
victor@2 414
victor@2 415 def find_systems(self):
victor@2 416 img = self.img_binary
victor@2 417 #print "finding staves"
victor@2 418 (staveblobs, otherblobs) = self.find_staveblobs()
victor@2 419 #print("found %d staves" % (len(staveblobs),))
victor@2 420 blobs = staveblobs + otherblobs
victor@2 421 self.blobs = blobs
victor@2 422 # systems = []
victor@2 423 systems = staveblobs
victor@2 424
victor@2 425 # attach disconnected bits in bounding box
victor@2 426 tidied = 0
victor@2 427 for blob in blobs:
victor@2 428 if not blob['system']:
victor@2 429 blob['parent'] = None
victor@2 430 for system in systems:
victor@2 431 rect = intersect(system['rect'], blob['rect'])
victor@2 432 if (rect['height'] > 0 and rect['width'] > 0):
victor@2 433 # Biggest intersection wins
victor@2 434 if (blob['parent'] == None) or (rect['area'] > blob['intersection']['area']):
victor@2 435 blob['parent'] = system
victor@2 436 blob['intersection'] = rect
victor@2 437
victor@2 438 # Just assign to closest bounding rectangle on y-axis
victor@2 439 if blob['parent'] == None:
victor@2 440 mindist = None
victor@2 441 for system in systems:
victor@2 442 dist = ydist(system['rect'], blob['rect'])
victor@2 443 if mindist == None or mindist > dist:
victor@2 444 blob['parent'] = system
victor@2 445 mindist = dist
victor@2 446 if blob['parent'] == None:
victor@2 447 print "wtf"
victor@2 448 else:
victor@2 449 tidied = tidied + 1
victor@2 450 #print "tidied %d" % tidied
victor@2 451
victor@2 452 # create new image for systems
victor@2 453 for system in systems:
victor@2 454 contours = [system['contour']]
victor@2 455 x1 = system['rect']['x']
victor@2 456 y1 = system['rect']['y']
victor@2 457 x2 = system['rect']['x'] + system['rect']['width']
victor@2 458 y2 = system['rect']['y'] + system['rect']['height']
victor@2 459
victor@2 460 children = 0
victor@2 461 for blob in blobs:
victor@2 462 if blob['parent'] == system:
victor@2 463 children = children + 1
victor@2 464 contours.append(blob['contour'])
victor@2 465 # include blob in image size/location
victor@2 466 x1 = min(x1, blob['rect']['x'])
victor@2 467 y1 = min(y1, blob['rect']['y'])
victor@2 468 x2 = max(x2, blob['rect']['x'] + blob['rect']['width'])
victor@2 469 y2 = max(y2, blob['rect']['y'] + blob['rect']['height'])
victor@2 470
victor@2 471 #print("found %d children" % children)
victor@2 472
victor@2 473 mask = np.zeros((self.imgHeight,self.imgWidth,1), np.uint8)
victor@2 474
victor@2 475 cv2.drawContours(mask, contours, -1, 255, -1);
victor@2 476 #src = img[x1:y1, x2:y2]
victor@2 477 #srcMask = mask[y1:y2, x1:x2]
victor@2 478 kernel = np.ones((4,4),np.uint8)
victor@2 479 mask=cv2.dilate(mask,kernel,iterations=3)
victor@2 480
victor@2 481 inv = cv2.bitwise_not(self.img)
victor@2 482 dest = cv2.bitwise_and(inv,inv,mask = mask)
victor@2 483 dest = cv2.bitwise_not(dest)
victor@2 484
victor@2 485 (h,w,d) = dest.shape
victor@2 486 system['image'] = dest
victor@2 487 system['location'] = (x1, y1, x2, y2)
victor@2 488 system['height'] = h
victor@2 489 system['width'] = w
victor@2 490
victor@2 491 min_x = self.imgWidth
victor@2 492
victor@2 493 for staff in system['staves']:
victor@2 494 for line in staff:
victor@2 495 min_x = min(min_x, line.left_x)
victor@2 496
victor@2 497 system['stave_min_x'] = min_x
victor@2 498
victor@2 499 #self.find_bars(system)
victor@2 500 #system['bar_images'] = self.extract_bars(system, blobs)
victor@2 501 if self.debug:
victor@2 502 cv2.imwrite('debug.png', self.debug_img)
victor@2 503 return(systems,blobs)
victor@2 504
victor@2 505 def blob_image(self,img,blob):
victor@2 506 r = blob['rect']
victor@2 507 y1 = r['y']
victor@2 508 x1 = r['x']
victor@2 509 y2 = r['y'] + r['height']
victor@2 510 x2 = r['x'] + r['width']
victor@2 511 return(img[y1:y2, x1:x2])
victor@2 512
victor@2 513 # def join_broken_staves(self):
victor@2 514 # img = self.img
victor@2 515 # (staveblobs, otherblobs) = self.find_staveblobs()
victor@2 516 # for i in range(0, len(staveblobs)-1):
victor@2 517 # for j in range(i, len(staveblobs)):
victor@2 518 # a = staveblobs[i]
victor@2 519 # b = staveblobs[j]
victor@2 520 # atop = a['rect']['x']
victor@2 521 # abot = a['rect']['x'] + a['rect']['height']
victor@2 522 # btop = b['rect']['x']
victor@2 523 # bbot = b['rect']['x'] + b['rect']['height']
victor@2 524 # if atop > btop and a
victor@2 525
victor@2 526
victor@2 527 def remove_ossia(self):
victor@2 528 img = self.img
victor@2 529
victor@2 530 ossia_mask = np.ones(self.img.shape[:2], dtype="uint8") * 255
victor@2 531
victor@2 532 (staveblobs, otherblobs) = self.find_staveblobs()
victor@2 533 staff_heights = map(lambda s: max_staff_height(s), staveblobs)
victor@2 534 staff_height = max(staff_heights)
victor@2 535 height_thresh = staff_height * 0.75
victor@2 536
victor@2 537 ossias = filter(lambda s: max_staff_height(s) < height_thresh, staveblobs)
victor@2 538
victor@2 539 print("blobs %d/%d" % (len(staveblobs), len(otherblobs)))
victor@2 540 #staves = self.find_staves(img)
victor@2 541
victor@2 542 working_img = img.copy()
victor@2 543
victor@2 544 for blob in staveblobs:
victor@2 545 miny = self.imgHeight
victor@2 546 for staff in blob['staves']:
victor@2 547 staffline = staff[0]
victor@2 548 miny = min(min(staffline.y_list),miny)
victor@2 549 cv2.line(working_img, (0,miny-4), (self.imgWidth,miny-4), (255,255,255), 4)
victor@2 550
victor@2 551 cv2.imwrite('test.png', working_img)
victor@2 552
victor@2 553 (staveblobs, otherblobs) = self.find_staveblobs(img=working_img)
victor@2 554 print("blobs %d/%d" % (len(staveblobs), len(otherblobs)))
victor@2 555 i = 0
victor@2 556 # for blob in otherblobs[112:113]:
victor@2 557 for blob in otherblobs:
victor@2 558 if blob['rect']['width'] < (self.imgWidth / 50):
victor@2 559 continue
victor@2 560 # if blob['rect']['width'] > (self.imgWidth / 2):
victor@2 561 # continue
victor@2 562
victor@2 563 src = self.img
victor@2 564 mask = np.zeros((self.imgHeight,self.imgWidth,1), np.uint8)
victor@2 565 cv2.drawContours(mask, [blob['contour']], -1, (255,255,255), -1);
victor@2 566 inv = cv2.bitwise_not(src)
victor@2 567 dest = cv2.bitwise_and(inv,inv,mask = mask)
victor@2 568 dest = cv2.bitwise_not(dest)
victor@2 569 cropped = self.blob_image(dest, blob)
victor@2 570
victor@2 571 gi = numpy_io.from_numpy(cropped)
victor@2 572 #sf = stafffinder_projections.StaffFinder_projections(gi)
victor@2 573 #sf = stafffinder_miyao.StaffFinder_miyao(gi)
victor@2 574 sf = stafffinder_dalitz.StaffFinder_dalitz(gi)
victor@2 575 sf.find_staves()
victor@2 576 staves = sf.get_skeleton()
victor@2 577
victor@2 578 if (len(staves) > 0):
victor@2 579 maxlines = max(map(len, staves))
victor@2 580 else:
victor@2 581 maxlines = 0
victor@2 582 if maxlines >= 4:
victor@2 583 print("aha ossia with %d lines" % (maxlines,))
victor@2 584 ossias.append(blob)
victor@2 585 for ossia in ossias:
victor@2 586 if self.debug:
victor@2 587 fn = 'removed_%d.png' % i
victor@2 588 cv2.imwrite(fn, cropped)
victor@2 589 i = i + 1
victor@2 590 cv2.drawContours(ossia_mask, [ossia['contour']], -1, 0, -1)
victor@2 591
victor@2 592 # erode a little to get rid of 'ghosting' around ossia
victor@2 593 kernel = np.ones((4,4),np.uint8)
victor@2 594 ossia_mask=cv2.erode(ossia_mask,kernel,iterations=4)
victor@2 595
victor@2 596 #cv2.imwrite('posterode.png', mask)
victor@2 597
victor@2 598 result = img.copy()
victor@2 599 inverted = cv2.bitwise_not(result)
victor@2 600 result = cv2.bitwise_or(inverted,inverted,mask=ossia_mask)
victor@2 601 result = cv2.bitwise_not(result)
victor@2 602
victor@2 603 if self.debug:
victor@2 604 cv2.imwrite('debug.png', self.debug_img)
victor@2 605
victor@2 606 self.img = result
victor@2 607
victor@2 608 def split_movements(self, outfileA, outfileB):
victor@2 609 # 2% of page width
victor@2 610 indentThresh = 0.02 * self.imgWidth
victor@2 611
victor@2 612 systems, blobs = self.find_systems()
victor@2 613
victor@2 614 # Top - down order
victor@2 615 systems = sorted(systems, key=lambda system: system['rect']['y'])
victor@2 616
victor@2 617 xs = []
victor@2 618 for system in systems:
victor@2 619 xs.append(system['stave_min_x'])
victor@2 620 threshold = min(xs) + indentThresh
victor@2 621
victor@2 622 # Skip the first one, we don't split if the movement starts at top
victor@2 623 # of page
victor@2 624 found = None
victor@2 625 for i in range(0,len(systems)):
victor@2 626 #cv2.imwrite("system%d.png" %i, systems[i]['image'])
victor@2 627 if xs[i] > threshold:
victor@2 628 if found != None:
victor@2 629 print "Oops, more than one movement found."
victor@2 630 found = i
victor@2 631 print("New movement at system %d" % (i+1))
victor@2 632
victor@2 633 if (found == 0):
victor@2 634 self.save_systems(outfileA, systems)
victor@2 635 else:
victor@2 636 self.save_systems(outfileA, systems[:found])
victor@2 637 self.save_systems(outfileB, systems[found:])
victor@2 638 return(found)
victor@2 639
victor@2 640 def save(self, outfile):
victor@2 641 cv2.imwrite(outfile, self.img)
victor@2 642
victor@2 643 def save_systems(self, outfile, systems):
victor@2 644 print "saving %s" % outfile
victor@2 645 contours = []
victor@2 646 for system in systems:
victor@2 647 contours.append(system['contour'])
victor@2 648
victor@2 649 for blob in self.blobs:
victor@2 650 if blob['parent'] == system:
victor@2 651 contours.append(blob['contour'])
victor@2 652
victor@2 653 mask = np.zeros((self.imgHeight,self.imgWidth,1), np.uint8)
victor@2 654
victor@2 655 cv2.drawContours(mask, contours, -1, 255, -1);
victor@2 656
victor@2 657 kernel = np.ones((4,4),np.uint8)
victor@2 658 mask=cv2.dilate(mask,kernel,iterations=1)
victor@2 659
victor@2 660 inv = cv2.bitwise_not(self.img)
victor@2 661 dest = cv2.bitwise_and(inv,inv,mask = mask)
victor@2 662 dest = cv2.bitwise_not(dest)
victor@2 663 cv2.imwrite(outfile,dest)