CustusX  15.8
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxDicomImageReader.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 #include "cxDicomImageReader.h"
34 
35 #include "cxVolumeHelpers.h"
36 #include "dcvrpn.h"
37 #include "cxLogger.h"
38 
39 namespace cx
40 {
41 
43 {
45  if (retval->loadFile(filename))
46  return retval;
47  else
48  return DicomImageReaderPtr();
49 }
50 
51 DicomImageReader::DicomImageReader() :
52  mDataset(NULL)
53 {
54 }
55 
56 bool DicomImageReader::loadFile(QString filename)
57 {
58  mFilename = filename;
59  OFCondition status = mFileFormat.loadFile(filename.toLatin1().data());
60  if( !status.good() )
61  {
62  return false;
63  }
64 
65  mDataset = mFileFormat.getDataset();
66  return true;
67 }
68 
70 {
71  return this->wrapInCTK(mDataset);
72 }
73 
74 double DicomImageReader::getDouble(const DcmTagKey& tag, const unsigned long pos, const OFBool searchIntoSub) const
75 {
76  double retval = 0;
77  OFCondition condition;
78  condition = mDataset->findAndGetFloat64(tag, retval, pos, searchIntoSub);
79  if (!condition.good())
80  {
81  QString tagName = this->item()->TagDescription(tag);
82  this->error(QString("Failed to get tag %1/%2").arg(tagName).arg(pos));
83  }
84  return retval;
85 }
86 
88 {
89  WindowLevel retval;
90  retval.center = this->getDouble(DCM_WindowCenter, 0, OFTrue);
91  retval.width = this->getDouble(DCM_WindowWidth, 0, OFTrue);
92  return retval;
93 }
94 
96 {
97  //DICOM standard PS3.3 section C.7.6.1.1.2 Image Type
98  //http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.7.6.1.1.2
99  bool retval = false;
100 
101  OFCondition condition;
102  OFString value;
103  condition = mDataset->findAndGetOFString(DCM_ImageType, value, 2, OFTrue);
104  if (condition.good())
105  {
106  QString imageSpesialization(value.c_str());
107  if (imageSpesialization.compare("LOCALIZER", Qt::CaseSensitive) == 0)
108  retval = true;
109  }
110  return retval;
111 }
112 
114 {
115  int numberOfFrames = this->item()->GetElementAsInteger(DCM_NumberOfFrames);
116  if (numberOfFrames==0)
117  {
118  unsigned short rows = 0;
119  unsigned short columns = 0;
120  mDataset->findAndGetUint16(DCM_Rows, rows, 0, OFTrue);
121  mDataset->findAndGetUint16(DCM_Columns, columns, 0, OFTrue);
122  if (rows*columns > 0)
123  numberOfFrames = 1; // seems like we have a 2D image
124  }
125  return numberOfFrames;
126 }
127 
129 {
130  Vector3D pos;
131  Vector3D e_x;
132  Vector3D e_y;
133 
134  for (int i=0; i<3; ++i)
135  {
136  OFCondition condition;
137  e_x[i] = this->getDouble(DCM_ImageOrientationPatient, i, OFTrue);
138  e_y[i] = this->getDouble(DCM_ImageOrientationPatient, i+3, OFTrue);
139  pos[i] = this->getDouble(DCM_ImagePositionPatient, i, OFTrue);
140  }
141 
142  Transform3D retval = cx::createTransformIJC(e_x, e_y, pos);
143  return retval;
144 }
145 
146 ctkDICOMItemPtr DicomImageReader::wrapInCTK(DcmItem* item) const
147 {
148  if (!item)
149  return ctkDICOMItemPtr();
150  ctkDICOMItemPtr retval(new ctkDICOMItem);
151  retval->InitializeFromItem(item);
152  return retval;
153 }
154 
155 void DicomImageReader::error(QString message) const
156 {
157  reportError(QString("Dicom convert: [%1] in %2").arg(message).arg(mFilename));
158 }
159 
161 {
162  DicomImage dicomImage(mFilename.toLatin1().data()); //, CIF_MayDetachPixelData );
163  const DiPixel *pixels = dicomImage.getInterData();
164  if (!pixels)
165  {
166  this->error("Found no pixel data");
167  return vtkImageDataPtr();
168  }
169 
170  vtkImageDataPtr data = vtkImageDataPtr::New();
171 
172  data->SetSpacing(this->getSpacing().data());
173 
174  Eigen::Array3i dim = this->getDim(dicomImage);
175  data->SetExtent(0, dim[0]-1, 0, dim[1]-1, 0, dim[2]-1);
176 
177  int samplesPerPixel = pixels->getPlanes();
178  int scalarSize = dim.prod() * samplesPerPixel;
179  int pixelDepth = dicomImage.getDepth();
180 
181  switch (pixels->getRepresentation())
182  {
183  case EPR_Uint8:
184 // std::cout << " VTK_UNSIGNED_CHAR" << std::endl;
185  data->AllocateScalars(VTK_UNSIGNED_CHAR, samplesPerPixel);
186  break;
187  case EPR_Uint16:
188 // std::cout << " VTK_UNSIGNED_SHORT" << std::endl;
189  data->AllocateScalars(VTK_UNSIGNED_SHORT, samplesPerPixel);
190  break;
191  case EPR_Uint32:
192  this->error("DICOM EPR_Uint32 not supported");
193  return vtkImageDataPtr();
194  break;
195  case EPR_Sint8:
196 // std::cout << " VTK_CHAR" << std::endl;
197  data->AllocateScalars(VTK_CHAR, samplesPerPixel);
198  break;
199  case EPR_Sint16:
200 // std::cout << " VTK_SHORT" << std::endl;
201  data->AllocateScalars(VTK_SHORT, samplesPerPixel);
202  break;
203  case EPR_Sint32:
204  this->error("DICOM EPR_Sint32 not supported");
205  return vtkImageDataPtr();
206  break;
207  }
208 
209  int bytesPerPixel = data->GetScalarSize() * samplesPerPixel;
210 
211  memcpy(data->GetScalarPointer(), pixels->getData(), pixels->getCount()*bytesPerPixel);
212  if (pixels->getCount()!=scalarSize)
213  this->error("Mismatch in pixel counts");
214  setDeepModified(data);
215  return data;
216 }
217 
218 Eigen::Array3d DicomImageReader::getSpacing() const
219 {
220  Eigen::Array3d spacing;
221  spacing[0] = this->getDouble(DCM_PixelSpacing, 0, OFTrue);
222  spacing[1] = this->getDouble(DCM_PixelSpacing, 1, OFTrue);
223  spacing[2] = this->getDouble(DCM_SliceThickness, 0, OFTrue);
224 // std::cout << " spacing: " << spacing << std::endl;
225  return spacing;
226 }
227 
228 Eigen::Array3i DicomImageReader::getDim(const DicomImage& dicomImage) const
229 {
230  Eigen::Array3i dim;
231  dim[0] = dicomImage.getWidth();
232  dim[1] = dicomImage.getHeight();
233  dim[2] = dicomImage.getFrameCount();
234  return dim;
235 }
236 
238 {
239  QString rawName = this->item()->GetElementAsString(DCM_PatientName);
240  return this->formatPatientName(rawName);
241 }
242 
243 QString DicomImageReader::formatPatientName(QString rawName) const
244 {
245  // ripped from ctkDICOMModel
246 
247  OFString dicomName = rawName.toStdString().c_str();
248  OFString formattedName;
249  OFString lastName, firstName, middleName, namePrefix, nameSuffix;
250  OFCondition l_error = DcmPersonName::getNameComponentsFromString(dicomName,
251  lastName, firstName, middleName, namePrefix, nameSuffix);
252  if (l_error.good())
253  {
254  formattedName.clear();
255  /* concatenate name components per this convention
256  * Last, First Middle, Suffix (Prefix)
257  * */
258  if (!lastName.empty())
259  {
260  formattedName += lastName;
261  if ( !(firstName.empty() && middleName.empty()) )
262  {
263  formattedName += ",";
264  }
265  }
266  if (!firstName.empty())
267  {
268  formattedName += " ";
269  formattedName += firstName;
270  }
271  if (!middleName.empty())
272  {
273  formattedName += " ";
274  formattedName += middleName;
275  }
276  if (!nameSuffix.empty())
277  {
278  formattedName += ", ";
279  formattedName += nameSuffix;
280  }
281  if (!namePrefix.empty())
282  {
283  formattedName += " (";
284  formattedName += namePrefix;
285  formattedName += ")";
286  }
287  }
288  return QString(formattedName.c_str());
289 }
290 
291 
292 } // namespace cx
293 
static DicomImageReaderPtr createFromFile(QString filename)
bool isLocalizerImage() const
void reportError(QString msg)
Definition: cxLogger.cpp:92
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
WindowLevel getWindowLevel() const
ctkDICOMItemPtr item() const
Transform3D getImageTransformPatient() const
vtkImageDataPtr createVtkImageData()
Transform3D createTransformIJC(const Vector3D &ivec, const Vector3D &jvec, const Vector3D &center)
QString getPatientName() const
boost::shared_ptr< class ctkDICOMItem > ctkDICOMItemPtr
boost::shared_ptr< class DicomImageReader > DicomImageReaderPtr
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:63
void setDeepModified(vtkImageDataPtr image)
vtkSmartPointer< class vtkImageData > vtkImageDataPtr