kwimage.im_runlen

Logic pertaining to run-length encodings

SeeAlso:
kwimage.structs.mask - stores binary segmentation masks, using RLEs as a

backend representation. Also contains cython logic for handling the coco-rle format.

Module Contents

Functions

encode_run_length(img, binary=False, order='C')

Construct the run length encoding (RLE) of an image.

decode_run_length(counts, shape, binary=False, dtype=np.uint8, order='C')

Decode run length encoding back into an image.

rle_translate(rle, offset, output_shape=None)

Translates a run-length encoded image in RLE-space.

_rle_bytes_to_array(s, impl='auto')

Uncompresses a coco-bytes RLE into an array representation.

_rle_array_to_bytes(counts, impl='auto')

Compresses an array RLE into a coco-bytes RLE.

kwimage.im_runlen.encode_run_length(img, binary=False, order='C')[source]

Construct the run length encoding (RLE) of an image.

Parameters
  • img (ndarray) – 2D image

  • binary (bool, default=False) – If true, assume that the input image only contains 0’s and 1’s. Set to True for compatibility with COCO (which does not support multi-value RLE encodings).

  • order ({‘C’, ‘F’}, default=’C’) – row-major (C) or column-major (F)

Returns

encoding: dictionary items are:

counts (ndarray): the run length encoding

shape (Tuple): the original image shape.

This should be in standard shape row-major (e.g. h/w) order

binary (bool):

if True, the counts are assumed to encode only 0’s and 1’s, otherwise the counts encoding specifies any numeric values.

order ({‘C’, ‘F’}, default=’C’): encoding order

Return type

Dict[str, object]

SeeAlso:
  • kwimage.Mask - a cython-backed data structure to handle coco-style RLEs

Example

>>> import ubelt as ub
>>> lines = ub.codeblock(
>>>     '''
>>>     ..........
>>>     ......111.
>>>     ..2...111.
>>>     .222..111.
>>>     22222.....
>>>     .222......
>>>     ..2.......
>>>     ''').replace('.', '0').splitlines()
>>> img = np.array([list(map(int, line)) for line in lines])
>>> encoding = encode_run_length(img)
>>> target = np.array([0,16,1,3,0,3,2,1,0,3,1,3,0,2,2,3,0,2,1,3,0,1,2,5,0,6,2,3,0,8,2,1,0,7])
>>> assert np.all(target == encoding['counts'])

Example

>>> binary = True
>>> img = np.array([[1, 0, 1, 1, 1, 0, 0, 1, 0]])
>>> encoding = encode_run_length(img, binary=True)
>>> assert encoding['counts'].tolist() == [0, 1, 1, 3, 2, 1, 1]
kwimage.im_runlen.decode_run_length(counts, shape, binary=False, dtype=np.uint8, order='C')[source]

Decode run length encoding back into an image.

Parameters
  • counts (ndarray) – the run-length encoding

  • shape (Tuple[int, int])

  • binary (bool) – if the RLE is binary or non-binary. Set to True for compatibility with COCO.

  • dtype (dtype, default=np.uint8) – data type for decoded image

  • order ({‘C’, ‘F’}, default=’C’) – row-major (C) or column-major (F)

Returns

the reconstructed image

Return type

ndarray

Example

>>> from kwimage.im_runlen import *  # NOQA
>>> img = np.array([[1, 0, 1, 1, 1, 0, 0, 1, 0]])
>>> encoded = encode_run_length(img, binary=True)
>>> recon = decode_run_length(**encoded)
>>> assert np.all(recon == img)
>>> import ubelt as ub
>>> lines = ub.codeblock(
>>>     '''
>>>     ..........
>>>     ......111.
>>>     ..2...111.
>>>     .222..111.
>>>     22222.....
>>>     .222......
>>>     ..2.......
>>>     ''').replace('.', '0').splitlines()
>>> img = np.array([list(map(int, line)) for line in lines])
>>> encoded = encode_run_length(img)
>>> recon = decode_run_length(**encoded)
>>> assert np.all(recon == img)
kwimage.im_runlen.rle_translate(rle, offset, output_shape=None)[source]

Translates a run-length encoded image in RLE-space.

Parameters
  • rle (dict) – an enconding dict returned by encode_run_length

  • offset (Tuple) – x,y offset, CAREFUL, this can only accept integers

  • output_shape (Tuple, optional) – h,w of transformed mask. If unspecified the input rle shape is used.

SeeAlso:

# ITK has some RLE code that looks like it can perform translations https://github.com/KitwareMedical/ITKRLEImage/blob/master/include/itkRLERegionOfInterestImageFilter.h

Doctest:
>>> # test that translate works on all zero images
>>> img = np.zeros((7, 8), dtype=np.uint8)
>>> rle = encode_run_length(img, binary=True, order='F')
>>> new_rle = rle_translate(rle, (1, 2), (6, 9))
>>> assert np.all(new_rle['counts'] == [54])

Example

>>> from kwimage.im_runlen import *  # NOQA
>>> img = np.array([
>>>     [1, 1, 1, 1],
>>>     [0, 1, 0, 0],
>>>     [0, 1, 0, 1],
>>>     [1, 1, 1, 1],], dtype=np.uint8)
>>> rle = encode_run_length(img, binary=True, order='C')
>>> offset = (1, -1)
>>> output_shape = (3, 5)
>>> new_rle = rle_translate(rle, offset, output_shape)
>>> decoded = decode_run_length(**new_rle)
>>> print(decoded)
[[0 0 1 0 0]
 [0 0 1 0 1]
 [0 1 1 1 1]]

Example

>>> from kwimage.im_runlen import *  # NOQA
>>> img = np.array([
>>>     [0, 0, 0],
>>>     [0, 1, 0],
>>>     [0, 0, 0]], dtype=np.uint8)
>>> rle = encode_run_length(img, binary=True, order='C')
>>> new_rle = rle_translate(rle, (1, 0))
>>> decoded = decode_run_length(**new_rle)
>>> print(decoded)
[[0 0 0]
 [0 0 1]
 [0 0 0]]
>>> new_rle = rle_translate(rle, (0, 1))
>>> decoded = decode_run_length(**new_rle)
>>> print(decoded)
[[0 0 0]
 [0 0 0]
 [0 1 0]]
kwimage.im_runlen._rle_bytes_to_array(s, impl='auto')[source]

Uncompresses a coco-bytes RLE into an array representation.

Parameters
  • s (bytes) – compressed coco bytes rle

  • impl (str) – which implementation to use (defaults to cython is possible)

CommandLine:

xdoctest -m ~/code/kwimage/kwimage/im_runlen.py _rle_bytes_to_array

Benchmark:
>>> import ubelt as ub
>>> from kwimage.im_runlen import _rle_bytes_to_array
>>> s = b';?1B10O30O4'
>>> ti = ub.Timerit(1000, bestof=50, verbose=2)
>>> # --- time python impl ---
>>> for timer in ti.reset('python'):
>>>     with timer:
>>>         _rle_bytes_to_array(s, impl='python')
>>> # --- time cython impl ---
>>> # xdoctest: +REQUIRES(--mask)
>>> for timer in ti.reset('cython'):
>>>     with timer:
>>>         _rle_bytes_to_array(s, impl='cython')
kwimage.im_runlen._rle_array_to_bytes(counts, impl='auto')[source]

Compresses an array RLE into a coco-bytes RLE.

Parameters
  • counts (ndarray) – uncompressed array rle

  • impl (str) – which implementation to use (defaults to cython is possible)

Example

>>> # xdoctest: +REQUIRES(--mask)
>>> from kwimage.im_runlen import _rle_array_to_bytes
>>> from kwimage.im_runlen import _rle_bytes_to_array
>>> arr_counts = np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
>>> str_counts = _rle_array_to_bytes(arr_counts)
>>> arr_counts2 = _rle_bytes_to_array(str_counts)
>>> assert np.all(arr_counts2 == arr_counts)
Benchmark:
>>> # xdoctest: +REQUIRES(--mask)
>>> import ubelt as ub
>>> from kwimage.im_runlen import _rle_array_to_bytes
>>> from kwimage.im_runlen import _rle_bytes_to_array
>>> counts = np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
>>> ti = ub.Timerit(1000, bestof=50, verbose=2)
>>> # --- time python impl ---
>>> #for timer in ti.reset('python'):
>>> #    with timer:
>>> #        _rle_array_to_bytes(s, impl='python')
>>> # --- time cython impl ---
>>> for timer in ti.reset('cython'):
>>>     with timer:
>>>         _rle_array_to_bytes(s, impl='cython')