in moonlight/util/run_length.py [0:0]
def vertical_run_length_encoding(image):
"""Returns the runs in each column of the image.
A run is a subsequence of consecutive pixels that all have the same value.
Internally, we treat the image as batches of single-column images in order to
use connected component analysis.
Args:
image: A 2D image.
Returns:
The column index of each vertical run.
The value in the image for each vertical run.
The length of each vertical run.
"""
with tf.name_scope('run_length_encoding'):
image = tf.convert_to_tensor(image, name='image', dtype=tf.bool)
# Set arbitrary, distinct, nonzero values for True and False pixels.
# True pixels map to 2, and False pixels map to 1.
# Transpose the image, and insert an extra dimension. This creates a batch
# of "images" for connected component analysis, where each image is a single
# column of the original image. Therefore, the connected components are
# actually runs from a single column.
components = contrib_image.connected_components(
tf.to_int32(tf.expand_dims(tf.transpose(image), axis=1)) + 1)
# Flatten in order to use with unsorted segment ops.
flat_components = tf.reshape(components, [-1])
num_components = tf.maximum(0, tf.reduce_max(components) + 1)
# Get the column index corresponding to each pixel present in
# flat_components.
column_indices = tf.reshape(
tf.tile(
# Count 0 through `width - 1` on axis 0, then repeat each element
# `height` times.
tf.expand_dims(tf.range(tf.shape(image)[1]), axis=1),
multiples=[1, tf.shape(image)[0]]),
# pyformat: disable
[-1])
# Take the column index for each component. For each component index k,
# we want any entry of column_indices where the corresponding entry in
# flat_components is k. column_indices should be the same for all pixels in
# the same component, so we can just take the max of all of them. Disregard
# component 0, which just represents all of the zero pixels across the
# entire array (should be empty, because we pass in a nonzero image).
component_columns = tf.unsorted_segment_max(column_indices, flat_components,
num_components)[1:]
# Take the original value of each component. Again, the value should be the
# same for all pixels in a single component, so we can just take the max.
component_values = tf.unsorted_segment_max(
tf.to_int32(tf.reshape(tf.transpose(image), [-1])), flat_components,
num_components)[1:]
# Take the length of each component (run), by counting the number of pixels
# in the component.
component_lengths = tf.to_int32(tf.bincount(flat_components)[1:])
return component_columns, component_values, component_lengths