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