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
Esempio n. 3
0
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)
Esempio n. 4
0
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)