Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Calculate offsets for scrolling piano sheet music
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function, absolute_import, division
import itertools
import json
from PIL import Image, ImageFilter
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = itertools.tee(iterable)
next(b, None)
return zip(a, b)
def calc_offsets(image_path):
im =
# binarize and transpose the image, so that columns in the original become rows
imgbin = im.convert("1")
imgbin_rotated = imgbin.transpose(Image.ROTATE_90)
width, height = imgbin_rotated.size
imgdata = list(imgbin_rotated.getdata())
def getrow(row):
start = row * width
end = start + width
return imgdata[start:end]
# find the line in the middle...
middle_row = getrow(height // 2)
# find all the points where the color changes...
changes = [i for i, (b, a) in enumerate(pairwise(middle_row)) if b != a]
# TODO: we probably will want to do some filtering here to ignore short
# changes among a lot of white
# guesstimate a minimum for the minimum amount of whitespace between the parts
staff_distance_min = width / 20
# calculate offsets based on the above guesstimate...
offsets = [a - (a - b)//2 for b, a in pairwise(changes) if a - b > staff_distance_min]
# print the offsets
return [0] + offsets
def run(args):
print(json.dumps([calc_offsets(path) for path in args.image_paths], indent=2))
if '__main__' == __name__:
import argparse
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('image_paths', nargs='+')
args = parser.parse_args()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment