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