Skip to the content.

run-length 编码和解码

Contact me


本文的代码来自于Run-Length Encode and Decode paulorzp

这个run-length是一个数值只取0和1的二维矩阵,一般的用途是描述图像的mask,比如:

run-len1

看一下简单的内容和图像的对应:

run-len2

这里先贴出编码和解码的代码,代码来源

def rle_encode(img):
    '''
    img: numpy array, 1 - mask, 0 - background
    Returns run length as string formated
    '''
    pixels = img.flatten()
    pixels = np.concatenate([[0], pixels, [0]])
    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1
    runs[1::2] -= runs[::2]
    return ' '.join(str(x) for x in runs)
 
def rle_decode(mask_rle, shape):
    '''
    mask_rle: run-length as string formated (start length)
    shape: (height,width) of array to return 
    Returns numpy array, 1 - mask, 0 - background

    '''
    s = mask_rle.split()
    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]
    starts -= 1
    ends = starts + lengths
    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)
    for lo, hi in zip(starts, ends):
        img[lo:hi] = 1
    return img.reshape(shape)

我们用上面的简单例子来一步步分析编码和解码的过程:

编码

mask = np.array([
    [0, 1, 1, 0], 
    [1, 1, 1, 1],
    [1, 0, 0, 1]
])

mask的图像就是上方那个简单的图像。

array([0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1]) ```

np.concatenate([[0], mask, [0]])

> array([0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0])
runs = np.where(mask[1:] != mask[:-1])[0] + 1

> array([ 2,  4,  5, 10, 12, 13])

run-len3

runs[1::2] -= runs[::2]

> array([ 2,  2,  5,  5, 12,  1])

至此,编码就完成了。

code = ' '.join(str(x) for x in runs)

注意到它这里的起始位置是从1开始算的

解码

code = code.split()

> ['2', '2', '5', '5', '12', '1']
starts, lengths = [np.asarray(x, dtype=int) for x in (code[0:][::2], code[1:][::2])]

> (array([ 2,  5, 12]), array([2, 5, 1]))
starts -= 1
ends = starts + lengths
starts, ends

> (array([ 1,  4, 11]), array([ 3,  9, 12]))
decode_mask = np.zeros(3*4, dtype=np.uint8)
for lo, hi in zip(starts, ends):
    decode_mask[lo:hi] = 1

> array([0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1], dtype=uint8)

结果图:

run-len4

总结起来就是记录所有连续1的起始位置和长度作为编码,解码依据这个记录恢复就好。