컴퓨터 비젼(Computer Vision)

RLE (RUN LENGTH ENCODING)

rongxian 2022. 5. 11. 00:12

매우 간단한 비손실 압축 방법으로, 데이터에서 같은 값이 연속해서 나타나는 것을 그 개수와 반복되는 값만으로 표현하는 방법이다.

(FROM WIKIPEDIA)

 

RLE로 된 데이터 (예를 들어 마스크 데이터) 는 특정한 형태로 이뤄졌다고 하자. (H: 높이, W: 너비)

그러면 이 마스크 데이터의 형태는 H*W 길이의 평면화된 방식으로 표현될 것이다. 이렇게 표현된 값은 각 짝마다 정보를 포함하고 있다.

첫번째 값은 평면화된 곳에서의 시작 위치, 두번째 값은 시작 위치에서부터의 길이를 표현한다.

즉, RLE 마스크 데이터에서 홀수번째 값은 시작 위치, 짝수번째 값은 길이를 표현함을 알 수있다.

 

RLE로 된 마스크 데이터가 다음과 같이 주어졌다고 하자. (Kaggle의 UWMGIT 데이터)

28094 3 28358 7 28623 9 28889 9 29155 9 29421 9 29687 9 29953 9 30219 9 30484 10 30750 10 31016 10 3...

 

코드 1)

def prepare_mask_data(string):
    # fetching all the values from the string
    all_values = map(int, string.split(" "))
    # preparing the usable arrays
    starterIndex, pixelCount = [], []
    for index, value in enumerate(all_values):
        if index % 2:
            # storing even indexed values in pixelCount
            pixelCount.append(value)
        else:
            # storing odd indexed values in starterIndex
            starterIndex.append(value)
    return starterIndex, pixelCount
    
def fetch_pos_pixel_indexes(indexes, counts):
    final_arr = []
    for index, counts in zip(indexes, counts):
        # adding all the values from starterIndex to range of positive pixel counts
        final_arr += [index + i for i in range(counts)]
    return final_arr

def prepare_mask(string, height, width):
    # preparing the respective arrays
    indexes, counts = prepare_mask_data(string)
    # preparing all the pixel indexes those have mask values
    pos_pixel_indexes = fetch_pos_pixel_indexes(indexes, counts)
    # forming the flattened array
    mask_array = np.zeros(height * width)
    # updating values in the array
    mask_array[pos_pixel_indexes] = 1
    # reshaping the masks
    return mask_array.reshape(height, width)
 
코드 2)
# ref: https://www.kaggle.com/paulorzp/run-length-encode-and-decode
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)  # Needed to align to RLE direction


# ref.: https://www.kaggle.com/stainsby/fast-tested-rle
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)

참고

https://en.wikipedia.org/wiki/Run-length_encoding

https://www.kaggle.com/code/sagnik1511/uwmgit-data-preparation-from-scratch