C#: 如何读取文件的部分内容?(DICOM)

13

我希望能够在 C# 中读取 DICOM 文件。目前仅想知道如何读取元素,但首先需要了解如何读取文件头以检查它是否为有效的 DICOM 文件,并不需要进行其它处理。

DICOM 文件由二进制数据元素组成。前 128 字节未使用(设置为零),后跟字符串“DICM”。接下来是组织为组的头信息。

一个样例 DICOM 文件头

前 128 字节:未使用的 DICOM 格式。
接下来是字符 'D'、'I'、'C'、'M'
接下来是额外的头信息,例如:
0002,0000,文件元素组长度:132 0002,0001,文件元信息版本:256 0002,0010,传输语法 UID:1.2.840.10008.1.2.1。 0008,0000,识别组长度:152 0008,0060,形态:MR 0008,0070,制造商:MRIcro

在上面的示例中,头部按组织,16 进制下的组 0002 是文件元信息组,其中包含 3 个元素:一个定义组长度,一个存储文件版本,第三个存储传输语法。

问题

  • 如何读取文件头并通过检查 128 字节引导后的 'D'、'I'、'C'、'M' 字符来验证它是否为 DICOM 文件?
  • 我如何继续解析文件以读取数据的其他部分?

我认为最好使用ReadLine()而不是逐字节读取文件。每个记录似乎在不同的行上。 - A9S6
4个回答

12

像这样读取文件,它很基本且不能处理所有情况,但它是一个起点:


public void ReadFile(string filename)
{
    using (FileStream fs = File.OpenRead(filename))
    {
        fs.Seek(128, SeekOrigin.Begin);
        if ((fs.ReadByte() != (byte)'D' ||
             fs.ReadByte() != (byte)'I' ||
             fs.ReadByte() != (byte)'C' ||
             fs.ReadByte() != (byte)'M'))
        {
            Console.WriteLine("Not a DCM");
            return;
        }
        BinaryReader reader = new BinaryReader(fs);

        ushort g;
        ushort e;
        do
        {
            g = reader.ReadUInt16();
            e = reader.ReadUInt16();

            string vr = new string(reader.ReadChars(2));
            long length;
            if (vr.Equals("AE") || vr.Equals("AS") || vr.Equals("AT")
                || vr.Equals("CS") || vr.Equals("DA") || vr.Equals("DS")
                || vr.Equals("DT") || vr.Equals("FL") || vr.Equals("FD")
                || vr.Equals("IS") || vr.Equals("LO") || vr.Equals("PN")
                || vr.Equals("SH") || vr.Equals("SL") || vr.Equals("SS")
                || vr.Equals("ST") || vr.Equals("TM") || vr.Equals("UI")
                || vr.Equals("UL") || vr.Equals("US"))
               length = reader.ReadUInt16();
            else
            {
                // Read the reserved byte
                reader.ReadUInt16();
                length = reader.ReadUInt32();
            }

            byte[] val = reader.ReadBytes((int) length);

        } while (g == 2);

        fs.Close();
    }

    return ;
}

该代码实际上并没有尝试考虑编码数据的传输语法在第二组元素之后可能会发生变化,它也没有尝试对实际读取的值做任何处理。


谢谢,Xaisoft。如果你真的想看,我从ClearCanvas库中复制了一些代码,这些库基于早期版本的mDCM。你可以查看ClearCanvas.Dicom.IO.DicomStreamReader类来查看我们的解析器,它显然比这个片段复杂得多。 - Steve Wranovsky

1

只是一些伪代码

如何读取头文件并通过检查128字节前导后的'D'、'I'、'C'、'M'字符来验证它是否为DICOM文件?

  • 以二进制文件形式打开,使用File.OpenRead
  • 定位到位置128并将4个字节读入数组中,并将其与DICM的byte[]值进行比较。您可以使用ASCIIEncoding.GetBytes()进行比较

如何继续解析文件并读取其他数据部分?

  • 使用先前拥有的FileStream对象句柄使用Read或ReadByte继续读取文件
  • 使用上述相同的方法进行比较。

不要忘记关闭和处理文件。


0

你也可以这样使用。

FileStream fs = File.OpenRead(path);

byte[] data = new byte[132];
fs.Read(data, 0, data.Length);

int b0 = data[0] & 255, b1 = data[1] & 255, b2 = data[2] & 255, b3 = data[3] & 255;

if (data[128] == 68 && data[129] == 73 && data[130] == 67 && data[131] == 77)
        {
           //dicom file
        }
        else if ((b0 == 8 || b0 == 2) && b1 == 0 && b3 == 0)
        {
            //dicom file
        }

0

Evil Dicom库的EvilDicom.Helper.DicomReader中获取:

 public static bool IsValidDicom(BinaryReader r)
    {
        try
        {
            //128 null bytes
            byte[] nullBytes = new byte[128];
            r.Read(nullBytes, 0, 128);
            foreach (byte b in nullBytes)
            {
                if (b != 0x00)
                {
                    //Not valid
                    Console.WriteLine("Missing 128 null bit preamble. Not a valid DICOM file!");
                    return false;
                }
            }
        }
        catch (Exception)
        {

            Console.WriteLine("Could not read 128 null bit preamble. Perhaps file is too short");
            return false;
        }

        try
        {
            //4 DICM characters
            char[] dicm = new char[4];
            r.Read(dicm, 0, 4);
            if (dicm[0] != 'D' || dicm[1] != 'I' || dicm[2] != 'C' || dicm[3] != 'M')
            {
                //Not valid
                Console.WriteLine("Missing characters D I C M in bits 128-131. Not a valid DICOM file!");
                return false;
            }
            return true;

        }
        catch (Exception)
        {

            Console.WriteLine("Could not read DICM letters in bits 128-131.");
            return false;
        }

    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接