С#: как читать части файла? (DICOM)

Я хотел бы прочитать файл DICOM в С#. Я не хочу ничего делать, я просто хотел бы знать, как читать элементы, но сначала мне бы хотелось узнать, как читать заголовок, чтобы увидеть, является ли допустимым DICOM файл.

Он состоит из двоичных элементов данных. Первые 128 байтов не используются (установлены на ноль), а затем строка "DICM". За ним следует информация заголовка, которая организована в группы.

Пример заголовка DICOM

First 128 bytes: unused DICOM format.
Followed by the characters 'D','I','C','M'
Followed by extra header information such as:

0002,0000, File Meta Elements Groups Len: 132
0002,0001, File Meta Info Version: 256
0002,0010, Transfer Syntax UID: 1.2.840.10008.1.2.1.
0008,0000, Identifying Group Length: 152
0008,0060, Modality: MR
0008,0070, Manufacturer: MRIcro

В приведенном выше примере заголовок организован в группы. Группа 0002 hex представляет собой группу метаданных файла, которая содержит 3 элемента: один определяет длину группы, один хранит версию файла и сохраняет их синтаксис передачи.

Вопросы

  • Как я могу прочитать файл заголовка и проверить, является ли он файлом DICOM, проверяя символы "D", "I", "C", "M" после 128-байтовой преамбулы?
  • Как продолжить анализ файла, просматривающего другие части данных?

Ответ 1

Что-то вроде этого должно прочитать файл, его основной и не обрабатывать все случаи, но это будет отправной точкой:


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 ;
}

Код на самом деле не пытается учесть, что синтаксис передачи закодированных данных может измениться после элементов группы 2, он также не пытается ничего делать с фактическими значениями, считанными.

Ответ 4

Только некоторые псевдологические

Как прочитать файл заголовка и проверить, является ли он файлом DICOM, проверяя символы "D", "I", "C", "M" после 128-байтовой преамбулы?

  • Открыть как двоичный файл, используя File.OpenRead
  • Найдите позицию 128 и прочитайте 4 байта в массиве и сравните ее снова с байтом [] для DICM. Вы можете использовать ASCIIEncoding.GetBytes() для этого

Как продолжить анализ файла, просматривающего другие части данных?

  • Продолжайте чтение файла с помощью Read или ReadByte с помощью дескриптора объекта FileStream, который у вас был ранее
  • Используйте тот же метод, что и выше, для сравнения.

Не забудьте закрыть и удалить файл.

Ответ 5

вы также можете использовать это.

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
        }

Ответ 6

Взято из EvilDicom.Helper.DicomReader из библиотека Evil Dicom:

 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;
        }

    }