2011年3月23日水曜日

カラービットマップ

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

{
if(PhotometricInterpretation != "RGB")
    retern;
//dataSet: DicomDataSet
Bitmap bitmap;
int columns = dataSet.Columns;
int rows = dataSet.Rows;
byte[] pixelData = dataSet.PixelData;
bitmap = new Bitmap(columns, rows, PixelFormat.Format24bppRgb);
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, columns, rows), 
ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
int padding = bitmapData.Stride - columns;
byte* pBitmap = (byte*)bitmapData.Scan0;
int j = 0, i = 0;
for (int y = 0; y < rows; y++)
{
    j = y * columns;
    for (int x = 0; x < columns; x++)
    {
        i = j + x;
        pBitmap[i * 3]     = pixelData[i * 3 + 2];   //G
        pBitmap[i * 3 + 1] = pixelData[i * 3 + 1];   //B
        pBitmap[i * 3 + 2] = pixelData[i * 3];       //R
    }
    i += padding;
}
bitmap.UnlockBits(bitmapData);
return bitmap;
}
.net 4.0から Parallel.For が使えるようになったので一部訂正。2015-08-12
fixed (byte* pData = pixelData)
{
    byte* rgb = pData;
    int stride = bmpData.Stride;
    Parallel.For(0, rows, y =>
    {
        for (int x = 0; x < columns; x++)
        {
            int pos = (x * 3) + y * stride;
            pBitmap[pos]     = rgb[pos + 2];   //G  
            pBitmap[pos + 1] = rgb[pos + 1];   //B
            pBitmap[pos + 2] = rgb[pos];       //R
        }
    });
}

2011年3月21日月曜日

マルチフレーム

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

List<byte[]> pixelDataList = new List<byte[]>();
int numberOfFrames = dicomData.NumberOfFrames;
int length = dicomData.PixelData.Length / numberOfFrames;
for(int k=0; k < numberOfFrames;k++)
{
    byte[] buf;
    Array.Copy(dicomData.PixelData, numberOfFrames * length, buf, 0, length);
    pixelDataList.Add(buf);
}

RescaleIntercept タグ と RescaleSlopeタグ

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

fixed (byte* pData = pixelData)
{
    int pixel;
    short* ptr = (short*)pData; //short型ポインタ
    byte* pBitmap = (byte*)bitmapData.Scan0;
    int j = 0, i = 0;
    int difference = max - min;
    if (rescaleIntercept == 0.0d )
    {
        for (int x = 0; x < _columns; x++)
        {
            pixel = (int)(((*ptr + rescaleIntercept - windowCenter) / windowWidth + 0.5d) * 255.0d);
            if (pixel > 255) pixel = 255;
            else if (pixel < 0) pixel = 0;
            *pBitmap = (byte)pixel; ptr++; pBitmap++;
        }
        pBitmap += padding;
    }
    else
    {
        for (int y = 0; y < _rows; y++)
        {
            j = y * _columns;
            for (int x = 0; x < _columns; x++)
            {
                pixel = (int)((((int)ptr[j + x] + rescaleIntercept - windowCenter) / windowWidth + 0.5d) * 255.0d);
                if (pixel > 255) pixel = 255;
                if (pixel < 0) pixel = 0;
                pixel = (int)(rescaleSlope * pixel + rescaleIntercept);
                pBitmap[i] = (byte)pixel;
                i++;
           }
           i += padding;
       }
    }
}

16 bit グレースケール

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

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

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


データの挿入 ()
public unsafe Bitmap Grayscale16To8()

{

int padding = bitmapData.Stride - columns;

int min = windowCenter - windowWidth / 2;

int max = windowCenter + windowWidth / 2;

fixed (byte* pData = pixelData)

{

    int pixel;

    short* ptr = (short*)pData;

    byte* pBitmap = (byte*)bitmapData.Scan0;

    int j = 0, i = 0;

    for (int y = 0; y < _rows; y++)

    {

        j = y * _columns;

        for (int x = 0; x < _columns; x++)

        {

            pixel = (int)ptr[j + x];   

            if (pixel <= min)

                pixel = 0;

            else if (pixel >= max)

                pixel = 255;

            else

                pixel = (int)((pixel - min) * 255 / (max - min));

            pBitmap[i] = (byte)pixel;

            i++;

        }

        i += padding;

    }

}

bitmap.UnlockBits(bitmapData);

return bitmap;

}