IMHOTEP Framework
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Pages
DICOM2D.cs
1 using System;
2 using System.Runtime.InteropServices;
3 using UnityEngine;
4 using itk.simple;
5 using System.Collections.Generic;
6 
8 public class DICOM2D : DICOM
9 {
11  public int slice { private set; get; }
12 
14  public Color32[] colors;
15 
18  private Texture2D texture2D;
19 
28  public SliceOrientation sliceOrientation { private set; get; }
29 
30  public DICOM2D( DICOMSeries seriesInfo, int slice ) : base( seriesInfo )
31  {
32  dimensions = 2;
33  slice = Mathf.Clamp (slice, 0, seriesInfo.filenames.Count - 1);
34  this.slice = slice;
35 
36  VectorString fileNames = seriesInfo.filenames;
37 
38  // Read the DICOM image:
39  image = SimpleITK.ReadImage( fileNames[slice] );
40  loadImageData (image);
41 
42  VectorDouble o1 = image.GetOrigin();
43  if ( o1.Count < 3) {
44  throw( new System.Exception ("Invalid origins found in first image."));
45  }
46  origin = new Vector3 ((float)o1 [0], (float)o1 [1], (float)o1 [2]);
47 
48  // Load the direction cosines:
49  // ITK stores the direction cosines in a matrix with row-major-ordering. The weird indexing is because
50  // we need the first and second column (0,3,6 for X and 1,4,7 for Y)
51  VectorDouble direction = image.GetDirection();
52  if( direction.Count < 6 )
53  throw( new System.Exception ("Invalid direction cosines found in images."));
54  directionCosineX = new Vector3 ((float)direction [0], (float)direction [3], (float)direction [6]);
55  directionCosineY = new Vector3 ((float)direction [1], (float)direction [4], (float)direction [7]);
56 
58 
59  // Calculate which direction the normal is facing to determine the orienation (Transverse,
60  // Coronal or Saggital).
61  float absX = Mathf.Abs (sliceNormal.x);
62  float absY = Mathf.Abs (sliceNormal.y);
63  float absZ = Mathf.Abs (sliceNormal.z);
64  if (absX > absY && absX > absZ) {
65  sliceOrientation = SliceOrientation.Saggital;
66  } else if (absY > absX && absY > absZ) {
67  sliceOrientation = SliceOrientation.Coronal;
68  } else if (absZ > absX && absZ > absY) {
69  sliceOrientation = SliceOrientation.Transverse;
70  } else {
71  sliceOrientation = SliceOrientation.Unknown;
72  }
73 
74  // Load the pixel spacing:
75  // NOTE: It seems that the the first value is the spacing between rows (i.e. y direction),
76  // the second value is the spacing between columns (i.e. x direction).
77  // I was not able to verify this so far, since all test dicoms we had have the same spacing in
78  // x and y direction...
79  VectorDouble spacing = image.GetSpacing();
80  if( spacing.Count < 2 )
81  throw( new System.Exception ("Invalid pixel spacing found in images."));
82  pixelSpacing = new Vector2 ((float)spacing [1], (float)spacing [0] );
83 
84  // Generate the transformation matrices which can later be used to translate pixels to
85  // 3D positions and vice versa.
87  }
88 
89 
92  private void loadImageData( Image image )
93  {
94 
95  origTexWidth = (int)image.GetWidth ();
96  origTexHeight = (int)image.GetHeight ();
97  origTexDepth = 1;
98  texWidth = Mathf.NextPowerOfTwo ((int)image.GetWidth ());
99  texHeight = Mathf.NextPowerOfTwo ((int)image.GetHeight ());
100  texDepth = 1;
101  texPaddingWidth = texWidth - origTexWidth;
102  texPaddingHeight = texHeight - origTexHeight;
103  texPaddingDepth = texDepth - origTexDepth;
104  colors = new Color32[ texWidth * texHeight ];
105 
106  /*int intercept = 0;
107  int slope = 1;
108  try {
109  intercept = Int32.Parse( image.GetMetaData("0028|1052") );
110  slope = Int32.Parse( image.GetMetaData("0028|1053") );
111  } catch {
112  }*/
113 
114  if (image.GetDimension () != 2 && image.GetDimension () != 3)
115  {
116  throw( new System.Exception( "Only 2D and 3D images are currently supported. Dimensions of image: " + image.GetDimension()));
117  }
118 
119  Debug.Log ("DICOM Pixel format: " + image.GetPixelID ());
120 
121  UInt32 min = UInt32.MaxValue;
122  UInt32 max = UInt32.MinValue;
123 
124  // Copy the image into a colors array:
125  if (image.GetPixelID () == PixelIDValueEnum.sitkUInt16) {
126  IntPtr bufferPtr = image.GetBufferAsUInt16 ();
127 
128  unsafe {
129  UInt16 *ptr = (UInt16 *)bufferPtr.ToPointer();
130 
131  int consecutiveIndex = 0;
132  //for (UInt32 z = 0; z < texDepth; z++) {
133  for (UInt32 y = 0; y < texHeight; y++) {
134  for (UInt32 x = 0; x < texWidth; x++) {
135  if (x < origTexWidth && y < origTexHeight) {// && z < origTexDepth )
136  long jumpingIndex = x + y * texWidth;
137 
138  UInt32 pixelValue = (UInt32)((UInt16)ptr[consecutiveIndex]);
139  colors [jumpingIndex] = F2C (pixelValue);
140 
141  if (pixelValue > max)
142  max = pixelValue;
143  if (pixelValue < min)
144  min = pixelValue;
145 
146  consecutiveIndex++;
147  }
148  }
149  }
150  }
151  } else if ( image.GetPixelID() == PixelIDValueEnum.sitkInt16 ) {
152  IntPtr bufferPtr = image.GetBufferAsInt16 ();
153 
154  unsafe {
155  Int16 *ptr = (Int16 *)bufferPtr.ToPointer();
156 
157  int consecutiveIndex = 0;
158  //for (UInt32 z = 0; z < texDepth; z++) {
159  for (UInt32 y = 0; y < texHeight; y++) {
160  for (UInt32 x = 0; x < texWidth; x++) {
161  if (x < origTexWidth && y < origTexHeight) {// && z < origTexDepth )
162  long jumpingIndex = x + y * texWidth;
163 
164  UInt32 pixelValue = (UInt32)((Int16)ptr[consecutiveIndex] + Int16.MaxValue);
165  colors [jumpingIndex] = F2C (pixelValue);
166 
167  if (pixelValue > max)
168  max = pixelValue;
169  if (pixelValue < min)
170  min = pixelValue;
171 
172  consecutiveIndex++;
173  }
174  }
175  }
176  }
177  } else if ( image.GetPixelID() == PixelIDValueEnum.sitkInt32 ) {
178  IntPtr bufferPtr = image.GetBufferAsInt32 ();
179 
180  unsafe {
181  Int32 *ptr = (Int32 *)bufferPtr.ToPointer();
182 
183  int consecutiveIndex = 0;
184  //for (UInt32 z = 0; z < texDepth; z++) {
185  for (UInt32 y = 0; y < texHeight; y++) {
186  for (UInt32 x = 0; x < texWidth; x++) {
187  if (x < origTexWidth && y < origTexHeight) {// && z < origTexDepth )
188  long jumpingIndex = x + y * texWidth;
189 
190  // TODO: To move from Int32 to UInt32 range, we should add Int32.MaxValue?!
191  // However, when we do this,
192  UInt32 pixelValue = (UInt32)((Int32)ptr[consecutiveIndex]) + (UInt32)Int16.MaxValue;
193  colors [jumpingIndex] = F2C (pixelValue);
194 
195  if (pixelValue > max)
196  max = pixelValue;
197  if (pixelValue < min)
198  min = pixelValue;
199 
200  consecutiveIndex++;
201  }
202  }
203  }
204  }
205  } else {
206  throw(new System.Exception ("Unsupported pixel format: " + image.GetPixelID()));
207  }
208 
209  seriesInfo.setMinMaxPixelValues (min, max);
210  // Make the loaded image accessable from elsewhere:
211  this.image = image;
212  }
213 
214 
217  public Texture2D getTexture2D()
218  {
219  if (texture2D != null)
220  return texture2D;
221 
222  if (dimensions != 2) {
223  throw(new System.Exception ("Trying to get Texture2D from a DICOM which has " + dimensions + " dimensions!"));
224  }
225 
226  texture2D = new Texture2D (texWidth, texHeight, TextureFormat.ARGB32, false, true);
227  texture2D.SetPixels32 (colors);
228  texture2D.Apply ();
229 
230  // Clear no longer needed data:
231  colors = null;
232 
233  return texture2D;
234  }
235 }
236 
int texPaddingDepth
Definition: DICOM.cs:35
Vector2 pixelSpacing
Definition: DICOM.cs:47
Vector3 directionCosineY
Definition: DICOM.cs:63
Vector3 directionCosineX
Definition: DICOM.cs:57
Vector3 origin
Definition: DICOM.cs:45
int slice
Definition: DICOM2D.cs:11
int origTexDepth
Definition: DICOM.cs:28
int origTexWidth
Definition: DICOM.cs:24
Image image
Definition: DICOM.cs:42
Vector3 sliceNormal
Definition: DICOM.cs:66
Definition: DICOM.cs:8
Color32[] colors
Definition: DICOM2D.cs:14
int texPaddingWidth
Definition: DICOM.cs:31
int texPaddingHeight
Definition: DICOM.cs:33
Texture2D getTexture2D()
Definition: DICOM2D.cs:217
int origTexHeight
Definition: DICOM.cs:26
void setupTransformationMatrices()
Definition: DICOM.cs:98
static Color32 F2C(UInt32 value)
Definition: DICOM.cs:173
int dimensions
Definition: DICOM.cs:18
DICOMSeries seriesInfo
Definition: DICOM.cs:13
SliceOrientation sliceOrientation
Definition: DICOM2D.cs:28