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