pair根据选择标注标签的不同,会保存生成不同的标注文件。目前我发现的就是压缩包文件,里面包含着nii.gz文件,或者.json文件。对于某些标注工具的选择,保存的内容可能不同,但是据我发现,.json文件是都会存在的。

标注过程中发现,pair标注中对闭合区域的标记,有两种形式可以选择,分别是实心闭合和空心闭合,发现如下:

  • 实心闭合,保存文件中包括nii.gzjson文件
  • 空心闭合,保存文件中只有json文件
  • 两者保存的json文件字段和格式不一样

下面我们就对这个复杂的json文件进行转储,生成一个相对比较简单的json文件,可以用labelme打开的文件。下面我们开始吧。

  1. 解压存储的标签文件 untar
  2. 去除一个series的标注信息,包括层号、类别、坐标等等
  3. 存储到json文件
  4. labelme打开确认下

下面我们就分空心闭合、实心闭合和混合型三个方面,进行记录。

1. 空心闭合操作

主代码如下:

import json
import commentjson
import tarfile
import os
import globdef untar(fname, output_dirs):t = tarfile.open(fname)t.extractall(path = output_dirs)def PolygonModelpoints3D2points2D(E_Points):tmp_points2d = []for e in E_Points:tmp_points2d.append([e[0], e[1]])return tmp_points2ddef save2jsonFile(list_coors, save_dir, filename):A = dict()listbigoption = []for coor in list_coors:print('coor:', coor)listobject = dict()listxy = coor[:-1]label_cls = coor[-1]listobject['points'] = listxylistobject['line_color'] = 'null'listobject['label'] = str(label_cls)listobject['fill_color'] = 'null'listbigoption.append(listobject)A['lineColor'] = [0, 255, 0, 128]A['imageData'] = 'imageData'A['fillColor'] = [255, 0, 0, 128]A['imagePath'] = filename.replace('.json', '.png')A['shapes'] = listbigoptionA['flags'] = {}with open(os.path.join(save_dir, filename), 'w') as f:json.dump(A, f, indent=2, ensure_ascii=False)def Polygon_json(json_path=None, with_comment=False):label_list = []with open(json_path, encoding='utf-8') as f:if with_comment:  # 若*.json中添加了注释,则使用commentjson。若无注释则使用json库也可。Anno_Dict = commentjson.load(f)else:Anno_Dict = json.load(f)Depth, Name = str(Anno_Dict["FileInfo"]["Depth"]), Anno_Dict["FileInfo"]["Name"].split('_')[0]Results_Dict = Anno_Dict["Models"]Polygon_list = Results_Dict["PolygonModel2"]dict_sliceNum_coor = {}for E_idx, E_item in enumerate(Polygon_list):E_Label = str(E_item["Label"])E_Points = E_item["Points"]# 由于存储标签中坐标是xyz的,labelme打开一张图时候,不需要高度信息,就去除掉E_Points = PolygonModelpoints3D2points2D(E_Points)E_Points.append(E_Label)E_SliceIndex = str(E_item["SliceIndex"])print('slicenum: {}\n类别id:{}\n坐标:{}\n'.format(E_SliceIndex, E_Label, E_Points))label_list.append(E_Label)if E_SliceIndex not in dict_sliceNum_coor.keys():dict_sliceNum_coor[E_SliceIndex] = [E_Points]else:cur_coor = dict_sliceNum_coor[E_SliceIndex]cur_coor.append(E_Points)dict_sliceNum_coor[E_SliceIndex] = cur_coorfor key, value in dict_sliceNum_coor.items():save_dir = os.path.join(os.path.dirname(json_path), 'json')filename = Name + '_' + (6-len(key))*'0'+key+'_'+Depth+'.json'if not os.path.exists(save_dir):os.makedirs(save_dir)save2jsonFile(value, save_dir, filename)print(save_dir, filename)return label_listif __name__ == '__main__':data_dir = r'F:\Pair\json_data'patient_list = os.listdir(data_dir)label_list_all = []TB_PatientNum = 0for patient in patient_list:file_dir = os.path.join(data_dir, patient)tar_list = glob.glob(file_dir + r'/*.tar')json_list = glob.glob(file_dir + r'/*.json')if len(tar_list) > len(json_list):if len(tar_list) > 0:for file_path in tar_list:print('start untar ---', file_path)untar(file_path, file_dir)json_list = glob.glob(file_dir + r'/*.json')if len(json_list) > 0:for file_path in json_list:label_list = PolygonModel2_json(json_path=file_path, with_comment=True)

到这里,已经将pair标注保存的json文件,转储到了小的json文件了。但是,此时的json文件和图片文件放到一起,还不能用labelme进行查看,还需要添加base64位的图像信息到json文件内。

2. 添加base64到imageData json中

添加的方式如下:

import base64
from PIL import Image
import iodef base64encode_img(image_path):src_image = Image.open(image_path)output_buffer = io.BytesIO()src_image.save(output_buffer, format='JPEG')byte_data = output_buffer.getvalue()base64_str = base64.b64encode(byte_data).decode('utf-8')return base64_strA['imageData'] = base64encode_img(os.path.join(raw_dir, file_name))

上面我就没和上面的代码组合到一起了,相信你一定知道该放置到哪里。如果还有疑问,来评论区留言就可以了。

此时,再用labelme打开,你就能够直接看到标注的信息,显示在图像上面了。

3. 实心闭合操作

import json
import commentjson
import tarfile
import os
import glob"""
1.解压存储的标签文件 untar
2.去除一个series的标注信息,包括层号、类别、坐标等等
3.存储到json文件
4.labelme打开确认下
"""def untar(fname, output_dirs):t = tarfile.open(fname)t.extractall(path = output_dirs)def Polyspoints3D2points2D(E_Points):tmp_points2d = []for e in E_Points:e_p = e["Pos"]tmp_points2d.append([e_p[0], e_p[1]])return tmp_points2ddef save2jsonFile(list_coors, save_dir, filename):A = dict()listbigoption = []for coor in list_coors:# print('coor:', coor)listobject = dict()listxy = coor[:-1]label_cls = coor[-1]listobject['points'] = listxylistobject['line_color'] = 'null'listobject['label'] = str(label_cls)listobject['fill_color'] = 'null'listbigoption.append(listobject)A['lineColor'] = [0, 255, 0, 128]A['imageData'] = 'imageData'A['fillColor'] = [255, 0, 0, 128]A['imagePath'] = filename.replace('.json', '.png')A['shapes'] = listbigoptionA['flags'] = {}with open(os.path.join(save_dir, filename), 'w') as f:json.dump(A, f, indent=2, ensure_ascii=False)def Polys_json(json_path=None, with_comment=False):label_list = []with open(json_path, encoding='utf-8') as f:if with_comment:  # 若*.json中添加了注释,则使用commentjson。若无注释则使用json库也可。Anno_Dict = commentjson.load(f)else:Anno_Dict = json.load(f)Depth, Name = str(Anno_Dict["FileInfo"]["Depth"]), Anno_Dict["FileInfo"]["Name"].split('_')[0]Polygon_list = Anno_Dict["Polys"]dict_sliceNum_coor = {}for E_idx, E_item in enumerate(Polygon_list):Shapes_info = E_item["Shapes"]for j_idx, j_item in enumerate(Shapes_info):E_Label = str(j_item["labelType"])E_SliceIndex = str(j_item["ImageFrame"])E_Points = j_item["Points"]# 由于存储标签中坐标是xyz的,labelme打开一张图时候,不需要高度信息,就去除掉E_Points = Polyspoints3D2points2D(E_Points)E_Points.append(E_Label)# print('slicenum: {}\n类别id:{}\n坐标:{}\n'.format(E_SliceIndex, E_Label, E_Points))label_list.append(E_Label)if E_SliceIndex not in dict_sliceNum_coor.keys():dict_sliceNum_coor[E_SliceIndex] = [E_Points]else:cur_coor = dict_sliceNum_coor[E_SliceIndex]cur_coor.append(E_Points)dict_sliceNum_coor[E_SliceIndex] = cur_coorfor key, value in dict_sliceNum_coor.items():save_dir = os.path.join(os.path.dirname(json_path), 'json')filename = Name + '_' + (6-len(key))*'0'+key+'_'+Depth+'.json'if not os.path.exists(save_dir):os.mkdir(save_dir)save2jsonFile(value, save_dir, filename)print(save_dir, filename)return label_listif __name__ == '__main__':data_dir = r'Z:\cancer1-100'patient_list = os.listdir(data_dir)label_list_all = []TB_PatientNum = 0for patient in patient_list:file_dir = os.path.join(data_dir, patient)print(file_dir)if os.path.exists(os.path.join(data_dir, patient, 'json')):continuetar_list = glob.glob(file_dir + r'/*.tar')json_list = glob.glob(file_dir + r'/*.json')if len(tar_list) > len(json_list):if len(tar_list) > 0:for file_path in tar_list:print('start untar ---', file_path)untar(file_path, file_dir)json_list = glob.glob(file_dir + r'/*.json')if len(json_list) > 0:for file_path in json_list:# Polyslabel_list = Polys_json(json_path=file_path, with_comment=True)

除去上面两种情况外,还会有混合的,则进行统一处理。


处理代码如下:

def Polygon_combine_json(json_path=None, with_comment=False):label_list = []with open(json_path, encoding='utf-8') as f:if with_comment:  # 若*.json中添加了注释,则使用commentjson。若无注释则使用json库也可。Anno_Dict = commentjson.load(f)else:Anno_Dict = json.load(f)Depth, Name = str(Anno_Dict["FileInfo"]["Depth"]), Anno_Dict["FileInfo"]["Name"].split('_')[0]try:Results_Dict = Anno_Dict["Models"]Polygon_list = Results_Dict["PolygonModel2"]dict_sliceNum_coor = {}for E_idx, E_item in enumerate(Polygon_list):E_Label = str(E_item["Label"])E_Points = E_item["Points"]if len(E_Points) < 3:continue# 由于存储标签中坐标是xyz的,labelme打开一张图时候,不需要高度信息,就去除掉E_Points = PolygonModelpoints3D2points2D(E_Points)E_Points.append(E_Label)# 序号这里建议直接+1,解决从0开始的问题E_SliceIndex = str(E_item["SliceIndex"])# print('slicenum: {}\n类别id:{}\n坐标:{}\n'.format(E_SliceIndex, E_Label, E_Points))label_list.append(E_Label)if E_SliceIndex not in dict_sliceNum_coor.keys():dict_sliceNum_coor[E_SliceIndex] = [E_Points]else:cur_coor = dict_sliceNum_coor[E_SliceIndex]cur_coor.append(E_Points)dict_sliceNum_coor[E_SliceIndex] = cur_coorexcept:passtry:Polygon_list2 = Anno_Dict["Polys"]for E_idx, E_item in enumerate(Polygon_list2):Shapes_info = E_item["Shapes"]for j_idx, j_item in enumerate(Shapes_info):E_Label = str(j_item["labelType"])# 序号这里建议直接+1,解决从0开始的问题E_SliceIndex = str(j_item["ImageFrame"])E_Points = j_item["Points"]# 加上判断,避免出现单个点if len(E_Points) < 3:continue# 由于存储标签中坐标是xyz的,labelme打开一张图时候,不需要高度信息,就去除掉E_Points = Polyspoints3D2points2D(E_Points)E_Points.append(E_Label)# print('slicenum: {}\n类别id:{}\n坐标:{}\n'.format(E_SliceIndex, E_Label, E_Points))label_list.append(E_Label)if E_SliceIndex not in dict_sliceNum_coor.keys():dict_sliceNum_coor[E_SliceIndex] = [E_Points]else:cur_coor = dict_sliceNum_coor[E_SliceIndex]cur_coor.append(E_Points)dict_sliceNum_coor[E_SliceIndex] = cur_coorexcept:passfor key, value in dict_sliceNum_coor.items():save_dir = os.path.join(os.path.dirname(json_path), 'json')# filename = Name + '_' + (6-len(key))*'0'+key+'_'+Depth+'.json'filename = Name + '_' + (6 - len(key)) * '0' + key  + '.json'if not os.path.exists(save_dir):os.mkdir(save_dir)save2jsonFile(value, save_dir, filename)print(save_dir, filename)return label_list

4.注意事项

注意事项1:ImageFrame从0开始


这点在对生成的json文件与图像对应时候尤为重要。我们dcm文件中都是从1开始的,而不是0。所以这点需要注意。

注意事项2:ImageFrame的排序和dcm文件的排序会不一致

生成的json标注文件内ImageFrame排序不是按照dcm文件内记录的顺序进行排布的,而是根据Z轴进行排布的,也就是我们下图的箭头方向:

注意事项3:json标注坐标,是在mm单位下的坐标,不是像素单位

如果你用labelme打开发现标注区域不匹配,这个点需要注意。所以在转图时候,记得转化到mm单位,这里要用到PixelSpacing

  • 方式一,对坐标除以pixelspace,换算到mm单位
  • 方式二,对图像大小乘以pixelspace,换算到像素单位

至此,亲测有效,你就可以打开生成的json和图像放到一起,用labelme打开看看了。相信你看到的内容,还是很满意的。

【Pair使用笔记指南3】标注结果转储labelme读取的json文件相关推荐

  1. Three.js入门学习笔记07:外部模型导入-C4D转成json文件供网页使用-fbx导入

    上一篇用的obj导入,转成json发现有些材质加载不进去,不知是什么原因. 比如blender导入obj模型的时候,只要obj和mtl材质文件在同一个文件夹内,正常情况,导入obj的同时就能直接导入同 ...

  2. Python深度学习入门笔记(二):使用Pandas读取批量CSV文件,文件名中有顺序变量

    前言 本文主要展示如何将具有变量名称的 CSV 文件导入 Python,比如一系列连续变化的文件如: r1.csv r2.csv r3.csv - 我将使用一个简单的例子来说明这个概念,并提供完整的 ...

  3. Three.js入门学习笔记05:外部模型导入-C4D转成json文件供网页使用

    参考学习: https://www.jianshu.com/p/906072e60197 https://blog.csdn.net/qq_30100043/article/details/79606 ...

  4. 根据标注精灵助手标好并导出的json文件生成txt文件(一)

    最近在做自然场景的OCR检测识别算法,对于检测来说,需要对文件图片进行ground truth坐标点label的标注,刚开始使用的是标注精灵助手,标注好boundingbox后导出的是json格式的文 ...

  5. 【深度学习之路记录02】python代码批量修改Labelme标注的json文件(删除标签、修改标签名)

    代码参考:https://blog.csdn.net/qq_44442727/article/details/112785978 创建自己的数据集时,经常需要一些调整,比如说修改某一批文件中已经标好的 ...

  6. Revit2016 笔记10 - Revit标注

    Revit2016 笔记10 - Revit标注 一.尺寸标注 尺寸标注是项目中显示距离和尺寸的视图专有图元,其中包括两种类型: 临时尺寸标注和永久性尺寸标注.当放置构件时,Revit 会放置临时尺寸 ...

  7. Linux学习笔记-段错误与内存转储

    在Linux下,程序中如果进行了不正确的指针操作,则程序崩溃.提示"Segment Fault": 源码如下: #include <stdio.h>void test( ...

  8. 好用的图像分割标注工具:Labelme

    缘起:最近在找合适的读博院校,正在参与一个和人眼语义分割有关的小测验,需要从网上自己找数据,做标签,所以借此机会和大家推荐一下这款救我于火急之中的小工具Labelme. 这里有详细的安装步骤:http ...

  9. Python修改图片格式以及相对应labelme标注的Json文件

    Python修改图片格式以及相对应labelme标注的Json文件 前言 前提条件 相关介绍 实验环境 Python修改图片格式以及相对应labelme标注的Json文件 代码实现 输出结果 前言 本 ...

最新文章

  1. jfreechart的使用
  2. MongoDB工具最新开发 源代码更新 兼 进展报告 - 集群功能开发
  3. VS2010 断点无效肿么办?
  4. 放苹果问题 POJ 1664
  5. Lucene教程--Analyzer分析器详解
  6. Spring4学习笔记
  7. android 布局防抖动,Android全屏返回布局抖动问题
  8. Jsoup获取所有链接
  9. OpenShift 4 Hands-on Lab (0) - 教程说明和准备环境
  10. 历史为什么选择C语言?事实证明:暮年的C语言,依旧宝刀未老!
  11. Codeforces Global Round 21 E. Placing Jinas
  12. 数据输入流与数据输出流
  13. 粒子群算法查找函数最小值
  14. 新自媒体账号想要开直播?大周给你几点建议
  15. 2004年国内十大暴利行业
  16. 湖北公安机关出台10条措施服务民营经济发展
  17. 5个实用的性能测试工具(软件测试工程师必备)
  18. 佳明表盘 c语言开发的吗,Garmin MonkeyC的写法和经验
  19. 红外接收二极管 -- 结电容和暗电流
  20. 噪鹃de“喔啊“悲惨的叫声

热门文章

  1. 清华大学计算机科学与技术系黄必胜,刘斌(清华大学计算机科学与技术系教授)_百度百科...
  2. SSRS 的简单使用(一)
  3. GIT乱码解决方案汇总及GIT用户名和邮箱修改
  4. 电脑上的c语言程序打不开,电脑软件无法打开怎么解决|电脑软件打不开的处理的方法...
  5. PyQt5界面多线程多进程爬虫(爬了600w张网页, 出现了一些问题)
  6. 全球各地5G频谱分配情况如何?最全无线通信频率分配表
  7. 你以为的5G仅仅是运行在5G的频段嘛?一文带你了解国内运营商的5G/4G/3G/2G频谱划分
  8. 如何只用逻辑运算实现算术加减乘除运算
  9. 关于开发Android应用时写从图库选择头像功能时遇到的一些问题。
  10. NC65后台手动创建用户并设置初始密码