def _estimate_staffline_distance()

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))