C# 醫學DICOM文件

一般醫學用的DICOM文件一般都是在標籤  7FE00010和60003000

 

使用方法

  ImageDcm _Property_Dcm = new ImageDcm();
  string _Address = “e:\1.dcm”;
   
_Property_Dcm.File_Load(System.IO.File.ReadAllBytes( _Bytes));

  Image _Property_DrawImage = m_Property_Dcm.ElementValue_Image("7FE00010");
  Image _Property_60003000 = m_Property_Dcm.ElementValue_Image("60003000");

 

下面是代碼。

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.IO;

namespace Zgke.MyImage.ImageFile
{
    /// <summary>
    /// DCM 文件轉換類
    /// [email protected]
    /// qq:116149
    /// </summary>
    public class ImageDcm
    {
        private Dictionary<string, object> m_ParamentValue = new Dictionary<string, object>();

        public ImageDcm()
        {
           
        }

        public void File_Load(byte[] p_FileBytes)
        {
            if (p_FileBytes.Length < 132) throw new Exception("文件錯誤!");
            if (Encoding.ASCII.GetString(p_FileBytes, 128, 4) != "DICM") throw new Exception("文件DICOM錯誤!");
            int _ReaderIndex = 132;
            while (_ReaderIndex < p_FileBytes.Length)
            {
                

                string _ElementID = p_FileBytes[_ReaderIndex + 1].ToString("X02") + p_FileBytes[_ReaderIndex].ToString("X02") + p_FileBytes[_ReaderIndex + 3].ToString("X02") + p_FileBytes[_ReaderIndex + 2].ToString("X02");
                _ReaderIndex += 4;
                string _ElementVR = Encoding.ASCII.GetString(p_FileBytes, _ReaderIndex, 2);
                _ReaderIndex += 2;
                //if (_ElementID == "20500020")
                //{
                //    int a = 0;
                //}
                object _Value = File_ElementVR(_ElementID, _ElementVR, p_FileBytes, ref _ReaderIndex);
                m_ParamentValue.Add(_ElementID, _Value);
            }
        }
         
        private object File_ElementVR(string p_ElementID, string p_ElementVR, byte[] p_FileBytes, ref int p_ReaderIndex)
        {
            object _Value = null;
            int _Size = 0;
            switch (p_ElementVR)
            {
                case "OB":
                case "OW":
                    _Size = BitConverter.ToInt32(p_FileBytes, p_ReaderIndex + 2);
                    p_ReaderIndex += 6;
                    _Value =  File_DataReader<byte[]>(p_FileBytes, ref p_ReaderIndex, _Size);
                    break;
                case "SL":
                    _Size = BitConverter.ToUInt16(p_FileBytes, p_ReaderIndex);
                    p_ReaderIndex += 2;
                    _Value =  File_DataReader<int>(p_FileBytes, ref p_ReaderIndex, _Size);
                    break;
                case "UL":
                case "AT":
                    _Size = BitConverter.ToUInt16(p_FileBytes, p_ReaderIndex);
                    p_ReaderIndex += 2;
                    _Value = File_DataReader<uint>(p_FileBytes, ref p_ReaderIndex, _Size);
                    break;
                case "US":
                    _Size = BitConverter.ToUInt16(p_FileBytes, p_ReaderIndex);
                    p_ReaderIndex += 2;
                    _Value =  File_DataReader<ushort>(p_FileBytes, ref p_ReaderIndex, _Size);
                    break;
                case "SS":
                    _Size = BitConverter.ToUInt16(p_FileBytes, p_ReaderIndex);
                    p_ReaderIndex += 2;
                    _Value = File_DataReader<short>(p_FileBytes, ref p_ReaderIndex, _Size);
                    break;
                case "FL":
                    _Size = BitConverter.ToUInt16(p_FileBytes, p_ReaderIndex);
                    p_ReaderIndex += 2;
                    _Value =  File_DataReader<float>(p_FileBytes, ref p_ReaderIndex, _Size);
                    break;
                case "FD":
                    _Size = BitConverter.ToUInt16(p_FileBytes, p_ReaderIndex);
                    p_ReaderIndex += 2;
                    _Value = File_DataReader<double>(p_FileBytes, ref p_ReaderIndex, _Size);
                    break;
                case "UI":
                case "SH":
                case "CS":
                case "DA":
                case "TM":
                case "LO":
                case "ST":
                case "PN":
                case "AS":
                case "AE":
                case "DS":
                case "IS":
                case "LT":
                case "DT":
                    _Size = BitConverter.ToUInt16(p_FileBytes, p_ReaderIndex);
                    p_ReaderIndex += 2;
                    if (_Size != 0)
                    {
                        _Value = Encoding.ASCII.GetString(p_FileBytes, p_ReaderIndex, _Size);
                        p_ReaderIndex += _Size;
                    }
                    else
                    {
                        _Value = null;
                    }
                    break;
                case "SQ":
                    #region SQ

                    if (BitConverter.ToString(p_FileBytes, p_ReaderIndex, 6) != "00-00-FF-FF-FF-FF") throw new Exception(p_ElementID + " Error 【" + p_ReaderIndex.ToString() + "】");
                    p_ReaderIndex += 6;

                    List<object> _ReturnList = new List< object>();
                    while (true)
                    {
                        Dictionary<string, object> _Return = new Dictionary<string, object>();

                        if (BitConverter.ToString(p_FileBytes, p_ReaderIndex, 2) != "FE-FF") throw new Exception(p_ElementID + " Error 【" + p_ReaderIndex.ToString() + "】");
                        string _ElementIDSub = BitConverter.ToString(p_FileBytes, p_ReaderIndex, 4);
                        p_ReaderIndex += 4;
                        
                        switch (BitConverter.ToString(p_FileBytes, p_ReaderIndex, 4))
                        {
                            case "FF-FF-FF-FF":
                                p_ReaderIndex += 4;
                                while (true)
                                {
                                    if (BitConverter.ToString(p_FileBytes, p_ReaderIndex, 8) == "FE-FF-0D-E0-00-00-00-00")
                                    {
                                        p_ReaderIndex += 8;
                                        break;
                                    }
                                    string _ElementID = p_FileBytes[p_ReaderIndex + 1].ToString("X02") + p_FileBytes[p_ReaderIndex].ToString("X02") + p_FileBytes[p_ReaderIndex + 3].ToString("X02") + p_FileBytes[p_ReaderIndex + 2].ToString("X02");
                                    p_ReaderIndex += 4;
                                    string _ElementVR = Encoding.ASCII.GetString(p_FileBytes, p_ReaderIndex, 2);
                                    p_ReaderIndex += 2;
                                    object _ValueSub = File_ElementVR(_ElementID, _ElementVR, p_FileBytes, ref p_ReaderIndex);
                                    _Return.Add(_ElementID, _ValueSub);
                                }
                                break;
                            case "00-00-00-00":
                                p_ReaderIndex += 4;
                                break;

                        }


                        _ReturnList.Add(_Return);

                        if (BitConverter.ToString(p_FileBytes, p_ReaderIndex, 8) == "FE-FF-DD-E0-00-00-00-00")
                        {
                            p_ReaderIndex += 8;
                            break;
                        }
                        if (_ElementIDSub == "FE-FF-DD-E0") break;
                    }
                    _Value = _ReturnList;
                    #endregion
                    break;
                default:
                    _Value = File_ElementID(p_ElementID, p_FileBytes, ref p_ReaderIndex);
                    break;
                    
            }

            return _Value;
        }

        private object File_ElementID(string p_ElementID, byte[] p_FileBytes, ref int p_ReaderIndex)
        {
             object _Value = null;
            int _Size = 0;
            if (p_ElementID.Substring(4, 4) == "0000")
            {
                _Size = BitConverter.ToInt32(p_FileBytes, p_ReaderIndex - 2);
                p_ReaderIndex += 2;
                _Value = File_DataReader<uint>(p_FileBytes, ref p_ReaderIndex, _Size);
            }
            else
            {

                switch (p_ElementID)
                {
                    case "7FE00010":
                        _Size = BitConverter.ToInt32(p_FileBytes, p_ReaderIndex - 2);
                        p_ReaderIndex += 2;
                        _Value = File_DataReader<byte[]>(p_FileBytes, ref p_ReaderIndex, _Size);
                        break;
                    case "00280010":
                    case "00280011":
                    case "00280100":
                    case "00280002":
                        _Size = BitConverter.ToInt32(p_FileBytes, p_ReaderIndex - 2);
                        p_ReaderIndex += 2;
                        _Value = File_DataReader<ushort>(p_FileBytes, ref p_ReaderIndex, _Size);
                        break;
                    default:
                        _Size = BitConverter.ToInt32(p_FileBytes, p_ReaderIndex - 2);
                        p_ReaderIndex += 2;
                        if (_Size != 0)
                        {
                            _Value = Encoding.ASCII.GetString(p_FileBytes, p_ReaderIndex, _Size);
                            p_ReaderIndex += _Size;
                        }
                        else
                        {
                            _Value = null;
                        }
                        break;
                }
                
            }
            return _Value;
        }

        private object File_DataReader<T>(byte[] p_FileBytes, ref int p_ReaderIndex, int p_ReaderSize)
        {
            if (p_ReaderSize == 0) return null;
            int _Count = 0;
            switch (typeof(T).Name)
            {
                case "Byte[]":
                    byte[] _Bytes =new byte[p_ReaderSize];
                    Array.Copy(p_FileBytes, p_ReaderIndex, _Bytes, 0, _Bytes.Length);
                    p_ReaderIndex += p_ReaderSize;
                    return _Bytes;
                case "Double":
                    if (p_ReaderSize % 8 != 0) throw new Exception("DataReader Size Error at【" + p_ReaderIndex.ToString() + "】");
                    _Count = p_ReaderSize / 8;
                    if (_Count == 1)
                    {
                        double _Double = BitConverter.ToDouble(p_FileBytes, p_ReaderIndex);
                        p_ReaderIndex += 8;
                        return _Double;
                    }
                    else
                    {
                        double[] _Double = new double[_Count];
                        for (int i = 0; i != _Count; i++)
                        {
                            _Double[i] = BitConverter.ToDouble(p_FileBytes, p_ReaderIndex);
                            p_ReaderIndex += 8;
                        }
                        return _Double;
                    }
                case "Single":
                    if (p_ReaderSize % 4 != 0) throw new Exception("DataReader Size Error at【" + p_ReaderIndex.ToString() + "】");
                    _Count = p_ReaderSize / 4;
                    if (_Count == 1)
                    {
                        float _Float = BitConverter.ToSingle(p_FileBytes, p_ReaderIndex);
                        p_ReaderIndex += 4;
                        return _Float;
                    }
                    else
                    {
                        float[] _Float = new float[_Count];
                        for (int i = 0; i != _Count; i++)
                        {
                            _Float[i] = BitConverter.ToSingle(p_FileBytes, p_ReaderIndex);
                            p_ReaderIndex += 4;
                        }
                        return _Float;
                    }
                case "Int32":
                    if (p_ReaderSize % 4 != 0) throw new Exception("DataReader Size Error at【" + p_ReaderIndex.ToString() + "】");
                    _Count = p_ReaderSize / 4;
                    if (_Count == 1)
                    {
                        int _Int = BitConverter.ToInt32(p_FileBytes, p_ReaderIndex);
                        p_ReaderIndex += 4;
                        return _Int;
                    }
                    else
                    {
                        int[] _Int = new int[_Count];
                        for (int i = 0; i != _Count; i++)
                        {
                            _Int[i] = BitConverter.ToInt32(p_FileBytes, p_ReaderIndex);
                            p_ReaderIndex += 4;
                        }
                        return _Int;
                    }
                case "UInt32":
                    if (p_ReaderSize % 4 != 0) throw new Exception("DataReader Size Error at【" + p_ReaderIndex.ToString() + "】");
                    _Count = p_ReaderSize / 4;
                    if (_Count == 1)
                    {
                        uint _Unit32 = BitConverter.ToUInt32(p_FileBytes, p_ReaderIndex);
                        p_ReaderIndex += 4;
                        return _Unit32;
                    }
                    else
                    {
                        uint[] _Uint32 = new uint[_Count];
                        for (int i = 0; i != _Count; i++)
                        {
                            _Uint32[i] = BitConverter.ToUInt32(p_FileBytes, p_ReaderIndex);
                            p_ReaderIndex += 4;
                        }
                        return _Uint32;
                    }
                case "Int16":
                    if (p_ReaderSize % 2 != 0) throw new Exception("DataReader Size Error at【" + p_ReaderIndex.ToString() + "】");
                    _Count = p_ReaderSize / 2;
                    if (_Count == 1)
                    {
                        short _Short = BitConverter.ToInt16(p_FileBytes, p_ReaderIndex);
                        p_ReaderIndex += 2;
                        return _Short;
                    }
                    else
                    {
                        short[] _Short = new short[_Count];
                        for (int i = 0; i != _Count; i++)
                        {
                            _Short[i] = BitConverter.ToInt16(p_FileBytes, p_ReaderIndex);
                            p_ReaderIndex += 2;
                        }
                        return _Short;
                    }
                case "UInt16":
                    if (p_ReaderSize % 2 != 0) throw new Exception("DataReader Size Error at【" + p_ReaderIndex.ToString() + "】");
                    _Count = p_ReaderSize / 2;
                    if (_Count == 1)
                    {
                        ushort _Unit16 = BitConverter.ToUInt16(p_FileBytes, p_ReaderIndex);
                        p_ReaderIndex += 2;
                        return _Unit16;
                    }
                    else
                    {
                        ushort[] _Unit16 = new ushort[_Count];
                        for (int i = 0; i != _Count; i++)
                        {
                            _Unit16[i] = BitConverter.ToUInt16(p_FileBytes, p_ReaderIndex);
                            p_ReaderIndex += 2;
                        }
                        return _Unit16;
                    }
                default:
                    throw new Exception(typeof(T).Name + " DataReader Type at【" + p_ReaderIndex.ToString() + "】");
            }
        }

        public double ElementValue_Double(string p_ElementID)
        {
            if (!m_ParamentValue.ContainsKey(p_ElementID) || m_ParamentValue[p_ElementID] == null) return 0;
            double _ReturnValue = 0;
            if (double.TryParse(m_ParamentValue[p_ElementID].ToString(), out _ReturnValue)) return _ReturnValue;
            return 0;
        }

        public short ElementValue_Int16(string p_ElementID)
        {
            if (!m_ParamentValue.ContainsKey(p_ElementID) || m_ParamentValue[p_ElementID] == null ) return 0;
            short _ReturnValue = 0;
            if (short.TryParse(m_ParamentValue[p_ElementID].ToString(), out _ReturnValue)) return _ReturnValue;
            return 0;
        }
        
        public int ElementValue_Int32(string p_ElementID)
        {
            if (!m_ParamentValue.ContainsKey(p_ElementID) || m_ParamentValue[p_ElementID]==null ) return 0;
            int _ReturnValue = 0;
            if (int.TryParse(m_ParamentValue[p_ElementID].ToString(), out _ReturnValue)) return _ReturnValue;
            return 0;
        }

        public string ElementValue_String(string p_ElementID)
        {
            if (!m_ParamentValue.ContainsKey(p_ElementID) || m_ParamentValue[p_ElementID]==null) return "";
            return m_ParamentValue[p_ElementID].ToString();
        }

        public void ElementValue_Save(string p_ElementID, object p_Value)
        {
            if (!m_ParamentValue.ContainsKey(p_ElementID)) m_ParamentValue.Add(p_ElementID, null);
            m_ParamentValue[p_ElementID] = p_Value;
        }

        public Bitmap ElementValue_Image(string p_ElementID)
        {
            if (!m_ParamentValue.ContainsKey(p_ElementID) || m_ParamentValue[p_ElementID] == null || m_ParamentValue[p_ElementID].GetType()!=typeof(byte[]) ) return null;
            string _ElementGroup = p_ElementID.Substring(0, 4);
            if (p_ElementID == "7FE00010") _ElementGroup = "0028";

            string _Type = ElementValue_String(_ElementGroup + "0004").Trim();
            int _Width = ElementValue_Int32(_ElementGroup + "0011");
            int _Height = ElementValue_Int32(_ElementGroup + "0010");
            int _Pix = ElementValue_Int32(_ElementGroup + "0100");
            int _Samples = ElementValue_Int32(_ElementGroup + "0002");
            if (_Samples != 0) _Pix *= _Samples;
          
            if (_Width == 0 || _Height == 0 || _Pix == 0) return null;
            
            byte[] _ImageBytes = (byte[])m_ParamentValue[p_ElementID];
            Bitmap _NewBitmap = null;
            BitmapData _NewBitmapData = null;
            ColorPalette _Palette = null;
            byte[] _ImageBytesWrite = null;
            switch (_Pix)
            {
                case 24:
                    #region 原始24位 彩色
                    _NewBitmap = new Bitmap(_Width, _Height, PixelFormat.Format24bppRgb);
                    _NewBitmapData = _NewBitmap.LockBits(new Rectangle(0, 0, _NewBitmap.Width, _NewBitmap.Height), ImageLockMode.ReadWrite, _NewBitmap.PixelFormat);
                    Marshal.Copy(_ImageBytes, 0, _NewBitmapData.Scan0, _ImageBytes.Length);
                    _NewBitmap.UnlockBits(_NewBitmapData);
                    #endregion
                    break;
                case 16:                    
                    #region 原始16位 灰度
                    _NewBitmap = new Bitmap(_Width, _Height, PixelFormat.Format8bppIndexed);
                    _NewBitmapData = _NewBitmap.LockBits(new Rectangle(0, 0, _NewBitmap.Width, _NewBitmap.Height), ImageLockMode.ReadWrite, _NewBitmap.PixelFormat);
                    _Palette = _NewBitmap.Palette;
                    switch (_Type)
                    {
                        case "MONOCHROME2":
                            for (int i = 0; i != _Palette.Entries.Length; i++)
                            {
                                _Palette.Entries[i] = Color.FromArgb(255, i, i, i);
                            }
                            break;
                        case "MONOCHROME1":
                            for (int i = 0; i != _Palette.Entries.Length; i++)
                            {
                                int _PaletteValue = 255 - i;
                                _Palette.Entries[i] = Color.FromArgb(255, _PaletteValue, _PaletteValue, _PaletteValue);
                            }
                            break;
                        default: throw new Exception("DrawImage Not (MONOCHROME2 OR MONOCHROME1)");
                    }
                    _NewBitmap.Palette = _Palette;
                    _ImageBytesWrite = new byte[_NewBitmapData.Stride * _NewBitmap.Height];

                    double _WindowCenter = 0;
                    if (!double.TryParse(ElementValue_String(_ElementGroup + "1050").Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries)[0], out _WindowCenter)) return null;
                    double _WindowWidth = 0;
                    if (!double.TryParse(ElementValue_String(_ElementGroup + "1051").Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries)[0], out _WindowWidth)) return null;
                    short _RescaleIntercept = ElementValue_Int16(_ElementGroup + "1052");


                    double _WindowMin = _WindowCenter - _WindowWidth / 2;
                    double _WindowMax = _WindowCenter + _WindowWidth / 2;
               

                    for (int y = 0; y != _NewBitmap.Height; y++)
                    {
                        int _IndexWrite = _NewBitmapData.Stride * y;
                        int _IndexReader = _Width * 2 * y;
                        for (int x = 0; x != _NewBitmap.Width; x++)
                        {
                            int _ReaderValue = BitConverter.ToInt16(_ImageBytes, _IndexReader) + _RescaleIntercept;

                            if (_ReaderValue < _WindowMin)
                            {
                                _ImageBytesWrite[_IndexWrite] = 0;
                            }
                            else if (_ReaderValue > _WindowMax)
                            {
                                _ImageBytesWrite[_IndexWrite] = 255;
                            }
                            else
                            {
                                double _ImageValue = (_ReaderValue - _WindowMin) / _WindowWidth * 255;
                                _ImageBytesWrite[_IndexWrite] = (byte)_ImageValue;
                            }
                            _IndexWrite++;
                            _IndexReader += 2;
                        }
                    }
                    Marshal.Copy(_ImageBytesWrite, 0, _NewBitmapData.Scan0, _ImageBytesWrite.Length);
                    _NewBitmap.UnlockBits(_NewBitmapData);
                    #endregion
                    break;
                case 1:
                    #region  原始1位
                    _NewBitmap = new Bitmap(_Width, _Height, PixelFormat.Format1bppIndexed);
                    _NewBitmapData = _NewBitmap.LockBits(new Rectangle(0, 0, _NewBitmap.Width, _NewBitmap.Height), ImageLockMode.ReadWrite, _NewBitmap.PixelFormat);
                    _Palette = _NewBitmap.Palette;
                    _Palette.Entries[0] = Color.FromArgb(0, 0, 0, 0);
                    _Palette.Entries[1] = Color.FromArgb(255, 255, 255, 255);
                    _NewBitmap.Palette = _Palette;
                    _ImageBytesWrite = new byte[_NewBitmapData.Stride * _NewBitmap.Height];
                    int _Sleep = _Width / 8;
                    for (int y = 0; y != _NewBitmap.Height; y++)
                    {
                        int _IndexRow = _NewBitmapData.Stride * y;
                        for (int x = 0; x != _Sleep; x++)
                        {
                            _ImageBytesWrite[_IndexRow] = Zgke.MyConvert.OperateBytes.ReverseByte(_ImageBytes[_IndexRow]);
                            _IndexRow++;
                        }
                    }
                    Marshal.Copy(_ImageBytesWrite, 0, _NewBitmapData.Scan0, _ImageBytesWrite.Length);
                    _NewBitmap.UnlockBits(_NewBitmapData);
                    #endregion
                    break;
                default: throw new Exception("DrawImage  Not 【" + _Pix.ToString() + "】");
            }

            
            return _NewBitmap;
        } 

      
    }
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章