CustusX  22.04-rc2
An IGT application
cxDICOMReader.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) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 
12 #include "cxDICOMReader.h"
13 
14 #include <QDir>
15 #include <vtkImageData.h>
16 #include <ctkDICOMDatabase.h>
17 #include <ctkDICOMIndexer.h>
18 #include "cxImage.h"
19 #include "cxPatientModelService.h"
20 #include "cxLogger.h"
21 #include "cxDicomConverter.h"
22 #include "cxDicomImageReader.h"
23 
24 namespace cx
25 {
27  FileReaderWriterImplService("DICOMReader" ,Image::getTypeName(), "", "dcm *", patientModelService)
28 {
29 
30 }
31 
32 // This function is used for checking all readers if they can read a file,
33 // so output should only be used for debug.
34 bool DICOMReader::canRead(const QString &type, const QString &filename)
35 {
36  QString fileType = QFileInfo(filename).suffix();
37  QFile file(filename);
38  bool opened = file.open(QIODevice::ReadOnly);
39 
40  // A DICOM file should have the characters "DICM" at position 0x80
41  bool success = file.seek(0x80);
42  if(!success)
43  {
44  //CX_LOG_WARNING() << "DICOMReader: File isn't large enough to be DICOM: " << filename;
45  return false;
46  }
47 
48  char buf[4];
49  int numReadChar = file.peek(buf, sizeof(buf));
50  if (numReadChar != sizeof(buf))
51  {
52  //CX_LOG_WARNING() << "DICOMReader: Cannot read from file: " << filename;
53  return false;
54  }
55  if (buf[0] != 'D' || buf[1] != 'I' || buf[2] != 'C' || buf[3] != 'M')
56  {
57  //CX_LOG_WARNING() << "DICOMReader: File isn't DICOM: " << filename;
58  return false;
59  }
60  else
61  return true;
62 }
63 
65 {
66  return Image::getTypeName();
67 }
68 
69 bool DICOMReader::readInto(DataPtr data, QString filename)
70 {
71  return this->readInto(boost::dynamic_pointer_cast<Image>(data), filename);
72 }
73 
74 bool DICOMReader::readInto(ImagePtr image, QString filename)
75 {
76  if (!image)
77  return false;
78  vtkImageDataPtr raw = this->loadVtkImageData(filename);
79  if(!raw)
80  return false;
81  image->setVtkImageData(raw);
82  return true;
83 }
84 
85 DataPtr DICOMReader::read(const QString& uid, const QString& filename)
86 {
87  ImagePtr image(new Image(uid, vtkImageDataPtr()));
88  this->readInto(image, filename);
89 
90  DataPtr retval = image;
91  return retval;
92 }
93 
94 std::vector<DataPtr> DICOMReader::read(const QString &filename)
95 {
96  std::vector<DataPtr> retval;
97  ImagePtr image = importSeries(filename);
98 
99  if(image)
100  retval.push_back(image);
101 
102  return retval;
103 }
104 
106 {
107  ImagePtr image = importSeries(filename);
108  return image->getBaseVtkImageData();
109 }
110 
111 
113 {
114  return "";
115 }
116 
117 bool DICOMReader::canWrite(const QString &type, const QString &filename) const
118 {
119  return false;
120 }
121 
122 //Copied from DicomWidget::importSeries
123 //Also copied DicomConverter and DicomImageReader files from the dicom plugin
125 {
126  cx::ImagePtr convertedImage;
127  cx::DicomConverter converter;
128  ctkDICOMDatabasePtr database = ctkDICOMDatabasePtr(new ctkDICOMDatabase);
129  database->openDatabase(":memory:");
130  converter.setDicomDatabase(database.data());
131 
132  QFileInfo dir = QFileInfo(fileName);
133  QString folder = dir.absolutePath();
134 
135  QSharedPointer<ctkDICOMIndexer> DICOMIndexer = QSharedPointer<ctkDICOMIndexer> (new ctkDICOMIndexer);
136  DICOMIndexer->addDirectory(*database,folder,"");
137 
138  QString seriesUid = this->getBestDICOMSeries(database);
139  convertedImage = converter.convertToImage(seriesUid);
140 
141  if (!convertedImage)
142  {
143  reportError(QString("Failed to convert DICOM series %1").arg(seriesUid));
144  }
145  database->closeDatabase();
146  return convertedImage;
147 }
148 
149 //Choose the series with the most files for now
151 {
152  QString retval;
153  int numFiles = 0;
154  QStringList patients = database->patients();
155  for(int pNr = 0; pNr < patients.size(); ++pNr)
156  {
157  QString patient = patients[pNr];
158  CX_LOG_DEBUG() << "Got " << patients.size() << " DICOM patients.";
159  QStringList studies = database->studiesForPatient(patient);
160  CX_LOG_DEBUG() << "Got " << studies.size() << " DICOM studies for patient " << patient;
161  for(int sNr = 0; sNr < studies.size(); ++sNr)
162  {
163  QString study = studies[sNr];
164  QStringList series = database->seriesForStudy(study);
165  CX_LOG_DEBUG() << "Got " << series.size() << " DICOM series for study " << study;
166  for(int seriesNr = 0; seriesNr < series.size(); ++seriesNr)
167  {
168  QString serie = series[seriesNr];
169  QStringList files = database->filesForSeries(serie);
170  CX_LOG_DEBUG() << "Got " << files.size() << " DICOM files for series " << serie;
171  if(numFiles < files.size())
172  {
173  numFiles = files.size();
174  if(retval.isEmpty())
175  CX_LOG_DEBUG() << "Selecting patient " << patient << " study " << study
176  << " series " << serie << " with " << numFiles << " files";
177  else
178  CX_LOG_DEBUG() << "Found longer series: Patient " << patient << " study " << study
179  << " series " << serie << " with " << numFiles << " files";
180  retval = serie;
181  }
182  }
183  }
184  }
185  return retval;
186 }
187 
188 }//cx
virtual vtkImageDataPtr loadVtkImageData(QString filename)
void reportError(QString msg)
Definition: cxLogger.cpp:71
QString canWriteDataType() const
DICOMReader(PatientModelServicePtr patientModelService)
virtual bool canRead(const QString &type, const QString &filename)
Simple check if file is a DICOM file. DICOM files can have several different endings (...
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:27
void setDicomDatabase(ctkDICOMDatabase *database)
bool canWrite(const QString &type, const QString &filename) const
boost::shared_ptr< class Data > DataPtr
ImagePtr convertToImage(QString seriesUid)
virtual QString canReadDataType() const
virtual DataPtr read(const QString &uid, const QString &filename)
virtual bool readInto(DataPtr data, QString path)
A volumetric data set.
Definition: cxImage.h:45
boost::shared_ptr< class PatientModelService > PatientModelServicePtr
static QString getTypeName()
Definition: cxImage.h:126
ImagePtr importSeries(QString fileName)
QString getBestDICOMSeries(ctkDICOMDatabasePtr database)
QSharedPointer< class ctkDICOMDatabase > ctkDICOMDatabasePtr
Definition: cxDICOMReader.h:18
#define CX_LOG_DEBUG
Definition: cxLogger.h:95
vtkSmartPointer< class vtkImageData > vtkImageDataPtr
Namespace for all CustusX production code.