之前数据处理也解析过json文件,不过那会是一张图只有一个mask,一个标签,近期接触多类别分割标签的json文件,进一步理解了以前写的解析代码,考虑了多类别标签的各种情况,特此记录。
单标签的json解析传送门:【数据处理】Python解析json文件(转mask)
1. 多类别分割标签
假设用labelme软件勾了如下一个标签(示例标签无实际意义,仅供代码测试),标签为0-4,标签之间存在包含情况,如标签0包含1-4;每一个类可能有多个区域,如标签4有两个区域的勾画。在医学实际应用中,此类标注可见于一个大病灶中,不同级别病灶的区分。
2. python解析
python代码及注释:
import json
import numpy as np
from collections import defaultdict
from labelme import utils
from skimage import img_as_ubyte
import matplotlib.pyplot as plt
from PIL import Imagepath = './1.json'
data = json.load(open(path))
imageData = data.get('imageData')
img = utils.img_b64_to_arr(imageData) # 解析json文件获得原图shape = data['shapes'] # shape中存储了各标签的标记点masks = defaultdict(list) # 定义一个空字典# 对每一个标签进行解析
index = 0
for item in shape:temp_label = item['label'] # 获得勾画时给定的标签temp_points = item['points'] # 获得该标签的标记点# 将标记点转化为mask, 其中背景的标记为0, 标记标签的值需要加1与背景区分# 实际应用中根据勾画时给定的标签修改lbl, _ = utils.shapes_to_label(img.shape, [item], {'_background_': 0, temp_label:int(temp_label)+1})temp_mask = img_as_ubyte(lbl) # int32转为图像uint8masks[str(index)] = temp_mask # 存入字典index = index + 1key_all = list(masks.keys()) # 获取字典中所有的键# 将字典masks转化为数组, 同时增加代码普适性适应于各种情况, 便于批量处理
if len(key_all) == 1:masks_all = masks[key_all[0]] # 若json中只标记了一个标签
else:for i in range(len(key_all)-1):if i == 0:masks_all = np.stack((masks[key_all[i]], masks[key_all[i+1]]), axis=0)else:masks_all = np.concatenate((masks_all, np.expand_dims(masks[key_all[i+1]], axis=0)), axis=0)# 合并数组masks_all中的所有标签, 本例中masks_all.shape:(6, 3264, 5824)
if len(key_all) != 1:final_mask = np.max(masks_all, axis=0)
else:final_mask = masks_allw, h = final_mask.shape # (3264, 5824)
zz = final_mask.reshape(w*h)
print(list(set(list(zz)))) # 输出mask中的数值为:[0, 1, 2, 3, 4, 5]# 画图--------------------------------------------------------------------------
plt.figure(dpi=300)
plt.subplot(2,1,1)
plt.imshow(img) # 原图
plt.axis('off')
plt.subplot(2,1,2)
plt.imshow(final_mask) # mask(伪彩)
plt.axis('off')
# 存图--------------------------------------------------------------------------
image_path = "./image.png"
mask_path = "./mask.png"
image_save = Image.fromarray(img)
mask_save = Image.fromarray(final_mask)
image_save.save(image_path)
mask_save.save(mask_path)
# ------------------------------------------------------------------------------
mask(伪彩显示)提取如下: