ctkDICOMIndexerBase.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.commontk.org/LICENSE
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. // Qt includes
  15. #include <QSqlQuery>
  16. #include <QSqlRecord>
  17. #include <QSqlError>
  18. #include <QVariant>
  19. #include <QDate>
  20. #include <QStringList>
  21. #include <QSet>
  22. #include <QFile>
  23. #include <QDirIterator>
  24. #include <QFileInfo>
  25. #include <QDebug>
  26. // ctkDICOM includes
  27. #include "ctkDICOMIndexerBase.h"
  28. #include "ctkLogger.h"
  29. // DCMTK includes
  30. #ifndef WIN32
  31. #define HAVE_CONFIG_H
  32. #endif
  33. #include <dcmtk/dcmdata/dcfilefo.h>
  34. #include <dcmtk/dcmdata/dcfilefo.h>
  35. #include <dcmtk/dcmdata/dcdeftag.h>
  36. #include <dcmtk/dcmdata/dcdatset.h>
  37. #include <dcmtk/ofstd/ofcond.h>
  38. #include <dcmtk/ofstd/ofstring.h>
  39. #include <dcmtk/ofstd/ofstd.h> /* for class OFStandard */
  40. #include <dcmtk/dcmdata/dcddirif.h> /* for class DicomDirInterface */
  41. //------------------------------------------------------------------------------
  42. static ctkLogger logger("org.commontk.dicom.DICOMIndexerBase" );
  43. //------------------------------------------------------------------------------
  44. //------------------------------------------------------------------------------
  45. class ctkDICOMIndexerBasePrivate
  46. {
  47. public:
  48. ctkDICOMIndexerBasePrivate();
  49. ~ctkDICOMIndexerBasePrivate();
  50. QSqlDatabase db;
  51. };
  52. //------------------------------------------------------------------------------
  53. // ctkDICOMIndexerBasePrivate methods
  54. //------------------------------------------------------------------------------
  55. ctkDICOMIndexerBasePrivate::ctkDICOMIndexerBasePrivate()
  56. {
  57. }
  58. //------------------------------------------------------------------------------
  59. ctkDICOMIndexerBasePrivate::~ctkDICOMIndexerBasePrivate()
  60. {
  61. }
  62. //------------------------------------------------------------------------------
  63. // ctkDICOMIndexerBase methods
  64. //------------------------------------------------------------------------------
  65. ctkDICOMIndexerBase::ctkDICOMIndexerBase()
  66. : d_ptr(new ctkDICOMIndexerBasePrivate)
  67. {
  68. }
  69. //------------------------------------------------------------------------------
  70. ctkDICOMIndexerBase::~ctkDICOMIndexerBase()
  71. {
  72. }
  73. //------------------------------------------------------------------------------
  74. void ctkDICOMIndexerBase::setDatabase ( QSqlDatabase database ) {
  75. Q_D(ctkDICOMIndexerBase);
  76. d->db = database;
  77. }
  78. //------------------------------------------------------------------------------
  79. const QSqlDatabase& ctkDICOMIndexerBase::database () const {
  80. Q_D(const ctkDICOMIndexerBase);
  81. return d->db;
  82. }
  83. //------------------------------------------------------------------------------
  84. void ctkDICOMIndexerBase::insert ( DcmDataset *dataset ) {
  85. this->insert ( dataset, QString() );
  86. }
  87. //------------------------------------------------------------------------------
  88. void ctkDICOMIndexerBase::insert ( DcmDataset *dataset, QString filename ) {
  89. Q_D(ctkDICOMIndexerBase);
  90. // Check to see if the file has already been loaded
  91. QSqlQuery fileExists ( d->db );
  92. fileExists.prepare("SELECT InsertTimestamp FROM Images WHERE Filename == ?");
  93. fileExists.bindValue(0,filename);
  94. fileExists.exec();
  95. if ( fileExists.next() && QFileInfo(filename).lastModified() < QDateTime::fromString(fileExists.value(0).toString(),Qt::ISODate) )
  96. {
  97. logger.debug ( "File " + filename + " already added" );
  98. return;
  99. }
  100. OFString patientsName, patientID, patientsBirthDate, patientsBirthTime, patientsSex,
  101. patientComments, patientsAge;
  102. OFString studyInstanceUID, studyID, studyDate, studyTime,
  103. accessionNumber, modalitiesInStudy, institutionName, performingPhysiciansName, referringPhysician, studyDescription;
  104. OFString seriesInstanceUID, seriesDate, seriesTime,
  105. seriesDescription, bodyPartExamined, frameOfReferenceUID,
  106. contrastAgent, scanningSequence;
  107. OFString instanceNumber;
  108. Sint32 seriesNumber = 0, acquisitionNumber = 0, echoNumber = 0, temporalPosition = 0;
  109. //If the following fields can not be evaluated, cancel evaluation of the DICOM file
  110. dataset->findAndGetOFString(DCM_PatientsName, patientsName);
  111. dataset->findAndGetOFString(DCM_StudyInstanceUID, studyInstanceUID);
  112. dataset->findAndGetOFString(DCM_SeriesInstanceUID, seriesInstanceUID);
  113. dataset->findAndGetOFString(DCM_PatientID, patientID);
  114. dataset->findAndGetOFString(DCM_PatientsBirthDate, patientsBirthDate);
  115. dataset->findAndGetOFString(DCM_PatientsBirthTime, patientsBirthTime);
  116. dataset->findAndGetOFString(DCM_PatientsSex, patientsSex);
  117. dataset->findAndGetOFString(DCM_PatientsAge, patientsAge);
  118. dataset->findAndGetOFString(DCM_PatientComments, patientComments);
  119. dataset->findAndGetOFString(DCM_StudyID, studyID);
  120. dataset->findAndGetOFString(DCM_StudyDate, studyDate);
  121. dataset->findAndGetOFString(DCM_StudyTime, studyTime);
  122. dataset->findAndGetOFString(DCM_AccessionNumber, accessionNumber);
  123. dataset->findAndGetOFString(DCM_ModalitiesInStudy, modalitiesInStudy);
  124. dataset->findAndGetOFString(DCM_InstitutionName, institutionName);
  125. dataset->findAndGetOFString(DCM_PerformingPhysiciansName, performingPhysiciansName);
  126. dataset->findAndGetOFString(DCM_ReferringPhysiciansName, referringPhysician);
  127. dataset->findAndGetOFString(DCM_StudyDescription, studyDescription);
  128. dataset->findAndGetOFString(DCM_SeriesDate, seriesDate);
  129. dataset->findAndGetOFString(DCM_SeriesTime, seriesTime);
  130. dataset->findAndGetOFString(DCM_SeriesDescription, seriesDescription);
  131. dataset->findAndGetOFString(DCM_BodyPartExamined, bodyPartExamined);
  132. dataset->findAndGetOFString(DCM_FrameOfReferenceUID, frameOfReferenceUID);
  133. dataset->findAndGetOFString(DCM_ContrastBolusAgent, contrastAgent);
  134. dataset->findAndGetOFString(DCM_ScanningSequence, scanningSequence);
  135. dataset->findAndGetSint32(DCM_SeriesNumber, seriesNumber);
  136. dataset->findAndGetSint32(DCM_AcquisitionNumber, acquisitionNumber);
  137. dataset->findAndGetSint32(DCM_EchoNumbers, echoNumber);
  138. dataset->findAndGetSint32(DCM_TemporalPositionIdentifier, temporalPosition);
  139. QSqlQuery check_exists_query(d->db);
  140. //The patient UID is a unique number within the database, generated by the sqlite autoincrement
  141. int patientUID = -1;
  142. if ( patientID != "" && patientsName != "" )
  143. {
  144. //Check if patient is already present in the db
  145. check_exists_query.prepare ( "SELECT * FROM Patients WHERE PatientID = ? AND PatientsName = ?" );
  146. check_exists_query.bindValue ( 0, QString ( patientID.c_str() ) );
  147. check_exists_query.bindValue ( 1, QString ( patientsName.c_str() ) );
  148. check_exists_query.exec();
  149. if (check_exists_query.next())
  150. {
  151. patientUID = check_exists_query.value(check_exists_query.record().indexOf("UID")).toInt();
  152. }
  153. else
  154. {
  155. // Insert it
  156. QSqlQuery statement ( d->db );
  157. statement.prepare ( "INSERT INTO Patients ('UID', 'PatientsName', 'PatientID', 'PatientsBirthDate', 'PatientsBirthTime', 'PatientsSex', 'PatientsAge', 'PatientsComments' ) values ( NULL, ?, ?, ?, ?, ?, ?, ? )" );
  158. statement.bindValue ( 0, QString ( patientsName.c_str() ) );
  159. statement.bindValue ( 1, QString ( patientID.c_str() ) );
  160. statement.bindValue ( 2, QString ( patientsBirthDate.c_str() ) );
  161. statement.bindValue ( 3, QString ( patientsBirthTime.c_str() ) );
  162. statement.bindValue ( 4, QString ( patientsSex.c_str() ) );
  163. statement.bindValue ( 5, QString ( patientsAge.c_str() ) );
  164. statement.bindValue ( 6, QString ( patientComments.c_str() ) );
  165. statement.exec ();
  166. patientUID = statement.lastInsertId().toInt();
  167. logger.debug ( "New patient inserted: " + QString().setNum ( patientUID ) );
  168. }
  169. }
  170. if ( studyInstanceUID != "" )
  171. {
  172. check_exists_query.prepare ( "SELECT * FROM Studies WHERE StudyInstanceUID = ?" );
  173. check_exists_query.bindValue ( 0, QString ( studyInstanceUID.c_str() ) );
  174. check_exists_query.exec();
  175. if(!check_exists_query.next())
  176. {
  177. QSqlQuery statement ( d->db );
  178. statement.prepare ( "INSERT INTO Studies ( 'StudyInstanceUID', 'PatientsUID', 'StudyID', 'StudyDate', 'StudyTime', 'AccessionNumber', 'ModalitiesInStudy', 'InstitutionName', 'ReferringPhysician', 'PerformingPhysiciansName', 'StudyDescription' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" );
  179. statement.bindValue ( 0, QString ( studyInstanceUID.c_str() ) );
  180. statement.bindValue ( 1, patientUID );
  181. statement.bindValue ( 2, QString ( studyID.c_str() ) );
  182. statement.bindValue ( 3, QDate::fromString ( studyDate.c_str(), "yyyyMMdd" ) );
  183. statement.bindValue ( 4, QString ( studyTime.c_str() ) );
  184. statement.bindValue ( 5, QString ( accessionNumber.c_str() ) );
  185. statement.bindValue ( 6, QString ( modalitiesInStudy.c_str() ) );
  186. statement.bindValue ( 7, QString ( institutionName.c_str() ) );
  187. statement.bindValue ( 8, QString ( referringPhysician.c_str() ) );
  188. statement.bindValue ( 9, QString ( performingPhysiciansName.c_str() ) );
  189. statement.bindValue ( 10, QString ( studyDescription.c_str() ) );
  190. if ( !statement.exec() )
  191. {
  192. logger.error ( "Error executing statament: " + statement.lastQuery() + " Error: " + statement.lastError().text() );
  193. }
  194. }
  195. }
  196. if ( seriesInstanceUID != "" )
  197. {
  198. check_exists_query.prepare ( "SELECT * FROM Series WHERE SeriesInstanceUID = ?" );
  199. check_exists_query.bindValue ( 0, QString ( seriesInstanceUID.c_str() ) );
  200. logger.warn ( "Statement: " + check_exists_query.lastQuery() );
  201. check_exists_query.exec();
  202. if(!check_exists_query.next())
  203. {
  204. QSqlQuery statement ( d->db );
  205. statement.prepare ( "INSERT INTO Series ( 'SeriesInstanceUID', 'StudyInstanceUID', 'SeriesNumber', 'SeriesDate', 'SeriesTime', 'SeriesDescription', 'BodyPartExamined', 'FrameOfReferenceUID', 'AcquisitionNumber', 'ContrastAgent', 'ScanningSequence', 'EchoNumber', 'TemporalPosition' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" );
  206. statement.bindValue ( 0, QString ( seriesInstanceUID.c_str() ) );
  207. statement.bindValue ( 1, QString ( studyInstanceUID.c_str() ) );
  208. statement.bindValue ( 2, static_cast<int>(seriesNumber) );
  209. statement.bindValue ( 3, QString ( seriesDate.c_str() ) );
  210. statement.bindValue ( 4, QDate::fromString ( seriesTime.c_str(), "yyyyMMdd" ) );
  211. statement.bindValue ( 5, QString ( seriesDescription.c_str() ) );
  212. statement.bindValue ( 6, QString ( bodyPartExamined.c_str() ) );
  213. statement.bindValue ( 7, QString ( frameOfReferenceUID.c_str() ) );
  214. statement.bindValue ( 8, static_cast<int>(acquisitionNumber) );
  215. statement.bindValue ( 9, QString ( contrastAgent.c_str() ) );
  216. statement.bindValue ( 10, QString ( scanningSequence.c_str() ) );
  217. statement.bindValue ( 11, static_cast<int>(echoNumber) );
  218. statement.bindValue ( 12, static_cast<int>(temporalPosition) );
  219. if ( !statement.exec() )
  220. {
  221. logger.error ( "Error executing statament: " + statement.lastQuery() + " Error: " + statement.lastError().text() );
  222. }
  223. }
  224. }
  225. if ( !filename.isEmpty() )
  226. {
  227. check_exists_query.prepare ( "SELECT * FROM Images WHERE Filename = ?" );
  228. check_exists_query.bindValue ( 0, filename );
  229. check_exists_query.exec();
  230. if(!check_exists_query.next())
  231. {
  232. QSqlQuery statement ( d->db );
  233. statement.prepare ( "INSERT INTO Images ( 'Filename', 'SeriesInstanceUID', 'InsertTimestamp' ) VALUES ( ?, ?, ? )" );
  234. statement.bindValue ( 0, filename );
  235. statement.bindValue ( 1, QString ( seriesInstanceUID.c_str() ) );
  236. statement.bindValue ( 2, QDateTime::currentDateTime() );
  237. statement.exec();
  238. }
  239. }
  240. }