qCTKDCMTKIndexer.cxx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. #include "qCTKDCMTKIndexer.h"
  2. ///
  3. /// DCMTK includes
  4. #ifndef WIN32
  5. #define HAVE_CONFIG_H
  6. #endif
  7. #include "dcmtk/dcmdata/dcfilefo.h"
  8. #include "dcmtk/dcmdata/dcdeftag.h"
  9. #include "dcmtk/dcmdata/dcdatset.h"
  10. #include "dcmtk/ofstd/ofcond.h"
  11. #include "dcmtk/ofstd/ofstring.h"
  12. #include "dcmtk/ofstd/ofstd.h" /* for class OFStandard */
  13. #include "dcmtk/dcmdata/dcddirif.h" /* for class DicomDirInterface */
  14. #include <QSqlQuery>
  15. #include <QSqlRecord>
  16. #include <QVariant>
  17. #include <QDate>
  18. #define MITK_ERROR std::cout
  19. #define MITK_INFO std::cout
  20. class qCTKDCMTKIndexerPrivate: public qCTKPrivate<qCTKDCMTKIndexer>
  21. {
  22. public:
  23. qCTKDCMTKIndexerPrivate();
  24. ~qCTKDCMTKIndexerPrivate();
  25. };
  26. qCTKDCMTKIndexerPrivate::qCTKDCMTKIndexerPrivate()
  27. {
  28. }
  29. qCTKDCMTKIndexerPrivate::~qCTKDCMTKIndexerPrivate()
  30. {
  31. }
  32. qCTKDCMTKIndexer::qCTKDCMTKIndexer()
  33. {
  34. }
  35. qCTKDCMTKIndexer::~qCTKDCMTKIndexer()
  36. {
  37. }
  38. void qCTKDCMTKIndexer::AddDirectory(QSqlDatabase database, const QString& directoryName)
  39. {
  40. QSqlDatabase db = database;
  41. const std::string src_directory(directoryName.toStdString());
  42. // db.transaction();
  43. OFList<OFString> originalDcmtkFileNames;
  44. OFList<OFString> dcmtkFileNames;
  45. OFStandard::searchDirectoryRecursively(src_directory.c_str(), originalDcmtkFileNames, NULL, NULL);
  46. // hack to reverse list of filenames (not neccessary when image loading works correctly)
  47. for ( OFListIterator(OFString) iter = originalDcmtkFileNames.begin(); iter != originalDcmtkFileNames.end(); ++iter )
  48. {
  49. dcmtkFileNames.push_front( *iter );
  50. }
  51. DcmFileFormat fileformat;
  52. OFListIterator(OFString) iter = dcmtkFileNames.begin();
  53. OFListIterator(OFString) last = dcmtkFileNames.end();
  54. if(iter == last) return;
  55. QSqlQuery query(database);
  56. /* iterate over all input filenames */
  57. OFString lastPatientID = "", lastPatientsName = "", lastPatientsBirthDate = "", lastStudyInstanceUID = "", lastSeriesInstanceUID = "";
  58. int lastPatientUID = -1;
  59. while (iter != last)
  60. {
  61. std::string filename((*iter).c_str());
  62. MITK_INFO << filename << "\n";
  63. OFCondition status = fileformat.loadFile(filename.c_str());
  64. ++iter;
  65. if (!status.good())
  66. {
  67. MITK_ERROR << "Could not load " << filename << "\nDCMTK says: " << status.text();
  68. continue;
  69. }
  70. OFString patientsName = "", patientID = "", patientsBirthDate = "", patientsBirthTime = "", patientsSex = "",
  71. patientComments = "", patientsAge = "";
  72. OFString studyInstanceUID = "", studyID = "", studyDate = "", studyTime = "",
  73. accessionNumber = "", modalitiesInStudy = "", performingPhysiciansName = "", referringPhysician = "", studyDescription = "";
  74. OFString seriesInstanceUID = "", seriesDate = "", seriesTime = "",
  75. seriesDescription = "", bodyPartExamined = "", frameOfReferenceUID = "",
  76. contrastAgent = "", scanningSequence = "";
  77. Sint32 seriesNumber = 0, acquisitionNumber = 0, echoNumber = 0, temporalPosition = 0;
  78. //The patient UID is a unique number within the database, generated by the sqlite autoincrement
  79. int patientUID = -1;
  80. //If the following fields can not be evaluated, cancel evaluation of the DICOM file
  81. if (!fileformat.getDataset()->findAndGetOFString(DCM_PatientsName, patientsName).good())
  82. {
  83. MITK_ERROR << "Could not read DCM_PatientsName from " << filename;
  84. continue;
  85. }
  86. if (!fileformat.getDataset()->findAndGetOFString(DCM_StudyInstanceUID, studyInstanceUID).good())
  87. {
  88. MITK_ERROR << "Could not read DCM_StudyInstanceUID from " << filename;
  89. continue;
  90. }
  91. if (!fileformat.getDataset()->findAndGetOFString(DCM_SeriesInstanceUID, seriesInstanceUID).good())
  92. {
  93. MITK_ERROR << "Could not read DCM_SeriesInstanceUID from " << filename;
  94. continue;
  95. }
  96. fileformat.getDataset()->findAndGetOFString(DCM_PatientID, patientID);
  97. fileformat.getDataset()->findAndGetOFString(DCM_PatientsBirthDate, patientsBirthDate);
  98. fileformat.getDataset()->findAndGetOFString(DCM_PatientsBirthTime, patientsBirthTime);
  99. fileformat.getDataset()->findAndGetOFString(DCM_PatientsSex, patientsSex);
  100. fileformat.getDataset()->findAndGetOFString(DCM_PatientsAge, patientsAge);
  101. fileformat.getDataset()->findAndGetOFString(DCM_PatientComments, patientComments);
  102. fileformat.getDataset()->findAndGetOFString(DCM_StudyID, studyID);
  103. fileformat.getDataset()->findAndGetOFString(DCM_StudyDate, studyDate);
  104. fileformat.getDataset()->findAndGetOFString(DCM_StudyTime, studyTime);
  105. fileformat.getDataset()->findAndGetOFString(DCM_AccessionNumber, accessionNumber);
  106. fileformat.getDataset()->findAndGetOFString(DCM_ModalitiesInStudy, modalitiesInStudy);
  107. fileformat.getDataset()->findAndGetOFString(DCM_PerformingPhysiciansName, performingPhysiciansName);
  108. fileformat.getDataset()->findAndGetOFString(DCM_ReferringPhysiciansName, referringPhysician);
  109. fileformat.getDataset()->findAndGetOFString(DCM_StudyDescription, studyDescription);
  110. fileformat.getDataset()->findAndGetOFString(DCM_SeriesDate, seriesDate);
  111. fileformat.getDataset()->findAndGetOFString(DCM_SeriesTime, seriesTime);
  112. fileformat.getDataset()->findAndGetOFString(DCM_SeriesDescription, seriesDescription);
  113. fileformat.getDataset()->findAndGetOFString(DCM_BodyPartExamined, bodyPartExamined);
  114. fileformat.getDataset()->findAndGetOFString(DCM_FrameOfReferenceUID, frameOfReferenceUID);
  115. fileformat.getDataset()->findAndGetOFString(DCM_ContrastBolusAgent, contrastAgent);
  116. fileformat.getDataset()->findAndGetOFString(DCM_ScanningSequence, scanningSequence);
  117. fileformat.getDataset()->findAndGetSint32(DCM_SeriesNumber, seriesNumber);
  118. fileformat.getDataset()->findAndGetSint32(DCM_AcquisitionNumber, acquisitionNumber);
  119. fileformat.getDataset()->findAndGetSint32(DCM_EchoNumbers, echoNumber);
  120. fileformat.getDataset()->findAndGetSint32(DCM_TemporalPositionIdentifier, temporalPosition);
  121. MITK_INFO << "Adding new items to database:";
  122. MITK_INFO << "studyID: " << studyID;
  123. MITK_INFO << "seriesInstanceUID: " << seriesInstanceUID;
  124. MITK_INFO << "Patient's Name: " << patientsName;
  125. //-----------------------
  126. //Add Patient to Database
  127. //-----------------------
  128. //Speed up: Check if patient is the same as in last file; very probable, as all images belonging to a study have the same patient
  129. if(lastPatientID.compare(patientID) || lastPatientsBirthDate.compare(patientsBirthDate) || lastPatientsName.compare(patientsName))
  130. {
  131. //Check if patient is already present in the db
  132. QSqlQuery check_exists_query(database);
  133. std::stringstream check_exists_query_string;
  134. check_exists_query_string << "SELECT * FROM Patients WHERE PatientID = '" << patientID << "'";
  135. check_exists_query.exec(check_exists_query_string.str().c_str());
  136. //check_exists_query_string.flush();
  137. bool patientExists = false;
  138. while (check_exists_query.next())
  139. {
  140. patientExists = true;
  141. QString checkPatientsName = check_exists_query.value(check_exists_query.record().indexOf("PatientsName")).toString();
  142. if(checkPatientsName.toStdString().compare(patientsName.c_str())) patientExists = false;
  143. QString checkPatientsBirthDate = check_exists_query.value(check_exists_query.record().indexOf("PatientsBirthDate")).toString();
  144. if(checkPatientsBirthDate.toStdString().compare(patientsBirthDate.c_str())) patientExists = false;
  145. if(patientExists)
  146. {
  147. patientUID = check_exists_query.value(check_exists_query.record().indexOf("UID")).toInt();
  148. break;
  149. }
  150. }
  151. if(!patientExists)
  152. {
  153. std::stringstream query_string;
  154. query_string << "INSERT INTO Patients VALUES( NULL,'" << patientsName << "','" << patientID << "','" << patientsBirthDate << "','"
  155. << patientsBirthTime << "','" << patientsSex << "','" << patientsAge << "','" << patientComments << "')";
  156. query.exec(query_string.str().c_str());
  157. patientUID = query.lastInsertId().toInt();
  158. MITK_INFO << "Query result: " << patientUID << "\n";
  159. }
  160. }
  161. else patientUID = lastPatientUID;
  162. lastPatientUID = patientUID;
  163. lastPatientID = patientID;
  164. lastPatientsBirthDate = patientsBirthDate;
  165. lastPatientsName = patientsName;
  166. //---------------------
  167. //Add Study to Database
  168. //---------------------
  169. if(lastStudyInstanceUID.compare(studyInstanceUID))
  170. {
  171. QSqlQuery check_exists_query(database);
  172. std::stringstream check_exists_query_string;
  173. check_exists_query_string << "SELECT * FROM Studies WHERE StudyInstanceUID = '" << studyInstanceUID << "'";
  174. check_exists_query.exec(check_exists_query_string.str().c_str());
  175. if(!check_exists_query.next())
  176. {
  177. std::stringstream query_string;
  178. query_string << "INSERT INTO Studies VALUES('"
  179. << studyInstanceUID << "','" << patientUID << "','" << studyID << "','"
  180. << QDate::fromString(studyDate.c_str(), "yyyyMMdd").toString("yyyy-MM-dd").toStdString() << "','"
  181. << studyTime << "','" << accessionNumber << "','" << modalitiesInStudy << "','" << referringPhysician << "','" << performingPhysiciansName << "','" << studyDescription << "')";
  182. query.exec(query_string.str().c_str());
  183. }
  184. }
  185. lastStudyInstanceUID = studyInstanceUID;
  186. //----------------------
  187. //Add Series to Database
  188. //----------------------
  189. if(lastSeriesInstanceUID.compare(seriesInstanceUID))
  190. {
  191. QSqlQuery check_exists_query(database);
  192. std::stringstream check_exists_query_string;
  193. check_exists_query_string << "SELECT * FROM Series WHERE SeriesInstanceUID = '" << seriesInstanceUID << "'";
  194. check_exists_query.exec(check_exists_query_string.str().c_str());
  195. if(!check_exists_query.next())
  196. {
  197. std::stringstream query_string;
  198. query_string << "INSERT INTO Series VALUES('"
  199. << seriesInstanceUID << "','" << studyInstanceUID << "','" << (int) seriesNumber << "','"
  200. << QDate::fromString(seriesDate.c_str(), "yyyyMMdd").toString("yyyy-MM-dd").toStdString() << "','"
  201. << seriesTime << "','" << seriesDescription << "','" << bodyPartExamined << "','"
  202. << frameOfReferenceUID << "','" << (int) acquisitionNumber << "','" << contrastAgent << "','"
  203. << scanningSequence << "','" << (int) echoNumber << "','" << (int) temporalPosition << "')";
  204. query.exec(query_string.str().c_str());
  205. }
  206. }
  207. lastSeriesInstanceUID = seriesInstanceUID;
  208. //----------------------------------
  209. //Move file to destination directory
  210. //----------------------------------
  211. /*
  212. // This depends on Poco and should be converted to Qt code
  213. Poco::File currentFile(filename);
  214. Poco::Path currentFilePath(filename);
  215. MITK_INFO << "currentFilePath.getFileName(): " << currentFilePath.getFileName() << "\n";
  216. if(moveFiles)
  217. {
  218. std::stringstream destDirectoryPath;
  219. if((dest_directory[dest_directory.length()-1] != '/') && (dest_directory[dest_directory.length()-1] != '\\'))
  220. destDirectoryPath << dest_directory << Poco::Path::separator() << seriesInstanceUID.c_str();
  221. else
  222. destDirectoryPath << dest_directory << seriesInstanceUID.c_str();
  223. MITK_INFO << "last symbol: " << dest_directory[dest_directory.length()-1]
  224. << "\ndestDirectoryPath: " << destDirectoryPath.str() << "\n";
  225. Poco::File directory(destDirectoryPath.str());
  226. if (!directory.exists()) directory.createDirectory();
  227. destDirectoryPath << Poco::Path::separator() << currentFilePath.getFileName();
  228. currentFile.moveTo(destDirectoryPath.str());
  229. //for testing only: copy file instead of moving
  230. //currentFile.copyTo(destDirectoryPath.str());
  231. }
  232. */
  233. //------------------------
  234. //Add Filename to Database
  235. //------------------------
  236. // std::stringstream relativeFilePath;
  237. // relativeFilePath << seriesInstanceUID.c_str() << "/" << currentFilePath.getFileName();
  238. QSqlQuery check_exists_query(database);
  239. std::stringstream check_exists_query_string;
  240. // check_exists_query_string << "SELECT * FROM Images WHERE Filename = '" << relativeFilePath.str() << "'";
  241. check_exists_query_string << "SELECT * FROM Images WHERE Filename = '" << filename << "'";
  242. check_exists_query.exec(check_exists_query_string.str().c_str());
  243. if(!check_exists_query.next())
  244. {
  245. std::stringstream query_string;
  246. //To save absolute path: destDirectoryPath.str()
  247. query_string << "INSERT INTO Images VALUES('"
  248. << /*relativeFilePath.str()*/ filename << "','" << seriesInstanceUID << "')";
  249. query.exec(query_string.str().c_str());
  250. }
  251. }
  252. // db.commit();
  253. // db.close();
  254. }