2015年8月28日金曜日

GDCM memo

Find Scu

PatID>>StudyInstansUID>>SeriesInstanceUID>>SOPInstanceUID
患者番号からSOPInstanceUIDを抽出

ushort port = 11112;
string aetcalled = "DCM4CHEE";
string aetcalling = "any";
string host = "192.168.0.1";
//Patient Number
string patId="123";
//Study Level
gdcm.PresentationContextGenerator generator = new PresentationContextGenerator();
gdcm.KeyValuePairArrayType theTagPair = new KeyValuePairArrayType();
theTagPair.Add(new KeyValuePairType(new gdcm.Tag(0x0010, 0x0020), patId));
theTagPair.Add(new KeyValuePairType(new gdcm.Tag(0x0010, 0x0010), "*"));    //Name
theTagPair.Add(new KeyValuePairType(new gdcm.Tag(0x0010, 0x0030), "*"));    //Birthday
theTagPair.Add(new KeyValuePairType(new gdcm.Tag(0x0010, 0x0040), "*"));    //Sex
theTagPair.Add(new KeyValuePairType(new gdcm.Tag(0x0020, 0x000D), "*"));    //StudyInstanceUID
theTagPair.Add(new KeyValuePairType(new gdcm.Tag(0x0008, 0x0050), "*"));    //AccessionNumber
var query = gdcm.CompositeNetworkFunctions.ConstructQuery(gdcm.ERootType.ePatientRootType,
    gdcm.EQueryLevel.eStudy, theTagPair);
var ret = new DataSetArrayType();
bool b = gdcm.CompositeNetworkFunctions.CFind(host, port, query, ret, aetcalling, aetcalled);
List studyInsUidList = new List();
for (int i = 0; i < ret.Count; i++)
{
    var ds = ret[i];
    Console.WriteLine("StudyInsUid:" + ds.GetDataElement(new gdcm.Tag(0x0020, 0x000D)).GetValue().toString());
    studyInsUidList.Add(ds.GetDataElement(new gdcm.Tag(0x0020, 0x000D)).GetValue().toString());
}
//Series Level
string studyInsUid = studyInsUidList[0].Trim(); //Select First Series                 
theTagPair = new KeyValuePairArrayType();
theTagPair.Add(new KeyValuePairType(new gdcm.Tag(0x0020, 0x000D), studyInsUid));    //StudyInstanceUID
theTagPair.Add(new KeyValuePairType(new gdcm.Tag(0x0020, 0x000E), "*"));            //SeriesInstanceUID
theTagPair.Add(new KeyValuePairType(new gdcm.Tag(0x0008, 0x0060), "*"));            //Modality
theTagPair.Add(new KeyValuePairType(new gdcm.Tag(0x0020, 0x0011), "*"));            //SeriesNumber
query = gdcm.CompositeNetworkFunctions.ConstructQuery(gdcm.ERootType.eStudyRootType,
    gdcm.EQueryLevel.eSeries, theTagPair);
ret = new DataSetArrayType();
gdcm.CompositeNetworkFunctions.CFind(host, port, query, ret, aetcalling, aetcalled);
List seriesInsUidList = new List();
for (int i = 0; i < ret.Count; i++)
{
    var ds = ret[i];
    Console.WriteLine("SeriesInsUid:" + ds.GetDataElement(new gdcm.Tag(0x0020, 0x000E)).GetValue().toString());
    seriesInsUidList.Add(ds.GetDataElement(new gdcm.Tag(0x0020, 0x000E)).GetValue().toString());
}
//Image Level
string seriesInsUid = seriesInsUidList[0].Trim(); //Select First Series                 
theTagPair = new KeyValuePairArrayType();
theTagPair.Add(new KeyValuePairType(new gdcm.Tag(0x0020, 0x000E), seriesInsUid));   //SeriesInstanceUID
theTagPair.Add(new KeyValuePairType(new gdcm.Tag(0x0020, 0x0013), "*"));            //InstanceNumber
theTagPair.Add(new KeyValuePairType(new gdcm.Tag(0x0008, 0x0018), "*"));            //SOPInstanceUID
query = gdcm.CompositeNetworkFunctions.ConstructQuery(gdcm.ERootType.eStudyRootType,
    gdcm.EQueryLevel.eImage, theTagPair);
ret = new DataSetArrayType();
gdcm.CompositeNetworkFunctions.CFind(host, port, query, ret, aetcalling, aetcalled);

for (int i = 0; i < ret.Count; i++)
{
    var ds = ret[i];
    Console.WriteLine("SopInsUid:" + ds.GetDataElement(new gdcm.Tag(0x0008, 0x0018)).GetValue().toString());
}

2015年8月22日土曜日

GDCM memo / send scu

 
var dir = new System.IO.DirectoryInfo(@"c:\dicom");
var filesInfo = dir.GetFiles("*.dcm");
//
var scu = new gdcm.ServiceClassUser();
scu.SetHostname("host");
scu.SetPort((ushort)11112);
scu.SetCalledAETitle("DCM4CHEE");
scu.SetAETitle("any");
scu.SetTimeout(2000);
if (!scu.InitializeConnection())
{ Console.WriteLine("Err :suc initialize connection"); return; }
var ft = new gdcm.FilenamesType();
foreach (FileInfo fi in filesInfo)
    ft.Add(fi.FullName);
var g = new gdcm.PresentationContextGenerator();
g.GenerateFromFilenames(ft);
scu.SetPresentationContexts(g.GetPresentationContexts());
if (!scu.StartAssociation())
{ Console.WriteLine(": suc Start Association"); return; }
foreach (FileInfo fi in filesInfo)
{
    if (!scu.SendStore(fi.FullName))
    { 
        Console.WriteLine("Err: Send scu[" +  fi.FullName +"]");
        break;
    }
                
}
if (!scu.StopAssociation())
{ Console.WriteLine("\r\nErr: suc Stop Association\n"); return; }
Console.WriteLine("\r\nEnd");
scu.Dispose();
g.Dispose();
ft.Dispose();

2015年8月11日火曜日

GDCM 覚書2 YBR_FULL_422

GDCM memo 2

YBR_FULL_422の画像

string photometricInterpretation = ds.GetDataElement(new gdcm.Tag(0x00280004)).GetValue().toString();
byte* pBmpData = (byte*)_bmpData.Scan0;
if (photometricInterpretation == "YBR_FULL_422")
{
    fixed (byte* pData = _pixelData)
    {
        byte* ybr = pData;
        for (int y = 0; y < _rows; y++)
        {
            for (int x = 0; x < _columns; x++)
            {
                int Y = ybr[0] - 16;
                int Cb = ybr[1] - 128;
                int Cr = ybr[2] - 128;
                int r = ((298 * Y + 409 * Cr + 128) / 256);
                int g = ((298 * Y - 100 * Cb - 208 * Cr + 128) / 256);
                int b = ((298 * Y + 516 * Cb + 128) / 256);
                pBmpData[2] = (byte)(r < 0 ? 0 : (r > 255 ? 255 : r));
                pBmpData[1] = (byte)(g < 0 ? 0 : (g > 255 ? 255 : g));
                pBmpData[0] = (byte)(b < 0 ? 0 : (b > 255 ? 255 : b));
                pBmpData += 3;
                ybr += 3;
            }
            pBmpData += padding;
        }
    }
}

2015年8月4日火曜日

GDCM 覚書

GDCM (Grassroots DICOM) memo memo

c#用wrapperの gdcmの覚書。

gdcm-2.4.4 の作成には cmakeはver2.8.9(cmake-2.8.9-win32-x86.zip), swigはver2.0.12(swigwin-2.0.12.zip)を使用しました。 swin3.0以降は不可のようです。
swigwinは実行ファイルのある場所にpathを切っておきます。

1. MONOCHROME2, シングルフレームのbitmap画像

            
//MONOCHROME2,シングルフレーム Dicom Image
var sw = new System.Diagnostics.Stopwatch(); 
sw.Start();
string fileName = @"chest.dcm";
// 
var ir = new ImageReader();
ir.SetFileName(fileName);
if (!ir.Read()){
    Console.WriteLine("Err: ImageReader "); 
    return;
}
gdcm.File file = ir.GetFile();          
gdcm.DataSet ds = file.GetDataSet();        //DataSetの取得
gdcm.Image image = ir.GetImage();           //Imageの取得
byte[] imgBuf = new byte[(int)image.GetBufferLength()];
image.GetBuffer(imgBuf);                    //Image bufferの取得
uint dims = image.GetNumberOfDimensions();  //ここではマルチフレームは未対応とする
if (dims == 3) { 
    Console.WriteLine("Err: マルチフレーム未対応"); return;
}
//
if (image.GetPhotometricInterpretation().GetType() == gdcm.PhotometricInterpretation.PIType.RGB) { 
    Console.WriteLine("Err: PhotometricInterpretation is RGB"); return;
}
if (image.GetPhotometricInterpretation().GetType() != gdcm.PhotometricInterpretation.PIType.MONOCHROME2)  {
    Console.WriteLine("Err: PhotometricInterpretation is not MONOCHROME2"); return;
}
//8bpp用のpaletteを作成しておく
var b = new System.Drawing.Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
var GrayscalePalette = b.Palette;
for (int i = 0; i < 256; i++)
    GrayscalePalette.Entries[i] = System.Drawing.Color.FromArgb(i, i, i);
//bitmapの作成とpaletteを設定
//
int wc,ww;
if (!ds.FindDataElement(new gdcm.Tag(0x00281050))){
    Console.WriteLine("Err: Window Center値がありません"); return;
}
if (!ds.FindDataElement(new gdcm.Tag(0x00281051))){
    Console.WriteLine("Err: Window Width値がありません"); return;
 }
if (ds.FindDataElement(new gdcm.Tag(0x00281052))){
    Console.WriteLine("Err: RescaleInterception未サポート"); return;
}
wc = Convert.ToInt32(Convert.ToDouble(ds.GetDataElement(new gdcm.Tag(0x00281050)).GetValue().toString()));
ww = Convert.ToInt32(Convert.ToDouble(ds.GetDataElement(new gdcm.Tag(0x00281051)).GetValue().toString()));
int max, min = 0;
double invww = 0d;
max = wc + (int)((double)ww * 0.5d);
min = wc - (int)((double)ww * 0.5d);
ushort max1 = (ushort)max;
ushort min1 = (ushort)min;
invww = 255.0d / (double)ww;
//MONOCHROME2 image
var bitmap = new System.Drawing.Bitmap((int)image.GetColumns(), (int)image.GetRows(), System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
bitmap.Palette = GrayscalePalette;
var bmpData = bitmap.LockBits(new Rectangle(0, 0, (int)image.GetColumns(), (int)image.GetRows()), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
int padding = bmpData.Stride - bmpData.Width;
unsafe
{
    fixed (byte* pBuf = imgBuf)
    {
        byte* pBmpData = (byte*)bmpData.Scan0;
        //PixelRepresentation(0x00280103)=1の場合
    //short* ptr = (short*)pBuf;
        //PixelRepresentation=なし,あるいは0の場合
        ushort* ptr = (ushort*)pBuf;
        int stride = bmpData.Stride;
        int pixel;
        for (int y = 0; y < bmpData.Height; y++)
        {
            for (int x = 0; x < bmpData.Width; x++)
            {
                int xy = *ptr++;
                pixel = xy  = min ? 0 : (xy >= max ? 255 : (int)((xy - min) * invww));  //16bit image to 8bit image
                //MONOCROME1 背景白
                //pixel = xy = min ? 255 : (xy = max ? 0 : 255 - (int)((xy - min) * invWW));  
                *pBmpData = (byte)pixel;
                pBmpData++;
            }
            pBmpData += padding;
        }
            bitmap.UnlockBits(bmpData);
    }
}
if (bitmap != null)
    pictureBox1.Image = bitmap;
sw.Stop(); 
Console.WriteLine(sw.ElapsedMilliseconds +" msec");

2. MONOCHROME2, マルチフレームの場合は次のようになります

uint k = image.GetNumberOfDimensions();
uint frames = 0;
if(k==3)
    frames = image.GetDimension(2);
var bitmaps = new System.Drawing.Bitmap[(int)frames];
unsafe
{
    fixed (byte* src = imgBuf)
    {
        for (uint i = 0; i < frames; i++)
        {
            var bitmap = new System.Drawing.Bitmap((int)image.GetColumns(), (int)image.GetRows(), System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
            bitmap.Palette = GrayscalePalette;
            var bmpData = bitmap.LockBits(new Rectangle(0, 0, (int)image.GetColumns(), (int)image.GetRows()), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
            int padding = bmpData.Stride - bmpData.Width;
            byte* pBmpData = (byte*)bmpData.Scan0;
            ushort* ptr = (ushort*)src;
            int stride = bmpData.Stride;
            int pixel;
            for (int y = 0; y < bmpData.Height; y++)
            {
                for (int x = 0; x < bmpData.Width; x++)
                {
                    int xy = *ptr++;
                    pixel = xy <= min ? 0 : (xy >= max ? 255 : (int)((xy - min) * invww));
                    *pBmpData = (byte)pixel;
                    pBmpData++;
                }
                pBmpData += padding;
            }
            bitmap.UnlockBits(bmpData);
            bitmaps[i] = bitmap;
       }
    }
}