如何根据一个.raw文件还原为一个dicom文件

本文由Markdown语法编辑器编辑完成.

1. 需求背景

已知已经获取到了一幅dicom医学图像的像素文件, 它的格式为.raw文件. 由于市面上通用的dicom viewer软件, 都只能识别dicom格式的文件. 因此, 如何将这个.raw文件, 还原为能够被大部分软件识别的医学dicom文件, 从而进行相应的显示和操作.

2. 需求调研

2.1 本地已有软件尝试

我本地的电脑中, 已经安装有三款dicom viewer的软件, 分别是: 3D Slicer, RadiAnt, Aliza.
用这三款软件, 载入本地的.raw文件时, 均无法正常的加载. 软件界面都会提示不同的错误信息, 大意都是文件不是正常的dicom文件, 无法加载. 可见这三个软件, 在加载文件时, 都会对文件的header进行校验, 如果不存在, 或无法被正确地识别, 都会导致图像无法正常被加载和显示.

2.2 google查找其他软件和方法

通过从google上, 按照: “raw data to dicom” 的关键词来搜索, 可以查询到一些关键信息.

根据: https://www.researchgate.net/post/Dear_all_can_anybody_introduce_me_a_software_to_can_convert_raw_formatted_images_to_dcm_format 链接, 可以看到, 目前市面上是有几款软件, 可以在无dicom的信息头的情况下, 直接显示.raw格式的纯数据文件的. 比较有代表性的两个软件是: ImageJ和XMedCon.

从网上下载了ImageJ的安装包, 并且安装后, 载入本地的.raw文件。出乎意料的是,看起来是一个比较简单轻量级的dicom viewer软件,居然就可以显示出.raw的文件。而RadiAnt, 3d slicer等都无法加载。而且,ImageJ软件,除了可以显示.raw文件,还可以导出该文件成为一个dicom文件。基本上也就实现了我的需求。但是,这个操作毕竟是手动进行的,因此就无法批量的,自动化的进行。

要知道批量和自动化操作,是软件工程师比较追求的。因为只要满足了这两条,那么这些繁琐的操作,便可以交给机器去完成。而自己就可以将更多地精力,放在别的更重要的工作上。这个听起来,也就是人工智能诞生的很重要的原因。

3. 解决方案

3.1 imageJ
https://imagej.nih.gov/ij/

3.2 SimpleITK
simpleITK的examples中提供了一个例子, 是关于读取raw文件的demo.

import argparse
import os
import tempfile

import SimpleITK as sitk


def read_raw(binary_file_name, image_size, sitk_pixel_type, image_spacing=None,
             image_origin=None, big_endian=False):
    """
    Read a raw binary scalar image.

    Parameters
    ----------
    binary_file_name (str): Raw, binary image file content.
    image_size (tuple like): Size of image (e.g. [2048,2048])
    sitk_pixel_type (SimpleITK pixel type: Pixel type of data (e.g.
        sitk.sitkUInt16).
    image_spacing (tuple like): Optional image spacing, if none given assumed
        to be [1]*dim.
    image_origin (tuple like): Optional image origin, if none given assumed to
        be [0]*dim.
    big_endian (bool): Optional byte order indicator, if True big endian, else
        little endian.

    Returns
    -------
    SimpleITK image or None if fails.
    """

    pixel_dict = {sitk.sitkUInt8: 'MET_UCHAR',
                  sitk.sitkInt8: 'MET_CHAR',
                  sitk.sitkUInt16: 'MET_USHORT',
                  sitk.sitkInt16: 'MET_SHORT',
                  sitk.sitkUInt32: 'MET_UINT',
                  sitk.sitkInt32: 'MET_INT',
                  sitk.sitkUInt64: 'MET_ULONG_LONG',
                  sitk.sitkInt64: 'MET_LONG_LONG',
                  sitk.sitkFloat32: 'MET_FLOAT',
                  sitk.sitkFloat64: 'MET_DOUBLE'}
    direction_cosine = ['1 0 0 1', '1 0 0 0 1 0 0 0 1',
                        '1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1']
    dim = len(image_size)
    header = ['ObjectType = Image\n'.encode(),
              ('NDims = {0}\n'.format(dim)).encode(),
              ('DimSize = ' + ' '.join([str(v) for v in image_size]) + '\n')
              .encode(),
              ('ElementSpacing = ' + (' '.join([str(v) for v in image_spacing])
                                      if image_spacing else ' '.join(
                  ['1'] * dim)) + '\n').encode(),
              ('Offset = ' + (
                  ' '.join([str(v) for v in image_origin]) if image_origin
                  else ' '.join(['0'] * dim) + '\n')).encode(),
              ('TransformMatrix = ' + direction_cosine[dim - 2] + '\n')
              .encode(),
              ('ElementType = ' + pixel_dict[sitk_pixel_type] + '\n').encode(),
              'BinaryData = True\n'.encode(),
              ('BinaryDataByteOrderMSB = ' + str(big_endian) + '\n').encode(),
              # ElementDataFile must be the last entry in the header
              ('ElementDataFile = ' + os.path.abspath(
                  binary_file_name) + '\n').encode()]
    fp = tempfile.NamedTemporaryFile(suffix='.mhd', delete=False)

    print(header)

    # Not using the tempfile with a context manager and auto-delete
    # because on windows we can't open the file a second time for ReadImage.
    fp.writelines(header)
    fp.close()
    img = sitk.ReadImage(fp.name)
    os.remove(fp.name)
    return img


parser = argparse.ArgumentParser()
parser.add_argument('raw_file_name', help='path to raw binary image file')
parser.add_argument('out_file_name',
                    help='output file name when image read as little endian')
parser.add_argument("big_endian", type=lambda v: v.lower() in {"1", "true"},
                    help="\'false\' for little ending or \'true\'for big "
                    "endian")
parser.add_argument('sitk_pixel_type',
                    help="SimpleITK pixel type (e.g. sitk.sitkUInt16)")
parser.add_argument('sz', nargs='+', help="image size, x,y,...",
                    type=int)
args = parser.parse_args()

string_to_pixelType = {"sitkUInt8": sitk.sitkUInt8,
                       "sitkInt8": sitk.sitkInt8,
                       "sitkUInt16": sitk.sitkUInt16,
                       "sitkInt16": sitk.sitkInt16,
                       "sitkUInt32": sitk.sitkUInt32,
                       "sitkInt32": sitk.sitkInt32,
                       "sitkUInt64": sitk.sitkUInt64,
                       "sitkInt64": sitk.sitkInt64,
                       "sitkFloat32": sitk.sitkFloat32,
                       "sitkFloat64": sitk.sitkFloat64}

# Read the image using both big and little endian
image = read_raw(binary_file_name=args.raw_file_name,
                 image_size=args.sz,
                 sitk_pixel_type=string_to_pixelType[args.sitk_pixel_type],
                 big_endian=args.big_endian)

sitk.WriteImage(image, args.out_file_name)

if "SITK_NOSHOW" not in os.environ:
    sitk.Show(image, 'raw converted')

参考链接:
https://simpleitk.readthedocs.io/en/master/link_RawImageReading_docs.html

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

inter_peng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值