def make_template_images(template_filepaths, size=None): """Make dictionary of images from template_filepaths. :param template_filepaths: :param size: """ templates = {} for filepath in template_filepaths: template = imp.load_image(filepath) if size is not None: template = imp.resize_image(template, size) template = imp.image_gray(template) template = imp.image_bin_otsu(template) template = imp.invert(template) templates[filepath] = template return templates
def find_whole_notes(image, regions, bar_lines, clefs, time_signatures, staff, staff_spacing, staff_distance, min_match=0.61): note_templates = {} for templateName in search_for_templates(["note_heads/whole", "note_heads/double_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) note_templates[templateName] = template rel_staff = get_rel_staff(staff, staff_distance) # find note_heads print("Finding whole note heads...") notes = [] possible_regions = get_possible_whole_note_regions(regions, bar_lines, clefs, time_signatures, staff_spacing) for region in possible_regions: reg_top = min([r for r, c in region]) reg_height, reg_width = get_region_image(image, region).shape[:2] if staff_spacing <= reg_width and reg_height >= staff_spacing: min_r = rel_staff[0][-1] line_index = 0.5 while abs(min_r - reg_top) >= staff_spacing // 2: if min_r > reg_top: min_r -= staff_spacing // 2 line_index -= 0.5 else: min_r += staff_spacing // 2 line_index += 0.5 min_r = int(min_r) max_r = max([r for r, c in region]) for start_r in range(min_r, max_r, int(staff_spacing // 2)): sub_region = [value for value in region if start_r + staff_spacing >= value[0] >= start_r] if len(sub_region) > 0: sub_region_img = get_region_image(image, sub_region) best_match = template_match(sub_region_img, template_images=note_templates, print_results=False) if min_match <= best_match[1]: notes += [(region, line_index, best_match)] line_index += 0.5 return notes
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 invert(image): print("Inverting image...") return imp.invert(image)