RLE(Run-Length Encoding)全称是游程编码,又译行程长度编码,或称为变动长度编码法。它是一种简单的非破坏性资料压缩法,主要技术是检测重复的比特或字符序列,并用它们的出现次数取而代之。这种压缩方法在控制论中对于二值图像而言是一种重要的编码方法,尤其适用于计算机生成的图形图像,对减少存储容量很有效果。
RLE的基本原理
RLE的基本原理是在给定的数据图像中寻找连续的重复数值,然后用两个字符取代这些连续值。具体来说,它将一扫描行中颜色值相同的相邻像素用两个字段表示:第一个字段是一个计数值,用于指定像素重复的次数;第二个字段是具体像素的值。通过压缩除掉数据中的冗余字节或字节中的冗余位,从而达到减少文件所占空间的目的。
RLE的用途
- 图像压缩:RLE压缩算法是Windows系统中使用的一种图像文件压缩方法,尤其适合于二值图像的编码。如果图像由很多块颜色或灰度相同的大面积区域组成,采用RLE编码可以达到很高的压缩比。
- 数据压缩:RLE不仅限于图像数据,还可以用于其他类型的数据压缩,特别是当数据中存在大量连续重复的元素时。
- 无损压缩:RLE是一种无损压缩技术,意味着在解压缩后,数据可以完全恢复到原始状态,不会丢失任何信息。
RLE的优缺点
优点:
- 加压缩和解压缩都非常快。
- 压缩过程简单直观,易于实现。
- 对于具有大量连续重复数据的情况,压缩效果显著。
缺点:
- 如果原始数据中连续重复的数据较少,压缩效果可能不明显,甚至可能导致数据膨胀。
- 不适用于连续色调图像的压缩,如日常生活中的照片。
编码:
def mask2rle(img):
'''
img: numpy array, 1 -> mask, 0 -> background
Returns run length as string formated
'''
pixels = img.T.flatten()
pixels = np.concatenate([[0], pixels, [0]])
runs = np.where(pixels[1:] != pixels[:-1])[0] + 1
# print("runs[1::2]: {}".format(runs[1::2].shape))
# print("runs[::2]: {}".format(runs[::2].shape))
runs[1::2] -= runs[::2]
return ' '.join(str(x) for x in runs)
读入数据并写入csv的完整过程,最后会生成一个csv文件。mask的值是0,1的二值图像,0是背景,1是前景。读入mask数据也可以使用cv2读入,写入csv的方式也可以按照自己喜欢的方式写入。
import numpy as np
import csv
import os
import pandas as pd
from PIL import Image
def mask2rle(img):
'''
img: numpy array, 1 -> mask, 0 -> background
Returns run length as string formated
'''
pixels = img.T.flatten()
pixels = np.concatenate([[0], pixels, [0]])
runs = np.where(pixels[1:] != pixels[:-1])[0] + 1
# print("runs[1::2]: {}".format(runs[1::2].shape))
# print("runs[::2]: {}".format(runs[::2].shape))
runs[1::2] -= runs[::2]
return ' '.join(str(x) for x in runs)
def read_mask(mask_path):
mask=Image.open(mask_path)
mask=np.array(mask)
mask=mask/255
if __name__=='__main__':
mask_paths="******" # mask 的位置
image_ids =os.listdir(mask_paths)
# # 准备要写入CSV的数据
data_to_write = []
for image_id in image_ids:
mask_path=os.path.join(mask_paths+image_id)
mask=read_mask(mask_path)
rle_string = mask2rle(mask) # 计算RLE编码
height, width = mask.shape # 获取图像尺寸
row = {'image_id': image_id, 'cell_rle': rle_string,'width': width, 'height': height}
data_to_write.append(row)
# # 写入CSV文件
with open('encoded_masks0.csv', 'w', newline='') as csvfile:
fieldnames = ['image_id', 'cell_rle', 'width', 'height'] # CSV的列名
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader() # 写入表头
for row in data_to_write:
writer.writerow(row) # 写入每一行数据
解码:
def rle2mask(mask_rle, shape=(256, 256)):
if mask_rle != 'None':
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
else:
return np.zeros([shape[1], shape[0]], dtype=np.uint8)