问题提出
最近我们遇到了一个问题。我们原计划在MRI图像堆栈上手动标注直肠癌的mask,以用于后续的影像组学研究。然而,手动标注耗时过多,因此我们打算基于开源模型的结果进行修改,最终得到可用的癌症病变区域标注。我们发现现有的直肠癌分割模型只接受mhd格式的输入,并输出mhd格式的文件,代表分割得到的灰度掩膜。然而,该模型在我们的数据集上效果欠佳,需要我们进行手动修改。但是,我没有找到可以修改mhd文件数据的标注软件(可能有,但我没找到)。因此,我们需要将mhd文件转换为dicom格式。
MHD与DICOM格式简介
MHD 格式
MHD(MetaImage Header)是一种用于医学图像存储的文件格式。它通常与RAW数据文件配合使用,以提供图像数据的详细描述。
特点:
文件结构:MHD文件包含图像数据的元数据,如维度、数据类型、像素间距等。与之配套的RAW文件则存储实际的图像数据。
灵活性:MHD文件可以描述任意维度的图像数据,适用于3D医学图像。
易读性:由于MHD文件是纯文本文件,易于阅读和修改。
应用:广泛用于医学图像处理和分析,特别是在研究和开发阶段。
示例:
ObjectType = Image
NDims = 3
DimSize = 256 256 128
ElementType = MET_UCHAR
ElementSpacing = 1.0 1.0 1.0
ElementDataFile = image.raw
DICOM 格式
DICOM(Digital Imaging and Communications in Medicine)是医学成像领域的标准格式,用于存储、传输和处理医学图像。
特点:
综合性:DICOM文件不仅包含图像数据,还包括丰富的患者信息、扫描参数等元数据。
互操作性:作为标准格式,DICOM文件可以在不同的医学成像设备和软件之间无缝传输。
复杂性:DICOM格式较为复杂,包含大量的标准标签和数据元素。
广泛应用:广泛应用于医院、诊所等医疗机构,用于CT、MRI、X光等多种医学成像设备。
示例:
DICOM文件通常包含一个头部和图像数据部分。头部包括患者信息、图像获取参数等,例如:
(0008, 0020) Study Date
(0010, 0010) Patient's Name
(0020, 0013) Image Number
对比总结
MHD文件简单、灵活,适合研究和开发环境。
DICOM文件复杂、综合性强,是医学成像的行业标准,适用于临床环境。
MHD转DICOM
代码如下:
import os
import numpy as np
import SimpleITK as sitk
import pydicom
from pydicom.dataset import Dataset, FileDataset
from pydicom.uid import generate_uid
def convert_mhd_to_dicom(mhd_file_path, dicom_output_dir):
if not os.path.exists(dicom_output_dir):
os.makedirs(dicom_output_dir)
series_instance_uid = generate_uid()
study_instance_uid = generate_uid()
# Read the MHD image
image = sitk.ReadImage(mhd_file_path)
image_array = sitk.GetArrayFromImage(image)
# Get metadata
spacing = image.GetSpacing()
origin = image.GetOrigin()
direction = image.GetDirection()
# Iterate over each slice and save it as a DICOM file
for i in range(image_array.shape[0]):
slice_array = image_array[i, :, :]
slice_array = slice_array.astype(np.uint8)
# Create DICOM dataset
file_meta = pydicom.dataset.FileMetaDataset()
file_meta.MediaStorageSOPClassUID = pydicom.uid.MRImageStorage
file_meta.MediaStorageSOPInstanceUID = generate_uid()
file_meta.TransferSyntaxUID = pydicom.uid.ExplicitVRLittleEndian
ds = FileDataset(None, {}, file_meta=file_meta, preamble=b"\0" * 128)
# Set necessary values for the DICOM dataset
ds.PatientName = "0001"
ds.PatientID = "0001"
ds.Modality = "MR"
ds.ContentDate = "20240101"
ds.ContentTime = "120000"
ds.StudyInstanceUID = study_instance_uid
ds.SeriesInstanceUID = series_instance_uid
ds.SOPInstanceUID = file_meta.MediaStorageSOPInstanceUID
ds.SOPClassUID = file_meta.MediaStorageSOPClassUID
# Set pixel data
ds.is_little_endian = True
ds.is_implicit_VR = False
ds.PixelData = slice_array.tobytes()
# Set additional metadata
ds.Rows, ds.Columns = slice_array.shape
ds.BitsAllocated = 8
ds.BitsStored = 8
ds.HighBit = 7
ds.PixelRepresentation = 0
ds.SamplesPerPixel = 1
ds.PhotometricInterpretation = "MONOCHROME2"
ds.PixelSpacing = [str(spacing[0]), str(spacing[1])]
ds.SpacingBetweenSlices = str(spacing[2])
ds.SliceThickness = str(spacing[2])
ds.ImagePositionPatient = [str(origin[0]), str(origin[1]), str(origin[2] + i * spacing[2])]
ds.ImageOrientationPatient = [str(direction[0]), str(direction[1]), str(direction[2]),
str(direction[3]), str(direction[4]), str(direction[5])]
# Save the DICOM file
dicom_file_path = os.path.join(dicom_output_dir, f"slice_{i:04d}.dcm")
ds.save_as(dicom_file_path)
print(f"Saved {dicom_file_path}")
convert_mhd_to_dicom('E:/ptj/3D-RU-Net-master/Output/0001/EnsemblePreds.mhd',
'E:/ptj/3D-RU-Net-master/Output/0001/dicom')
目录结构如下:
总体来说,输入mhd文件路径,在dicom文件夹中输出若干dicom格式的文件堆栈,需要注意的是ds.SliceThickness 可能需要根据实际情况经行修改。
结尾
医工结合是未来的发展趋势。我们深知一线临床医疗人员的辛苦与挑战。如果您是一名临床医生,并在科研上遇到问题,可以随时与我联系。