def find_vertical_regions(image, image_vertical_lines=None, staff_spacing=None, pixel_span=2, eight_way=True): """Return regions from image that contain vertical lines :param image: :param image_vertical_lines: :param staff_spacing: :param pixel_span: :param eight_way: """ if image_vertical_lines is None: image_vertical_lines = imo.open_image_vertically( image, staff_spacing) return find_regions(image, image_vertical_lines, pixel_span=pixel_span, eight_way=eight_way)
def find_vertical_notes(org_image, regions, staff, staff_spacing, staff_distance, tolerance=None, flag_min_match=0.7, note_head_min_match=0.8, half_note_head_min_match=0.65): image = org_image.copy() rel_staff = get_rel_staff(staff, staff_distance) recognized_notes = [] unrecognized_regions = [] small_regions = [] note_heads_templates = {} for templateName in search_for_templates(["note_heads/filled"]): template = imp.load_image(templateName) template = imp.resize_image(template, (int(round(staff_spacing)), int(round(staff_spacing)))) template = imp.image_gray(template) template = imp.image_bin_otsu(template) template = imp.invert(template) note_heads_templates[templateName] = template half_note_heads_templates = {} for templateName in search_for_templates(["note_heads/half", "note_heads/whole"]): template = imp.load_image(templateName) template = imp.resize_image(template, (int(round(staff_spacing)), int(round(staff_spacing)))) template = imp.image_gray(template) template = imp.image_bin_otsu(template) template = imp.invert(template) half_note_heads_templates[templateName] = template for index, region in enumerate(regions): org_reg_c = min([c for r, c in region]) org_reg_r = min([r for r, c in region]) region_image = irr.get_region_image(image, region) if len(region_image) > 3 * staff_spacing: img_vert_lines = imo.open_image_vertically(region_image, staff_spacing, 3) vertical_lines = find_regions(img_vert_lines)[1] remove_white_pixels([region_image], vertical_lines) avg_vert_line_thickness = find_avg_thickness(vertical_lines) if tolerance is None: tolerance = avg_vert_line_thickness # Find beams by searching for regions between vertical lines print("Finding full beams...") full_beams = [] connected_regions = [] separate_regions = [] sub_regions = find_regions(region_image)[1] for sub_region in sub_regions: start_vert_line = None end_vert_line = None lines = [] min_col = min([c for r, c in sub_region]) max_col = max([c for r, c in sub_region]) for line in vertical_lines: min_line_col = min([c for r, c in line]) max_line_col = max([c for r, c in line]) if -tolerance <= min_col - max_line_col <= tolerance: start_vert_line = line lines += [line] elif -tolerance <= min_line_col - max_col <= tolerance: end_vert_line = line lines += [line] elif min_col < min_line_col < max_col: lines += [line] if start_vert_line is not None and end_vert_line is not None: full_beams += [(sub_region, start_vert_line, end_vert_line, lines)] elif len(lines) > 0: connected_regions += [(sub_region, lines[0])] else: separate_regions += [sub_region] # Find half beams print("Finding half beams...") half_beams = [] for sub_region in connected_regions: max_row = max([r for r, c in sub_region[0]]) min_row = min([r for r, c in sub_region[0]]) min_col = min([c for r, c in sub_region[0]]) max_col = max([c for r, c in sub_region[0]]) for beam in full_beams: if sub_region[1] in beam[3]: try: min_beam_row = min([r for r, c in beam[0] if min_col <= c <= max_col]) max_beam_row = max([r for r, c in beam[0] if min_col <= c <= max_col]) except ValueError: continue distance = None if min_row > max_beam_row: distance = min_row - max_beam_row elif max_row < min_beam_row: distance = min_beam_row - max_row if distance is not None and distance < staff_spacing: half_beams += [sub_region] break for half_beam in half_beams: connected_regions.remove(half_beam) # find flags print("Finding flags...") flags = [] flag_templates = search_for_templates("flags") for sub_region in connected_regions: best_match = template_match(get_region_image(region_image, sub_region[0]), template_filepaths=flag_templates, resize=True, print_results=False) if flag_min_match <= best_match[1]: flags += [(sub_region, best_match)] for flag, match in flags: connected_regions.remove(flag) # find note_heads print("Finding note heads...") note_heads = [] for connected_region in connected_regions: min_r = rel_staff[0][-1] line_index = 0.5 while abs(min_r - org_reg_r) >= staff_spacing // 2: if min_r > org_reg_r: min_r -= staff_spacing // 2 line_index -= 0.5 else: min_r += staff_spacing // 2 line_index += 0.5 min_r -= org_reg_r min_r = int(min_r) max_r = max([r for r, c in connected_region[0]]) for start_r in range(min_r, max_r, int(staff_spacing // 2)): sub_region = [value for value in connected_region[0] if start_r + staff_spacing >= value[0] >= start_r] if len(sub_region) > 0: sub_region_img = get_region_image(region_image, sub_region) best_match = template_match(sub_region_img, template_images=note_heads_templates, print_results=False) if note_head_min_match <= best_match[1]: note_heads += [(sub_region, connected_region, line_index, best_match)] else: best_match = template_match(sub_region_img, template_images=half_note_heads_templates, print_results=False) if half_note_head_min_match <= best_match[1]: note_heads += [(sub_region, connected_region, line_index, ("templates/note_heads/half_01", best_match[1]))] line_index += 0.5 for note_head, connected_region, line_index, match in note_heads: if connected_region in connected_regions: connected_regions.remove(connected_region) # recognize note print("Recognizing notes' properties...") checked_flags = [] notes = [] for note_head, connected_region, line_index, match in note_heads: height = line_index note_head_type = match[0].split('/')[-1].split('_')[0] flags_and_beams = 0 line = connected_region[1] for beam in full_beams: if line in beam[3]: flags_and_beams += 1 for half_beam in half_beams: if line == half_beam[1]: flags_and_beams += 1 for flag, flag_match in flags: if line == flag[1]: flags_and_beams += int(flag_match[0].split('/')[-1].split('_')[0]) / 8 checked_flags += [(flag, flag_match)] if flags_and_beams > 0: duration = 1 / 4. for i in range(flags_and_beams): duration /= 2 else: duration = 1 / 4. if note_head_type == "filled" else 0.5 notes += [(min([c for r, c in connected_region[0]]), height, note_head_type, duration)] for flag in flags: if flag not in checked_flags: connected_region = flag[0] min_r = rel_staff[0][-1] line_index = 0.5 while abs(min_r - org_reg_r) >= staff_spacing // 2: if min_r > org_reg_r: min_r -= staff_spacing // 2 line_index -= 0.5 else: min_r += staff_spacing // 2 line_index += 0.5 min_r -= org_reg_r min_r = int(min_r) max_r = max([r for r, c in connected_region[0]]) for start_r in range(min_r, max_r, int(staff_spacing // 2)): sub_region = [value for value in connected_region[0] if start_r + staff_spacing >= value[0] >= start_r] if len(sub_region) > 0: best_match = template_match(get_region_image(region_image,sub_region), template_images=half_note_heads_templates, print_results=False) if half_note_head_min_match <= best_match[1]: note_heads += [(sub_region, connected_region, line_index, ("templates/note_heads/half_01", best_match[1]))] notes += [(min([c for r, c in connected_region[0]]), line_index, "half", 0.5)] line_index += 0.5 notes = sorted(notes) recognized_notes += [(region, org_reg_c, notes)] unrecognized_regions += [(region, connected_regions, separate_regions)] if False: # Remove flags and beams from original image to_remove = [] to_remove_from_region_image = [] for flag, match in flags: for r, c in flag[0]: to_remove += [(r + org_reg_r, c + org_reg_c)] to_remove_from_region_image += [(r, c)] for half_beam in half_beams: for r, c in half_beam[0]: to_remove += [(r + org_reg_r, c + org_reg_c)] to_remove_from_region_image += [(r, c)] for beam in full_beams: for r, c in beam[0]: to_remove += [(r + org_reg_r, c + org_reg_c)] to_remove_from_region_image += [(r, c)] for note_head, connected_region, line_index, match in note_heads: for r, c in note_head: to_remove += [(r + org_reg_r, c + org_reg_c)] to_remove_from_region_image += [(r, c)] for line in vertical_lines: for r, c in line: to_remove += [(r + org_reg_r, c + org_reg_c)] to_remove_from_region_image += [(r, c)] remove_white_pixels([image], [to_remove]) remove_white_pixels([region_image], [to_remove_from_region_image]) else: small_regions += [region] # remove_white_pixels([image], [region]) recognized_notes.sort(key=lambda x: x[1]) return recognized_notes
def open_image_vertically(staff_image, avg_staff_spacing): print("Opening staff image with vertical kernel...") return imo.open_image_vertically(staff_image, avg_staff_spacing)
def analyze_staff(img_wo_lines, staff, index, avg_staff_spacing, avg_staff_distance): print("Analyzing staff %s" % (index + 1)) staff_image_top = staff[0][0] - avg_staff_distance//2 staff_image_bot = staff[-1][-1] + avg_staff_distance//2 staff_image = img_wo_lines[staff_image_top: staff_image_bot] staff_copy = staff_image.copy() img_vert_lines = open_image_vertically(staff_image, avg_staff_spacing) vertical_lines = find_regions(img_vert_lines, pixel_span=1, eight_way=False)[1] img_vert_objects, vertical_regions = \ find_vertical_regions(staff_image, img_vert_lines, avg_staff_spacing, pixel_span=1, eight_way=False) bar_lines = get_bar_lines(vertical_regions, vertical_lines, staff) remove_bar_lines([staff_image, img_vert_lines], bar_lines, []) img_vert_objects, vertical_regions = \ find_vertical_regions(staff_image, img_vert_lines, avg_staff_spacing, pixel_span=3) clefs = get_clefs(staff_image, vertical_regions, bar_lines) remove_clefs([staff_image, img_vert_objects, img_vert_lines], clefs, vertical_regions) endings = get_endings(staff_image, vertical_regions, staff[0][0] - staff_image_top) remove_endings([staff_image, img_vert_objects, img_vert_lines], endings, vertical_regions) regions = find_regions(staff_image, pixel_span=1, eight_way=False)[1] dots = find_dots(staff_image, regions, avg_staff_spacing) remove_dots([staff_image], dots, [regions]) img_vert_lines = imo.open_image_vertically(staff_image, avg_staff_spacing, 3.5) img_vert_objects, vertical_regions = \ find_vertical_regions(staff_image, img_vert_lines, avg_staff_spacing, pixel_span=2, eight_way=True) img_vert_lines = imo.open_image_vertically(staff_image, avg_staff_spacing, 1.5) img_vert_objects, vertical_regions = \ find_vertical_regions(imo.image_subtract(staff_image, img_vert_objects), img_vert_lines, avg_staff_spacing, pixel_span=1, eight_way=False) accidentals = find_accidentals(img_vert_objects, vertical_regions) remove_accidentals([staff_image], accidentals, None) img_vert_objects, vertical_regions = \ find_vertical_regions(staff_image, img_vert_lines, avg_staff_spacing, pixel_span=2) time_signatures = get_time_signatures(staff_image, vertical_regions, bar_lines, [clef[0] for clef in clefs]) remove_time_signatures([staff_image, img_vert_objects, img_vert_lines], time_signatures, vertical_regions) img_vert_objects, vertical_regions = \ find_vertical_regions(staff_image, img_vert_lines, avg_staff_spacing, pixel_span=4, eight_way=True) notes = find_vertical_notes(img_vert_objects, vertical_regions, staff, avg_staff_spacing, avg_staff_distance) remove_vertical_notes([staff_image, img_vert_objects, img_vert_lines], notes, vertical_regions) remove_ledgers([staff_image], regions, staff, avg_staff_distance) regions = find_regions(staff_image, pixel_span=2)[1] rests = find_rests(staff_image, regions, bar_lines) remove_rests([staff_image], [rest[0] for rest in rests], [regions]) regions = find_regions(staff_image, pixel_span=3)[1] whole_notes = find_whole_notes(staff_image, regions, bar_lines, [clef[0] for clef in clefs], [time_signature[0] for time_signature in time_signatures], staff, avg_staff_spacing, avg_staff_distance) remove_whole_notes([staff_image], [note[0] for note in whole_notes], [regions]) export_data(index, bar_lines, clefs, time_signatures, endings, notes, accidentals, dots, whole_notes, rests, staff, avg_staff_spacing, avg_staff_distance) imp.display_image(staff_copy)