Home | Course Index |
Course DICis: The DICOM Medical Image Format
|
|
Let me know what you think |
Projekt tag1 Dump and Tag Search Weitere Aufgaben |
Diese Übung liest beim Programmstart automatisch eine Textdatei C:\temp\dicom.dic mit dem vollständigen und aktuellen DICOM Dictionary 2001 (bis supplement 59). Jede Zeile der Datei enthält einen Eintrag mit 5 Feldern: Tag, VR, Name, VM, Version. Die letzten 2 Felder werden von tags1 ignoriert und abgeschnitten.
Man kann nunmehr unbekannte Dateien jeder Art einlesen. Das Programm listet maximal 16x16 Bytes in 3 parallelen Typkonvertierungen: Bytes hexadezimal, 16-Bit-Integer und Character.
Falls es sich um Dicom-Bilder handelt, listet es sämtliche Felder des DICOM Headers. Das Programm nimmt schlicht an, dass das erste Wort und das zweite Wort der Datei die beiden Teile eines gültigen DICOM-Tags sind und dass das dann folgende 32-Bit-Wort den Dezimalwert der Länge des ersten Eintrags enthält. Falls diese Länge kürzer als die verbleibende Dateilänge ist, werden die ersten 48 Byte des Feldinhalts als String ausgegeben. Der Dateioffset wird um die Feldlänge inkrementiert und der Vorgang setzt sich fort bis zum Dateiende.
Falls es sich um gültige DICOM-Tags handelt, interpretiert das Programm deren Bedeutung an Hand des DICOM dictionary und konvertiert DICOM-Felder vom DICOM-Typ kurze Integer (US, SS) und lange Integer (UL, SL) in Strings und zeigt diese an.
Wichtig: DICOM Dictionary ASCII-Textdatei hier laden: dicom.dic 86 kB und nach C:\temp\dicom.dic kopieren !
Vorschlag: Kopieren Sie folgende Bilder in eine neue Directory C:\temp\Images.
Beispielbild: Ultrasound 303 kB
Beispielbild: Ultrasound 303 kB
Beispielbild: NMR 137 kB
Beispielbild: CT 514 kB
Beispielbild: Uro 570 kB
Microsoft Visual Studio.NET starten
File New Project Project Types: Visual C# Projects, Templates: Windows Application
Name: tag1
Location: C:\temp
Button OK unten Mitte klicken.
Klicken Sie mit der rechten Maustaste auf des Innere von Form1.
Es öffnet sich ein kleines Kontextmenü. Klicken Sie auf View Code.
Sie sehen jetzt den vorprogrammierten Code von Visual Studio. Löschen Sie den gesamten Code vollständig.
Schreiben Sie in das leere Fenster folgenden Code:
using System; using System.Drawing; using System.Windows.Forms; using System.IO; using System.Text; public class Form1 : Form { byte[] mybuffer;//space for Dicom file String dic; //space for dictionary filie String DicText; //Dicom dictionary additional text; StringBuilder s = new StringBuilder(); TextBox TB = new TextBox(); [STAThread] static void Main() { Application.Run( new Form1() ) ; } public Form1() { Text = "DicomHeader"; MenuItem miOpen = new MenuItem("&Open", new EventHandler( MenuFileOpenOnClick ) ); MenuItem miExit = new MenuItem("&Exit", new EventHandler( MenuFileExitOnClick ) ); MenuItem miFile = new MenuItem("&File", new MenuItem[] { miOpen, miExit } ); Menu = new MainMenu( new MenuItem[] { miFile } ); ClientSize = TB.Size = new Size( 800, 800 ); TB.Font = new Font( "Courier New", 8 ); TB.Multiline = true; TB.WordWrap = false; TB.ScrollBars = ScrollBars.Both; Controls.Add( TB ); try { StreamReader sr = new StreamReader( "C:\\temp\\dicom.dic" ); dic = sr.ReadToEnd(); sr.Close(); } catch { MessageBox.Show( "Cannot find C:\\temp\\dicom.dic." ); } } void MenuFileOpenOnClick( object obj, EventArgs ea ) { OpenFileDialog dlg = new OpenFileDialog(); if ( dlg.ShowDialog() == DialogResult.OK ) { FileStream fs = new FileStream( dlg.FileName, FileMode.Open, FileAccess.Read ); mybuffer = new Byte[fs.Length]; fs.Read( mybuffer, 0, (int)fs.Length ); DumpIt(); } } void MenuFileExitOnClick( object obj, EventArgs ea ) { Close(); } private void DumpIt() { s.Length = 0; int x, y; for ( y=0; y < 64; y++ ) // print 64 lines { for ( x=0; x < 16; x++ ) // 16 bytes as hexadecimals in each line s.Append( String.Format( "{0:X2} ", mybuffer[y*16+x] ) ); s.Append( " " ); for ( x=0; x < 16; x+=2 ) // 16 bytes as 8 Int16 in each line { int figure = mybuffer[y*16+x] + 16*mybuffer[y*16+x+1]; s.Append( String.Format( "{0:D4} ", figure ) ); } s.Append( " " ); for ( x=0; x < 16; x++ ) // 16 bytes as 16 characters in each line { char c = Convert.ToChar( mybuffer[y*16+x] ); if ( Char.IsControl(c) ) s.Append( "." ); else s.Append( c.ToString() ); } s.Append( "\r\n" ); } s.Append( "\r\n" ); int i, bytecount = 0; do { int tlen1 = (int)mybuffer[bytecount++]; int tlen2 = (int)mybuffer[bytecount++]; int tlen3 = (int)mybuffer[bytecount++]; int tlen4 = (int)mybuffer[bytecount++]; String tag = String.Format ("({0:X4},{1:X4})", tlen1 + 256*tlen2, tlen3 + 256*tlen4 ); int halftag = tlen1 + 256*tlen2; tlen1 = (int)mybuffer[bytecount++]; tlen2 = (int)mybuffer[bytecount++]; tlen3 = (int)mybuffer[bytecount++]; tlen4 = (int)mybuffer[bytecount++]; int tlen = tlen1 + 256*tlen2 + 256*256*tlen3 + 256*256*256*tlen4; s.Append( tag + ' ' + String.Format("{0:D8} ", tlen ) + " " ); //output the first 48 bytes of any arbitrary content for ( i=0; i < Math.Min( tlen, 48 ); i++ ) { char c = Convert.ToChar( mybuffer[bytecount + i] ); if ( Char.IsControl( c ) ) s.Append( '.' ); else s.Append( c.ToString() ); } for ( ; i < 48; i++ ) s.Append( ' ' ); String VR = FindTagInDictionary( tag ); //function: look into the dictionary String Value = GetValue( VR, bytecount ); //function: get US, SS, UL, SL data types s.Append( ' ' + VR + Value + "\r\n" ); bytecount += tlen; } while ( bytecount < mybuffer.Length ); TB.Text = s.ToString(); Invalidate(); } private String FindTagInDictionary( String tag ) { //uneven tags are never listed in the dictionary if ( Convert.ToInt16( tag[4] ) % 2 != 0 ) return "?? PrivateTag"; int n1, n2, n3, n4; n1 = dic.IndexOf( tag ); //find the even tag in the dictionary if ( n1 < 0 ) return String.Empty; //not found int i = 11; // jump over the tag in order to search for the following tag do n2 = dic.IndexOf( '(', n1 + i++ );//leading clause ? while ( dic[n2+5] != ',' || dic[n2+10] != ')' );//middle comma and end clause ? if ( n2 < 0 ) n2 = n1 + 13; //there is no following tag, supress the rest DicText = dic.Substring( n1, n2-n1 );//cut out one line from the dictionary DicText = DicText.Substring( 12, DicText.Length-12 );//cut off anything in front of VR String VR = DicText.Substring( 0, 2 );//2 bytes of the value representation n3 = DicText.IndexOf( '\t', 0 ); //1. tab inside the dictionary line n4 = DicText.IndexOf( '\t', n3+1 );//2. tab String Description = DicText.Substring( n3+1, n4-n3 );//Cut out between tabs return VR + ' ' + Description; } private String GetValue( String VR, int bytecount ) //This function extracts values from Dicom header tags carrying decimal data of type: //unsigned short, signed short, unsigned long, signed long. { if ( VR.Length < 2 || bytecount <= 0 ) return String.Empty; //bad parameter if ( VR[0] == '?' ) return String.Empty; //private tag if ( VR[0] == 'U' && VR[1] == 'S' || VR[0] == 'S' && VR[1] == 'S' )//16-bit integers ? { int number = (int)mybuffer[bytecount ] + 256*(int)mybuffer[bytecount+1]; return( " = " + String.Format("{0}", number ) ); } if ( VR[0] == 'U' && VR[1] == 'L' || VR[0] == 'S' && VR[1] == 'L' )//32-bit integers ? { int number = (int)mybuffer[bytecount ] + 256*(int)mybuffer[bytecount+1] + 256*256*(int)mybuffer[bytecount+2] + 256*256*256*(int)mybuffer[bytecount+3]; return( " = " + String.Format("{0}", number ) ); } return String.Empty; } }
Übersetzen, linken und starten Sie mit Start Without Debugging Ctrl F5.
Falls eine Fehlermeldung erscheint, steht C:\temp\dicom.dic nicht an der richtigen Stelle. Holen Sie das nach und erproben Sie tags1 erneut.
Besuchen Sie den Link: http://medical.nema.org/dicom/2001/01_05PU.PDF und lesen Sie Kapitel 6.2 ab Seite 21.
Besuchen Sie den Link: http://medical.nema.org/dicom/2001/01_06PU.PDF und lesen Sie Kapitel 3.3 ab Seite 6.
Laden Sie C:\temp\dicom.dic mit Hilfe von TextPad und studieren Sie den Inhalt.
Klicken sie auf help in der Menüleiste von VS.NET und suchen sie Information zu den ihnen unbekannten Sprachelementen.
Beenden sie VS.NET, starten sie den Explorer, löschen sie die gesamte Directory c:\temp\tags1
Erfinden und erproben sie neue Varianten des Programms (in Form von neuen Projekten tags2, tags3 usw. nach obigem Muster).
top of page: |