1.dcm转jpg
def convert_from_dicom_to_jpg(img, low_window, high_window, save_path):
lungwin = np.array([low_window * 1., high_window * 1.])
newimg = (img - lungwin[0]) / (lungwin[1] - lungwin[0])
newimg = (newimg * 255).astype('uint8')
cv2.imwrite(save_path, newimg, [int(cv2.IMWRITE_JPEG_QUALITY), 100])
def dcm2jpg():
count = 1
path = r"C:\data\dcm"
filename = os.listdir(path)
for i in filename:
document = os.path.join(path, i)
outputpath = r"C:\jpg"
index = i.rfind('.')
countname = i[:index]
countfullname = countname + '.jpg'
output_jpg_path = os.path.join(outputpath, countfullname)
ds_array = sitk.ReadImage(document)
img_array = sitk.GetArrayFromImage(ds_array)
shape = img_array.shape # name.shape
img_array = np.reshape(img_array, (shape[1], shape[2]))
high = np.max(img_array)
low = np.min(img_array)
convert_from_dicom_to_jpg(img_array, low, high, output_jpg_path)
print('FINISHED')
count = count + 1
当时找了好多个代码,感觉转换出来都没那么亮,就随便贴一个吧。
2.dcom轮廓数据转标注可识别
这里遇到的问题是 轮廓数据里基本找到属性为:(1)引用到原数据的ruid,(2)ROIName,(3)世界坐标,然后根据这些数据 转换坐标,然后 对每一个原图找到它用到的ROI,加到字典里,后续新建json存入。
dcm后缀 数据+轮廓数据 转为eiseg标注可识别工具代码。
可根据代码内函数自定义改为labelme或者其他可识别的标签文件。
做记录使用,没有做太多详细注释,当时debug然后根据属性获取 转换的。希望对大家有帮助。
import os
import numpy as np
import pydicom
from os.path import splitext, basename
import random
import json
uid2file = {}
file2uid = {}
# 世界坐标转图像坐标
def worldToVoxelCoord(worldCoord, origin, spacing):
stretchedVoxelCoord = np.absolute(worldCoord - origin)
voxelCoord = stretchedVoxelCoord / spacing
return voxelCoord
#
def dcm2coord():
data = dict()
dcms_data = dict()
data_dir = r'C:\data'
dcm_dir = os.path.join(data_dir, 'dcm')
rt_dir = os.path.join(data_dir, 'rt')
for dcm_file in os.listdir(dcm_dir): # 遍历读取数据
dcm_file_path = os.path.join(dcm_dir, dcm_file)
dcm_name = splitext(basename(dcm_file_path))[0]
ds = pydicom.dcmread(dcm_file_path)
array = ds.pixel_array
origin = ds.ImagePositionPatient # 网格原点在世界坐标系的位置
spacing = ds.PixelSpacing # 采样间隔
uid = ds.SOPInstanceUID
uid2file[uid] = dcm_name
file2uid[dcm_name] = uid
dcms_data[uid] = {'dcmSpacing': spacing, 'dcmOrigin': origin, 'array': array}
data['dcms_data'] = dcms_data # 存放图像信息,后续根据该信息获取 ruid对应关系
# rt data
rt_data = dict() # 以{RUID:label_data}形式返回结果
rt_file_path = os.path.join(rt_dir, os.listdir(rt_dir)[0])
ds = pydicom.dcmread(rt_file_path)
seq_lists = []
ROI_name_lists = []
for i in range(0, len(ds.ROIContourSequence)):
sequences = ds.ROIContourSequence[i].ContourSequence
ROI_name = ds.ROIContourSequence[i].ReferencedROINumber
seq_lists.append(sequences)
ROI_name_lists.append(ROI_name) # seq name 顺序一一对应
# 0是 RIO31, 有38个对应image
all_rt_data = []
for i, sequences in enumerate(seq_lists):
tmp_rt_datas = dict()
tmp_rt_data = dict()
ruids = []
dup = 1
for sequence in sequences:
ruid = sequence.ContourImageSequence[0].ReferencedSOPInstanceUID
array = sequence.ContourData
num = sequence.NumberOfContourPoints
if ruid in ruids:
dep_ruid = ruid + '-' + str(dup)
rt_data[dep_ruid] = {'ROIname': ROI_name_lists[i], 'pointNumber': num, 'array': array}
tmp_rt_data[dep_ruid] = {'ROIname': ROI_name_lists[i], 'pointNumber': num, 'array': array}
dup += 1
continue # 跳出本次循环进入下一循环
rt_data[ruid] = {'ROIname': ROI_name_lists[i], 'pointNumber': num, 'array': array}
tmp_rt_data[ruid] = {'ROIname': ROI_name_lists[i], 'pointNumber': num, 'array': array}
ruids.append(ruid)
data['rt_data'] = rt_data # 得到与之对应的image的ruid和 轮廓点坐标 会覆盖
tmp_rt_datas['rt_data'] = tmp_rt_data
all_rt_data.append(tmp_rt_datas['rt_data']) # 共12个元素
'''
00 ROI31 元素分别为 对应到CT Image的 ruid 和 点坐标
01 ROI1
02 ROI3
03 ROI4
04 ROI11
05 ROI12
06 ROI13
07 ROI14
08 ROI15
09 ROI16
10 ROI17
11 ROI46
'''
ROI_cood_dic = {}
for index, ROI in enumerate(all_rt_data): # 遍历所有的ROI 即每个ROI的 rt_data
point_data = {}
for uid, value in ROI.items(): # 遍历当前ROI的 对应CT Image的ruid和 轮廓坐标
num = value['pointNumber']
ROI_name = value['ROIname']
true_uid = uid.split('-')[0] if uid.rfind('-') != -1 else uid
label_data = value['array']
dcm_origin = data['dcms_data'][true_uid]['dcmOrigin']
dcm_spacing = data['dcms_data'][true_uid]['dcmSpacing']
point = [] # 坐标[(x1,y1),(...),...]
for i in range(0, len(label_data), 3):
x = label_data[i] # 轮廓世界坐标系
y = label_data[i + 1]
X = worldToVoxelCoord(float(x), float(dcm_origin[0]), float(dcm_spacing[0]))
Y = worldToVoxelCoord(float(y), float(dcm_origin[1]), float(dcm_spacing[1]))
point.append([X, Y])
point_data[uid] = point
ROI_cood_dic[ROI_name_lists[index]] = point_data
return ROI_cood_dic
# 由原本的 ROI 对应 Image 转换为 Image 下所有ROI轮廓
def ROI_cood_to_img_coord(ROI_cood_dic):
'''
对某一个img名字,把旗下所有的ROI标签拿到,对应ROI标签坐标拿到。
Args:
ROI_cood_dic:
Returns:
'''
img_dir = r'C:\data\jpg'
over_lists = {}
for img in os.listdir(img_dir): # 遍历img
img_name = splitext(img)[0]
img2uid = file2uid[img_name] # 该图片对应的ruid
labels_lists = []
for k, v in ROI_cood_dic.items(): # 遍历12个ROI
ROIname = k
uid_coords = v
color = [random.randint(16, 255), random.randint(32, 255), random.randint(64, 255)]
for uid, vals in uid_coords.items(): # 遍历每个ROI对应的image
labels = dict()
if uid.find(img2uid) != -1: # 当前图片 有这个label
labels["name"] = ROIname
labels["labelIdx"] = int(ROIname)
labels["color"] = color
labels["points"] = vals
if labels != {}:
labels_lists.append(labels)
over_lists[img] = labels_lists
return over_lists
def toeiseg(over_lists):
'''
字典中存的 key是图片名 value是 不同标签的 dict。 将这些个label遍历 然后依次添加到对应的list中。
Args:
over_lists:
Returns:
'''
desc_dir = r'C:\data\labels'
for img, lists in over_lists.items():
img_name = splitext(img)[0]
img2json = img_name + '.json'
desc_path = os.path.join(desc_dir, img2json)
if not desc_path:
os.mkdir(desc_path)
with open(desc_path, 'w') as file_obj:
json.dump(lists, file_obj, indent=2)
if __name__ == "__main__":
ROI_cood_dic = dcm2coord()
over_lists= ROI_cood_to_img_coord(ROI_cood_dic)
toeiseg(over_lists)