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) |