def calc_slopes(img, chunks, lines):
    chunk_size = height(img) // chunks
    slopes = [[0 for _ in range(width(img))] for c in range(chunks)]
    for i in range(width(img)):
        s = [0 for _ in range(chunks)]
        num = [0 for _ in range(chunks)]
        for line in lines:
            x1,y1,x2,y2 = line[0]
            if (x1 <= i and x2 >= i) or (x1 <= i and x2 >= i):
                for chunk in range(chunks):
                    c1 = y1 // chunk_size
                    c2 = y2 // chunk_size
                    if (c1 >= chunk and c2 <= chunk) or (c2 >= chunk and c1 <= chunk):
                        s[chunk] += float(y2 - y1) / float(x2 - x1)
                        num[chunk] += 1

        for j in range(chunks):
            if num[j] > 0:
                slopes[j][i] = float(s[j]) / float(num[j])


    img_blank = img.copy()
    k = 0
    for s in slopes:
        row = int(np.round((height(img_blank) // len(slopes)) * (k + .5)))
        k += 1
        line = calc_staff_line(s, row, img)
        for pt in line:
            img_blank[pt[0]][pt[1]] = 255

    return slopes, img_blank
def calc_staff_line_chunks(slopes, row, img, chunk_size, interval = 15):
    white_seen = 0
    col = 0
    r = row
    line = []
    for col in range(0, width(img), interval):
        if (int(np.round(r)) < height(img) and col < width(img)):
            for i in range(interval):
                line.append((int(np.round(r)), col + i))
            if(img[int(np.round(r))][col] == 255):
                white_seen += 1
        if (int(r // chunk_size) < len(slopes) and int(r // chunk_size) >= 0):
            r += slopes[int(r // chunk_size)][col] * float(interval)
        col += 1
    return line, white_seen*interval
def find_staff_candidates(img, slopes, T_staff_cand, T_length, num_chunks, staff_height, staff_space, min_y, max_y):
    staff_candidates = []
    chunk_size = height(img) // num_chunks

    rows = [i for i in range(min_y - 50, max_y + 50)]

    for row in rows:
        pts, total_white = calc_staff_line_chunks(slopes, row, img, chunk_size)
        if total_white > 0:
            if (float(total_white) / width(img) > T_staff_cand):
                if (len(staff_candidates) == 0
                or (len(staff_candidates) > 0 and row - staff_candidates[-1][0] > T_length)):
                    staff_candidates.append((row, pts, total_white))
                if (len(staff_candidates) > 0 and row - staff_candidates[-1][0] <= T_length and total_white > staff_candidates[-1][2]):
                    staff_candidates[len(staff_candidates) - 1] = (row, pts, total_white)

    to_remove = []
    T_staff = (5 * staff_height) + (7 * staff_space)
    curr = []
    for cand in staff_candidates:
        curr.append(cand)
        if (curr[-1][0] - curr[0][0] > T_staff):
            curr = curr[:len(curr) - 1]
            while (len(curr) > 5):
                tr = [x for x in curr if x[2] == min([c[2] for c in curr])][0]
                to_remove.append(tr)
                curr = [x for x in curr if x != tr]

            curr = []

    for r in to_remove:
        staff_candidates.remove(r)

    print([str(x[0]) + " " + str(x[2]) for x in staff_candidates])
    return staff_candidates
def calc_staff_line(slopes, row, img):
    col = 0
    r = row
    line = []
    for slope in slopes:
        if (int(np.round(r)) < height(img) and col < width(img)):
            line.append((int(np.round(r)), col))
        r += slope
        col += 1
    return line
def remove_text(img):
    new_img = img.copy()
    kernel = cv.getStructuringElement(cv.MORPH_CROSS, (3, 3))
    dilated = cv.dilate(new_img, kernel, iterations=5)
    _, contours, hierarchy = cv.findContours(dilated, cv.RETR_EXTERNAL,
                                             cv.CHAIN_APPROX_NONE)
    for contour in contours:
        [x, y, w, h] = cv.boundingRect(contour)
        if (w < width(img) // 2):
            cv.rectangle(img, (x, y), (x + w, y + h), (0, 0, 0), cv.FILLED)
    return img
def estimate_staff_stats(img):
    white_runs = []
    black_runs = []
    for i in range(0, width(img), 20):
        wr, br = calc_runs(img[:, i], 255, 0)
        white_runs.extend(wr)
        black_runs.extend(br)

    staff_space = int(np.median(black_runs))
    staff_height = int(np.median(white_runs)) #image is bit flipped

    T_length = int(min(2.0 * staff_height, staff_height + staff_space))

    return staff_height, staff_space, T_length
def create_initial_staff_image(img, T_length):
    img_copy = img.copy()
    for col in range(width(img_copy)):
        i = 0
        while(i < height(img_copy)):
            while(i < height(img_copy) and img_copy[i][col] == 0):
                i+=1
            mark = i
            while(i < height(img_copy) and img_copy[i][col] == 255):
                i+=1
            if (i - mark > T_length):
                for j in range(mark, i):
                    img_copy[j][col] = 0

    return img_copy