2011年9月17日土曜日

DICOMDIR から TreeNode へ

string path;
if (Path.GetFileName(path).Equals("DICOMDIR"))
retern;
TreeView treeView = new TreeView();
TreeNode treeNode = new TreeNode();
List<string[]> imageList = new List<string[]>();
treeNode.Nodes.Clear();
treeView.Nodes.Clear();
//DicomDir dicomDir = new DicomDir(path);
//ReadDicomDir(dicomDir);
Stream stream = null;
DcmParser parser = null;
Dataset ds = null;
try
{
stream = new BufferedStream(new FileStream(path, FileMode.Open, FileAccess.Read));
parser = new org.dicomcs.data.DcmParser(stream);
org.dicomcs.data.FileFormat format = parser.DetectFileFormat();
if (format != null)
{
ds = new org.dicomcs.data.Dataset();
parser.DcmHandler = ds.DcmHandler;
parser.ParseDcmFile(format);
TreeNode nodePatient = new TreeNode();
TreeNode nodeStudy = new TreeNode();
TreeNode nodeSeries = new TreeNode();
TreeNode nodeStudat = new TreeNode();
//
int tmpStudat = 0;
int patBirdat = 0;
string patName = string.Empty;
//
DcmObject doRoot = (DcmObject)ds;
IEnumerator enuRoot = doRoot.GetEnumerator();
int count = 0;
while (enuRoot.MoveNext())
{
DcmElement elRoot = (DcmElement)enuRoot.Current;
if (elRoot.HasItems())
{
for (int i = 0; i < elRoot.vm(); i++)
{
DcmObject dcmObj = (DcmObject)elRoot.GetItem(i);
IEnumerator enu = dcmObj.GetEnumerator();
while (enu.MoveNext())
{
DcmElement el = (DcmElement)enu.Current;
if (el.tag() == DcmTags.DirectoryRecordType)
{
string rs = el.GetString(Encoding.Unicode);
if (rs == "PATIENT")
{
PatientTable pt = new PatientTable();
if (dcmObj.Contains(Tags.PatientBirthDate))
patBirdat = Convert.ToInt32(dcmObj.GetDate(DcmTags.PatientBirthDate).ToString("yyyyMMdd"));
if (dcmObj.Contains(Tags.PatientName))
patName = dcmObj.GetString(DcmTags.PatientName);
}
else if (rs == "STUDY")
{
if (dcmObj.Contains(DcmTags.StudyDate))
{
int studat = Convert.ToInt32(dcmObj.GetDate(Tags.StudyDate).ToString("yyyyMMdd"));
string stuinsuid = string.Empty;
string studes = string.Empty;
if (dcmObj.Contains(DcmTags.StudyInstanceUID))
stuinsuid = dcmObj.GetString(DcmTags.StudyInstanceUID);
if (dcmObj.Contains(DcmTags.StudyDescription))
studes = dcmObj.GetString(DcmTags.StudyInstanceUID);
if (studat != tmpStudat)
{
nodeStudat = new TreeNode(studat.ToString("####/##/##"));
nodeStudat.Tag = studat;
treeViewStudy.Nodes.Add(nodeStudat);
tmpStudat = studat;
}
nodeStudy = new TreeNode("");
nodeStudat.Nodes.Add(nodeStudy);
}
}
else if (rs == "SERIES")
{
imageList = new List<string[]>();
string serinsuid = string.Empty;
string sernum = string.Empty; ;
string numserrelima = string.Empty;
string serdes = string.Empty;
string bodparexa = string.Empty;
string modality = string.Empty;
if (dcmObj.Contains(DcmTags.SeriesInstanceUID))
serinsuid = dcmObj.GetString(DcmTags.SeriesInstanceUID);
if (dcmObj.Contains(DcmTags.SeriesNumber))
sernum = dcmObj.GetString(DcmTags.SeriesNumber);
if (dcmObj.Contains(DcmTags.SeriesDescription))
serdes = dcmObj.GetString(DcmTags.SeriesDescription);
if (dcmObj.Contains(DcmTags.Modality))
modality = dcmObj.GetString(DcmTags.Modality);
nodeSeries = new TreeNode(modality + "." + sernum);
nodeStudy.Nodes.Add(nodeSeries);
if (nodeStudy.Text == string.Empty)
nodeStudy.Text = modality;
nodeSeries.Tag=imageList; //Add (refFile and uid)List
}
else if (rs == "IMAGE")
{
string refFileID = string.Empty;
string uid = string.Empty;
if (dcmObj.Contains(DcmTags.RefFileID))
refFileID = dcmObj.GetString(DcmTags.RefFileID);
if (dcmObj.Contains(DcmTags.RefSOPInstanceUIDInFile))
uid = dcmObj.GetString(DcmTags.RefSOPInstanceUIDInFile);
string[] ss = new string[2];
ss[0] = refFileID;
ss[1] = uid;
imageList.Add(ss);
}
}
}
}
}
}

2011年5月24日火曜日

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

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

参照設定
using org.dicomcs.dict;
using org.dicomcs.data;
using org.dicomcs.net;
using org.dicomcs.util;
using log4net;


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

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

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

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;

}