Ejemplo n.º 1
0
def hough_peaks(hough_bins, thetas, minval=0, invalidate_distance=0):
  """Finds the peak lines in Hough space.

  Args:
    hough_bins: Hough bins returned by `hough_lines`.
    thetas: Angles; argument given to `hough_lines`.
    minval: Minimum vote count for a Hough bin to be considered. int or float.
    invalidate_distance: When selecting a line `(rho, theta)`, invalidate all
        lines with the same theta and `+- invalidate_distance` from `rho`.
        int32. Caveat: this should only be used if all theta values are similar.
        If thetas cover a wide range, this will invalidate lines that might not
        even intersect.

  Returns:
    Tensor of peak rho indices (int32).
    Tensor of peak theta values (float32).
  """
  thetas = tf.convert_to_tensor(thetas)
  bin_score_dtype = thetas.dtype  # floating point score derived from hough_bins
  minval = tf.convert_to_tensor(minval)
  if minval.dtype.is_floating:
    minval = tf.ceil(minval)
  invalidate_distance = tf.convert_to_tensor(
      invalidate_distance, dtype=tf.int32)
  # Choose the theta with the highest bin value for each rho.
  selected_theta_ind = tf.argmax(hough_bins, axis=0)
  # Take the Hough bin value for each rho and the selected theta.
  hough_bins = tf.gather_nd(hough_bins,
                            tf.stack(
                                [
                                    tf.cast(selected_theta_ind, tf.int32),
                                    tf.range(tf.shape(hough_bins)[1])
                                ],
                                axis=1))
  # hough_bins are integers. Subtract a penalty (< 1) for lines that are not
  # horizontal or vertical, so that we break ties in favor of the more
  # horizontal or vertical line.
  infinitesimal = tf.constant(1e-10, bin_score_dtype)
  # Decrease minval so we don't discard bins that are penalized, if they
  # originally equalled minval.
  minval = tf.cast(minval, bin_score_dtype) - infinitesimal
  selected_thetas = tf.gather(thetas, selected_theta_ind)
  # min(|sin(t)|, |cos(t)|) is 0 for horizontal and vertical angles, and between
  # 0 and 1 otherwise.
  penalty = tf.multiply(
      tf.minimum(
          tf.abs(tf.sin(selected_thetas)), tf.abs(tf.cos(selected_thetas))),
      infinitesimal)
  bin_score = tf.cast(hough_bins, bin_score_dtype) - penalty
  # Find the peaks in the 1D hough_bins array.
  peak_rhos = segments.peaks(
      bin_score, minval=minval, invalidate_distance=invalidate_distance)
  # Get the actual angles for each selected peak.
  peak_thetas = tf.gather(thetas, tf.gather(selected_theta_ind, peak_rhos))
  return peak_rhos, peak_thetas
Ejemplo n.º 2
0
 def test_peaks_invalidate_distance(self):
   values = tf.constant([0, 0, 10, 0, 5, 3, 2, 1, 2, 3, 8, 8, 7, 8])
   with self.test_session():
     self.assertAllEqual(
         segments.peaks(values, invalidate_distance=0).eval(), [2, 4, 10, 13])
     self.assertAllEqual(
         segments.peaks(values, invalidate_distance=1).eval(), [2, 4, 10, 13])
     self.assertAllEqual(
         segments.peaks(values, invalidate_distance=2).eval(), [2, 10, 13])
     self.assertAllEqual(
         segments.peaks(values, invalidate_distance=3).eval(), [2, 10])
     self.assertAllEqual(
         segments.peaks(values, invalidate_distance=4).eval(), [2, 10])
     self.assertAllEqual(
         segments.peaks(values, invalidate_distance=7).eval(), [2, 10])
     self.assertAllEqual(
         segments.peaks(values, invalidate_distance=8).eval(), [2, 13])
     self.assertAllEqual(
         segments.peaks(values, invalidate_distance=99).eval(), [2])
Ejemplo n.º 3
0
 def test_peaks_one_segment(self):
   values = tf.constant([0, 0, 0, 0, 3, 0, 0, 0, 0])
   with self.test_session():
     self.assertAllEqual(segments.peaks(values).eval(), [4])
Ejemplo n.º 4
0
 def test_peaks_array_filled_with_same_value(self):
   for value in (0, 42, 4.2):
     arr = tf.fill([100], value)
     with self.test_session():
       self.assertEmpty(segments.peaks(arr).eval())
Ejemplo n.º 5
0
 def test_peaks_empty(self):
   with self.test_session():
     self.assertAllEqual(segments.peaks([]).eval(), [])
Ejemplo n.º 6
0
 def test_peaks(self):
   values = tf.constant([5, 3, 1, 1, 0, 1, 2, 3, 3, 3, 2, 3, 4, 1, 2])
   with self.test_session():
     self.assertAllEqual(segments.peaks(values).eval(), [0, 8, 12, 14])
     self.assertAllEqual(segments.peaks(values, minval=3).eval(), [0, 8, 12])
Ejemplo n.º 7
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))