:py:mod:`kwimage.im_runlen` =========================== .. py:module:: kwimage.im_runlen .. autoapi-nested-parse:: 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 ~~~~~~~~~ .. autoapisummary:: kwimage.im_runlen.encode_run_length kwimage.im_runlen.decode_run_length kwimage.im_runlen.rle_translate kwimage.im_runlen._rle_bytes_to_array kwimage.im_runlen._rle_array_to_bytes .. py:function:: encode_run_length(img, binary=False, order='C') 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 :rtype: Dict[str, object] SeeAlso: * kwimage.Mask - a cython-backed data structure to handle coco-style RLEs .. rubric:: 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']) .. rubric:: 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] .. py:function:: decode_run_length(counts, shape, binary=False, dtype=np.uint8, order='C') 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 :rtype: ndarray .. rubric:: 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) .. py:function:: rle_translate(rle, offset, output_shape=None) 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]) .. rubric:: 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]] .. py:function:: _rle_bytes_to_array(s, impl='auto') 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') .. py:function:: _rle_array_to_bytes(counts, impl='auto') 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) .. rubric:: 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')