in moonlight/staves/staffline_distance.py [0:0]
def _estimate_staffline_distance(columns, lengths):
"""Estimates the staffline distances of a music score.
Args:
columns: 1D array. The column indices of each vertical run.
lengths: 1D array. The length of each consecutive vertical run.
Returns:
A 1D tensor of possible staffline distances in the image.
"""
with tf.name_scope('estimate_staffline_distance'):
run_pair_lengths = lengths[:-1] + lengths[1:]
keep_pair = tf.equal(columns[:-1], columns[1:])
staffline_distance_histogram = tf.bincount(
tf.boolean_mask(run_pair_lengths, keep_pair),
# minlength required to avoid errors on a fully white image.
minlength=_MAX_STAFFLINE_DISTANCE_THICKNESS_VALUE,
maxlength=_MAX_STAFFLINE_DISTANCE_THICKNESS_VALUE)
peaks = segments.peaks(
staffline_distance_histogram,
minval=_MIN_STAFFLINE_DISTANCE_SCORE,
invalidate_distance=_STAFFLINE_DISTANCE_INVALIDATE_DISTANCE)
def do_filter_peaks():
"""Process the peaks if they are non-empty.
Returns:
The filtered peaks. Peaks below the cutoff when compared to the highest
peak are removed. If the peaks are invalid, then an empty list is
returned.
"""
histogram_size = tf.shape(staffline_distance_histogram)[0]
peak_values = tf.to_float(tf.gather(staffline_distance_histogram, peaks))
max_value = tf.reduce_max(peak_values)
allowed_peaks = tf.greater_equal(peak_values,
max_value * tf.constant(_PEAK_CUTOFF))
# Check if there are too many detected staffline distances, and we should
# return an empty list.
allowed_peaks &= tf.less_equal(
tf.reduce_sum(tf.to_int32(allowed_peaks)),
_MAX_ALLOWED_UNIQUE_STAFFLINE_DISTANCES)
# Check if any values sufficiently far away from the peaks are too high.
# This means the peaks are not sharp enough and we should return an empty
# list.
far_from_peak = tf.greater(
tf.reduce_min(
tf.abs(tf.range(histogram_size)[None, :] - peaks[:, None]),
axis=0), _STAFFLINE_DISTANCE_INVALIDATE_DISTANCE)
allowed_peaks &= tf.less(
tf.to_float(
tf.reduce_max(
tf.boolean_mask(staffline_distance_histogram,
far_from_peak))),
max_value * tf.constant(_PEAK_CUTOFF))
return tf.boolean_mask(peaks, allowed_peaks)
return tf.cond(
tf.greater(tf.shape(peaks)[0], 0), do_filter_peaks,
lambda: tf.identity(peaks))