1. 程式人生 > >RLE格式標註檔案轉為PNG格式(Run Length Encode)

RLE格式標註檔案轉為PNG格式(Run Length Encode)

一、什麼是 RLE 格式

在機器視覺領域的深度學習中,每個資料集都有一份標註好的資料用於訓練神經網路。

但是神經網路的輸入一定是一張圖片,為此必須把RLE格式的檔案轉變為影象格式。

影象格式主要又分為 .jpg 和 .png 兩種格式,其中label資料一定不能使用 .jpg,因為它因為壓縮算演算法的原因,會造成影象失真,影象各個畫素的值可能會發生變化。分割任務的資料集的 label 影象中每一個畫素都代表了該畫素點所屬的類別,所以這樣的失真是無法接受的。為此只能使用 .png 格式作為label,pascol voc 和 coco 資料集正是這樣做的。

二、如何轉化為 .png

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
from PIL import Image


# ref: https://www.kaggle.com/paulorzp/run-length-encode-and-decode
#將圖片編碼成rle格式
def rle_encode(img, min_max_threshold=1e-3, max_mean_threshold=None):
    '''
    img: numpy array, 1 - mask, 0 - background
    Returns run length as string formated
    '''
    if np.max(img) < min_max_threshold:
        return '' ## no need to encode if it's all zeros
    if max_mean_threshold and np.mean(img) > max_mean_threshold:
        return '' ## ignore overfilled mask
    pixels = img.T.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)

#將圖片從rle解碼
def rle_decode(mask_rle, shape=(768, 768)):
    '''
    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).T  # Needed to align to RLE direction


def masks_as_image(in_mask_list):
    # Take the individual ship masks and create a single mask array for all ships
    all_masks = np.zeros((768, 768), dtype = np.uint8)
    for mask in in_mask_list:
        if isinstance(mask, str):
            all_masks |= rle_decode(mask)
    return all_masks

#將目標路徑下的rle檔案中所包含的所有rle編碼,儲存到save_img_dir中去
def rle_2_img(train_rle_dir,save_img_dir):
    masks = pd.read_csv(train_rle_dir)
    not_empty = pd.notna(masks.EncodedPixels)
    print(not_empty.sum(), 'masks in', masks[not_empty].ImageId.nunique(), 'images')
    print((~not_empty).sum(), 'empty images in', masks.ImageId.nunique(), 'total images')
    all_batchs = list(masks.groupby('ImageId'))
    train_images = []
    train_masks = []
    i = 0
    for img_id, mask in all_batchs:
        c_mask = masks_as_image(mask['EncodedPixels'].values)
        im = Image.fromarray(c_mask)
        im.save(save_img_dir+img_id.split('.')[0] + '.png')
        print(i,img_id.split('.')[0] + '.png')
        i += 1
        
    return train_images, train_masks



if __name__ == '__main__':
    rle_2_img('D://DL//airbus-kaggle//dataset_V2//train_ship_segmentations_v2.csv',
              'D://DL//airbus-kaggle//dataset_V2//mask//')