2011年9月17日土曜日

DICOMDIR から TreeNode へ

  1. string path;
  2. if (Path.GetFileName(path).Equals("DICOMDIR"))
  3. retern;
  4. TreeView treeView = new TreeView();
  5. TreeNode treeNode = new TreeNode();
  6. List<string[]> imageList = new List<string[]>();
  7. treeNode.Nodes.Clear();
  8. treeView.Nodes.Clear();
  9. //DicomDir dicomDir = new DicomDir(path);
  10. //ReadDicomDir(dicomDir);
  11. Stream stream = null;
  12. DcmParser parser = null;
  13. Dataset ds = null;
  14. try
  15. {
  16. stream = new BufferedStream(new FileStream(path, FileMode.Open, FileAccess.Read));
  17. parser = new org.dicomcs.data.DcmParser(stream);
  18. org.dicomcs.data.FileFormat format = parser.DetectFileFormat();
  19. if (format != null)
  20. {
  21. ds = new org.dicomcs.data.Dataset();
  22. parser.DcmHandler = ds.DcmHandler;
  23. parser.ParseDcmFile(format);
  24. TreeNode nodePatient = new TreeNode();
  25. TreeNode nodeStudy = new TreeNode();
  26. TreeNode nodeSeries = new TreeNode();
  27. TreeNode nodeStudat = new TreeNode();
  28. //
  29. int tmpStudat = 0;
  30. int patBirdat = 0;
  31. string patName = string.Empty;
  32. //
  33. DcmObject doRoot = (DcmObject)ds;
  34. IEnumerator enuRoot = doRoot.GetEnumerator();
  35. int count = 0;
  36. while (enuRoot.MoveNext())
  37. {
  38. DcmElement elRoot = (DcmElement)enuRoot.Current;
  39. if (elRoot.HasItems())
  40. {
  41. for (int i = 0; i < elRoot.vm(); i++)
  42. {
  43. DcmObject dcmObj = (DcmObject)elRoot.GetItem(i);
  44. IEnumerator enu = dcmObj.GetEnumerator();
  45. while (enu.MoveNext())
  46. {
  47. DcmElement el = (DcmElement)enu.Current;
  48. if (el.tag() == DcmTags.DirectoryRecordType)
  49. {
  50. string rs = el.GetString(Encoding.Unicode);
  51. if (rs == "PATIENT")
  52. {
  53. PatientTable pt = new PatientTable();
  54. if (dcmObj.Contains(Tags.PatientBirthDate))
  55. patBirdat = Convert.ToInt32(dcmObj.GetDate(DcmTags.PatientBirthDate).ToString("yyyyMMdd"));
  56. if (dcmObj.Contains(Tags.PatientName))
  57. patName = dcmObj.GetString(DcmTags.PatientName);
  58. }
  59. else if (rs == "STUDY")
  60. {
  61. if (dcmObj.Contains(DcmTags.StudyDate))
  62. {
  63. int studat = Convert.ToInt32(dcmObj.GetDate(Tags.StudyDate).ToString("yyyyMMdd"));
  64. string stuinsuid = string.Empty;
  65. string studes = string.Empty;
  66. if (dcmObj.Contains(DcmTags.StudyInstanceUID))
  67. stuinsuid = dcmObj.GetString(DcmTags.StudyInstanceUID);
  68. if (dcmObj.Contains(DcmTags.StudyDescription))
  69. studes = dcmObj.GetString(DcmTags.StudyInstanceUID);
  70. if (studat != tmpStudat)
  71. {
  72. nodeStudat = new TreeNode(studat.ToString("####/##/##"));
  73. nodeStudat.Tag = studat;
  74. treeViewStudy.Nodes.Add(nodeStudat);
  75. tmpStudat = studat;
  76. }
  77. nodeStudy = new TreeNode("");
  78. nodeStudat.Nodes.Add(nodeStudy);
  79. }
  80. }
  81. else if (rs == "SERIES")
  82. {
  83. imageList = new List<string[]>();
  84. string serinsuid = string.Empty;
  85. string sernum = string.Empty; ;
  86. string numserrelima = string.Empty;
  87. string serdes = string.Empty;
  88. string bodparexa = string.Empty;
  89. string modality = string.Empty;
  90. if (dcmObj.Contains(DcmTags.SeriesInstanceUID))
  91. serinsuid = dcmObj.GetString(DcmTags.SeriesInstanceUID);
  92. if (dcmObj.Contains(DcmTags.SeriesNumber))
  93. sernum = dcmObj.GetString(DcmTags.SeriesNumber);
  94. if (dcmObj.Contains(DcmTags.SeriesDescription))
  95. serdes = dcmObj.GetString(DcmTags.SeriesDescription);
  96. if (dcmObj.Contains(DcmTags.Modality))
  97. modality = dcmObj.GetString(DcmTags.Modality);
  98. nodeSeries = new TreeNode(modality + "." + sernum);
  99. nodeStudy.Nodes.Add(nodeSeries);
  100. if (nodeStudy.Text == string.Empty)
  101. nodeStudy.Text = modality;
  102. nodeSeries.Tag=imageList; //Add (refFile and uid)List
  103. }
  104. else if (rs == "IMAGE")
  105. {
  106. string refFileID = string.Empty;
  107. string uid = string.Empty;
  108. if (dcmObj.Contains(DcmTags.RefFileID))
  109. refFileID = dcmObj.GetString(DcmTags.RefFileID);
  110. if (dcmObj.Contains(DcmTags.RefSOPInstanceUIDInFile))
  111. uid = dcmObj.GetString(DcmTags.RefSOPInstanceUIDInFile);
  112. string[] ss = new string[2];
  113. ss[0] = refFileID;
  114. ss[1] = uid;
  115. imageList.Add(ss);
  116. }
  117. }
  118. }
  119. }
  120. }
  121. }

2011年5月24日火曜日

dicom-cs あるいは dicomネットワークツール

C#用のDICOMネットワークツール。
イメージ用のソースは無いが元ネタのdcm-4cheにあり。

参照設定
  1. using org.dicomcs.dict;
  2.  
  3. using org.dicomcs.data;
  4.  
  5. using org.dicomcs.net;
  6.  
  7. using org.dicomcs.util;
  8.  
  9. using log4net;
  10.  


log4net用にlog4net.config設定ファイル
[assembly: log4net.Config.XmlConfigurator(ConfigFile = @"log4net.config", Watch = true)]
を入れておく。

出力に
'System.IO.EndOfStreamException' の初回例外が mscorlib.dll で発生しました。
が出る。。。。
stream 読み取り時、エラーが出たら次のtagを読みに行くという設定のためか?
どうしたら出ないようにできるものか。。。。

PixelDataの取得は
  1. org.dicomcs.util.ByteBuffer buff = dataSet.GetByteBuffer(Tags.PixelData);
  2. byte[] pixelData = (byte[])buff.ToArray();

2011年3月23日水曜日

カラービットマップ

pixelDataからカラービットマップを取得
BGR > RGB の変換が必要

  1. {
  2. if(PhotometricInterpretation != "RGB")
  3. retern;
  4. //dataSet: DicomDataSet
  5. Bitmap bitmap;
  6. int columns = dataSet.Columns;
  7. int rows = dataSet.Rows;
  8. byte[] pixelData = dataSet.PixelData;
  9. bitmap = new Bitmap(columns, rows, PixelFormat.Format24bppRgb);
  10. BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, columns, rows),
  11. ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
  12. int padding = bitmapData.Stride - columns;
  13. byte* pBitmap = (byte*)bitmapData.Scan0;
  14. int j = 0, i = 0;
  15. for (int y = 0; y < rows; y++)
  16. {
  17. j = y * columns;
  18. for (int x = 0; x < columns; x++)
  19. {
  20. i = j + x;
  21. pBitmap[i * 3] = pixelData[i * 3 + 2]; //G
  22. pBitmap[i * 3 + 1] = pixelData[i * 3 + 1]; //B
  23. pBitmap[i * 3 + 2] = pixelData[i * 3]; //R
  24. }
  25. i += padding;
  26. }
  27. bitmap.UnlockBits(bitmapData);
  28. return bitmap;
  29. }
.net 4.0から Parallel.For が使えるようになったので一部訂正。2015-08-12
  1. fixed (byte* pData = pixelData)
  2. {
  3. byte* rgb = pData;
  4. int stride = bmpData.Stride;
  5. Parallel.For(0, rows, y =>
  6. {
  7. for (int x = 0; x < columns; x++)
  8. {
  9. int pos = (x * 3) + y * stride;
  10. pBitmap[pos] = rgb[pos + 2]; //G
  11. pBitmap[pos + 1] = rgb[pos + 1]; //B
  12. pBitmap[pos + 2] = rgb[pos]; //R
  13. }
  14. });
  15. }

2011年3月21日月曜日

マルチフレーム

NumberOfFrames タグ (0028,0008)があるとマルチフレーム画像。
PixelData(7FD0,0010)の長さをNumberOfFramesで割った値が一枚当たりの画像の PixelData 。

  1. List<byte[]> pixelDataList = new List<byte[]>();
  2.  
  3. int numberOfFrames = dicomData.NumberOfFrames;
  4.  
  5. int length = dicomData.PixelData.Length / numberOfFrames;
  6.  
  7. for(int k=0; k < numberOfFrames;k++)
  8.  
  9. {
  10.  
  11.     byte[] buf;
  12.  
  13.     Array.Copy(dicomData.PixelData, numberOfFrames * length, buf, 0, length);
  14.  
  15.     pixelDataList.Add(buf);
  16.  
  17. }
  18.  

RescaleIntercept タグ と RescaleSlopeタグ

他院からのCDで Rescale Interceptタグ と Rescale Slopeタグがある DICOM Fileを散見。
シーメンスのCTなど。
画像データに傾斜と切片を付加して8bitグレースケールを得る。

  1. fixed (byte* pData = pixelData)
  2.  
  3. {
  4.  
  5.     int pixel;
  6.  
  7.     short* ptr = (short*)pData; //short型ポインタ
  8.  
  9.     byte* pBitmap = (byte*)bitmapData.Scan0;
  10.  
  11.     int j = 0, i = 0;
  12.  
  13.     int difference = max - min;
  14.  
  15.     if (rescaleIntercept == 0.0d )
  16.  
  17.     {
  18.  
  19.         for (int x = 0; x < _columns; x++)
  20.  
  21.         {
  22.  
  23.             pixel = (int)(((*ptr + rescaleIntercept - windowCenter) / windowWidth + 0.5d) * 255.0d);
  24.  
  25.             if (pixel > 255) pixel = 255;
  26.  
  27.             else if (pixel < 0) pixel = 0;
  28.  
  29.             *pBitmap = (byte)pixel; ptr++; pBitmap++;
  30.  
  31.         }
  32.  
  33.         pBitmap += padding;
  34.  
  35.     }
  36.  
  37.     else
  38.  
  39.     {
  40.  
  41.         for (int y = 0; y < _rows; y++)
  42.  
  43.         {
  44.  
  45.             j = y * _columns;
  46.  
  47.             for (int x = 0; x < _columns; x++)
  48.  
  49.             {
  50.  
  51.                 pixel = (int)((((int)ptr[j + x] + rescaleIntercept - windowCenter) / windowWidth + 0.5d) * 255.0d);
  52.  
  53.                 if (pixel > 255) pixel = 255;
  54.  
  55.                 if (pixel < 0) pixel = 0;
  56.  
  57.                 pixel = (int)(rescaleSlope * pixel + rescaleIntercept);
  58.  
  59.                 pBitmap[i] = (byte)pixel;
  60.  
  61.                 i++;
  62.  
  63.            }
  64.  
  65.            i += padding;
  66.  
  67.        }
  68.  
  69.     }
  70.  
  71. }

16 bit グレースケール

CT, MR, CR, DR などの医用画像は殆どが16bit グレースケール画像。
PCでは8bitしか表示できないので、これを変換。
また Bitmap.SetPixel がとても遅いため LockBits を使用。

  1. using System;
  2. using System.Drawing;
  3. using System.Drawing.Imaging;
DICOMオブジェクト
  1. int columns = dicomData.Columns;
  2. int rows = dicomData.Rows;
  3. int windowCenter = dicomData.WindowCenter;
  4. int windowWidth = dicomData.WindowWidth;
ビットマップ
 1byteが1pixelのグレースケール用ColorPaletteを作成する。
 3byte=1pixelのグレースケール(R=G=B)より容量減か。

  1. byte[] pixelData = dicomData.PixelData;Bitmap bitmap;
  2. ColorPalette colorPalette;
  3. for (int i = 0; i < 256; i++)
  4.     colorPalette.Entries[i] = Color.FromArgb(i, i, i);
  5. Bitmap bitmap = new Bitmap(columns, rows, PixelFormat.Format8bppIndexed);


データの挿入 ()
  1. public unsafe Bitmap Grayscale16To8()
  2.  
  3. {
  4.  
  5. int padding = bitmapData.Stride - columns;
  6.  
  7. int min = windowCenter - windowWidth / 2;
  8.  
  9. int max = windowCenter + windowWidth / 2;
  10.  
  11. fixed (byte* pData = pixelData)
  12.  
  13. {
  14.  
  15.     int pixel;
  16.  
  17.     short* ptr = (short*)pData;
  18.  
  19.     byte* pBitmap = (byte*)bitmapData.Scan0;
  20.  
  21.     int j = 0, i = 0;
  22.  
  23.     for (int y = 0; y < _rows; y++)
  24.  
  25.     {
  26.  
  27.         j = y * _columns;
  28.  
  29.         for (int x = 0; x < _columns; x++)
  30.  
  31.         {
  32.  
  33.             pixel = (int)ptr[j + x];  
  34.  
  35.             if (pixel <= min)
  36.  
  37.                 pixel = 0;
  38.  
  39.             else if (pixel >= max)
  40.  
  41.                 pixel = 255;
  42.  
  43.             else
  44.  
  45.                 pixel = (int)((pixel - min) * 255 / (max - min));
  46.  
  47.             pBitmap[i] = (byte)pixel;
  48.  
  49.             i++;
  50.  
  51.         }
  52.  
  53.         i += padding;
  54.  
  55.     }
  56.  
  57. }
  58.  
  59. bitmap.UnlockBits(bitmapData);
  60.  
  61. return bitmap;
  62.  
  63. }