Azure语义分割RLE转Mask异常:解码后仅显示右上角竖线求助
我用Azure Data Labelling制作了Semantic Segmentation (Preview)数据集,导出到本地后有images文件夹的图片和JSON标签文件。尝试解码RLE字符串生成分割Mask时,结果始终只有右上角一条竖线,使用的解码代码如下:
JSON中的RLE数据
{"rle":[121256,0,3,1,715,0,6,1,712,0,8,1,712,0,8,1,712,0,9,1,711,0,12,1,708,0,19,1,702,0,21,1,699,0,23,1,698,0,22,1,699,0,21,1,700,0,20,1,704,0,15,1,675,0,5,1,714,0,6,1,705,0,4,1,4,0,8,1,703,0,18,1,701,0,20,1,699,0,22,1,697,0,24,1,696,0,25,1,694,0,26,1,693,0,27,1,693,0,28,1,692,0,28,1,692,0,29,1,691,0,29,1,690,0,30,1,691,0,30,1,690,0,30,1,690,0,30,1,690,0,30,1,690,0,30,1,690,0,30,1,690,0,31,1,689,0,31,1,689,0,31,1,689,0,30,1,691,0,29,1,691,0,29,1,691,0,28,1,692,0,28,1,693,0,27,1,693,0,27,1,694,0,26,1,695,0,25,1,696,0,23,1,698,0,22,1,700,0,20,1,701,0,19,1,702,0,18,1,704,0,16,1,705,0,15,1,707,0,13,1,708,0,12,1,710,0,10,1,711,0,9,1,713,0,7,1,714,0,6,1,355398,0]}
使用的解码代码
import json import numpy as np import cv2 # rle_decode function def rle_decode(rle_list, shape, fill_value=1, dtype=int, relative=False): rle_str = ' '.join(map(str, rle_list)) s = rle_str.strip().split(" ") starts, lengths = np.array([np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]) mask = np.zeros(np.prod(shape), dtype=dtype) if relative: start = 0 for index, length in zip(starts, lengths): start = start + index end = start + length mask[start:end] = fill_value start = end return mask.reshape(shape[::-1]).T else: starts -= 1 ends = starts + lengths for lo, hi in zip(starts, ends): mask[lo:hi] = fill_value return mask.reshape(shape[::-1]).T # Read JSON file with open('downloads/labels/2D82C4F8-F1F2-4042-AE45-C4988A55048A.json', 'r') as f: data = json.load(f) rle_list = data['rle'] shape = (100, 100) # Assuming the shape is known or provided # Decode RLE list mask = rle_decode(rle_list, shape) # Create a black image image = np.zeros(shape, dtype=np.uint8) # Draw the mask on the black image image[mask == 1] = 255 # White color for mask # Display the image cv2.imshow('Mask', image) cv2.waitKey(0) cv2.destroyAllWindows()
当前输出仅为右上角一条竖线,需要正确解码RLE得到完整分割Mask用于模型训练。
问题出在两个核心点:
错误的图像尺寸假设:手动设置的
(100,100)和实际图像尺寸不匹配。从RLE的第一个数值121256来看,这个数值远大于100*100=10000,说明实际图像的像素总数远大于10000。- 解决:从对应的图片文件中读取真实尺寸,比如用
cv2.imread获取图像的高和宽:img = cv2.imread('path/to/your/image.jpg') shape = (img.shape[0], img.shape[1]) # (height, width)
- 解决:从对应的图片文件中读取真实尺寸,比如用
Azure Data Labelling的RLE编码规则:Azure导出的语义分割RLE是相对编码(即每个起始位置是相对于前一段结束的偏移量),但原代码默认使用了
relative=False的绝对编码逻辑,导致解码位置完全错误。- 解决:调用解码函数时必须匹配相对编码逻辑,同时Azure的RLE按**行优先(row-major)**排列,不需要额外转置。
修正后的完整代码
import json import numpy as np import cv2 def rle_decode(rle_list, shape, fill_value=1, dtype=int): # 适配Azure的相对偏移RLE编码,行优先排列 mask = np.zeros(np.prod(shape), dtype=dtype) current_pos = 0 # RLE列表为[偏移量, 长度]交替结构,处理末尾的填充偏移 for i in range(0, len(rle_list), 2): offset = rle_list[i] length = rle_list[i+1] if length == 0: current_pos += offset continue start = current_pos + offset end = start + length mask[start:end] = fill_value current_pos = end # 按(height, width)直接reshape,无需转置 return mask.reshape(shape) # 读取JSON标签文件 with open('downloads/labels/2D82C4F8-F1F2-4042-AE45-C4988A55048A.json', 'r') as f: data = json.load(f) rle_list = data['rle'] # 读取对应图片获取真实尺寸(替换为你的图片路径) img_path = 'downloads/images/2D82C4F8-F1F2-4042-AE45-C4988A55048A.jpg' img = cv2.imread(img_path) shape = (img.shape[0], img.shape[1]) # (height, width) # 解码RLE生成Mask mask = rle_decode(rle_list, shape) # 可视化正确的Mask mask_img = (mask * 255).astype(np.uint8) cv2.imshow('Correct Mask', mask_img) cv2.waitKey(0) cv2.destroyAllWindows()
额外验证点
- 确认JSON中的
rle列表是成对的(偏移量+长度),Azure导出的RLE最后通常会以[大偏移量, 0]结尾,用于填充到图像末尾,修正后的代码已处理这种情况。 - 确保图片路径和标签文件名对应,Azure导出的标签文件名通常和图片文件名一致(仅后缀不同)。
内容的提问来源于stack exchange,提问作者Muhammad Faizan

