|
@@ -33,6 +33,7 @@
|
|
|
|
|
|
|
|
|
// ctkDICOM includes
|
|
|
+#include "ctkLogger.h"
|
|
|
#include "ctkDICOMIndexer.h"
|
|
|
#include "ctkDICOMAbstractThumbnailGenerator.h"
|
|
|
|
|
@@ -49,8 +50,9 @@
|
|
|
#include <dcmtk/dcmimage/diregist.h> /* include support for color images */
|
|
|
|
|
|
|
|
|
-#define MITK_ERROR std::cout
|
|
|
-#define MITK_INFO std::cout
|
|
|
+//------------------------------------------------------------------------------
|
|
|
+static ctkLogger logger("org.commontk.dicom.DICOMIndexer" );
|
|
|
+//------------------------------------------------------------------------------
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
class ctkDICOMIndexerPrivate
|
|
@@ -60,6 +62,15 @@ public:
|
|
|
~ctkDICOMIndexerPrivate();
|
|
|
|
|
|
ctkDICOMAbstractThumbnailGenerator* thumbnailGenerator;
|
|
|
+
|
|
|
+ /// these are for optimizing the import of image sequences
|
|
|
+ /// since most information are identical for all slices
|
|
|
+ OFString lastPatientID;
|
|
|
+ OFString lastPatientsName;
|
|
|
+ OFString lastPatientsBirthDate;
|
|
|
+ OFString lastStudyInstanceUID;
|
|
|
+ OFString lastSeriesInstanceUID;
|
|
|
+ int lastPatientUID;
|
|
|
};
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
@@ -69,6 +80,13 @@ public:
|
|
|
ctkDICOMIndexerPrivate::ctkDICOMIndexerPrivate()
|
|
|
{
|
|
|
this->thumbnailGenerator = NULL;
|
|
|
+
|
|
|
+ this->lastPatientID = "";
|
|
|
+ this->lastPatientsName = "";
|
|
|
+ this->lastPatientsBirthDate = "";
|
|
|
+ this->lastStudyInstanceUID = "";
|
|
|
+ this->lastSeriesInstanceUID = "";
|
|
|
+ this->lastPatientUID = -1;
|
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
@@ -93,364 +111,374 @@ ctkDICOMIndexer::~ctkDICOMIndexer()
|
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
-void ctkDICOMIndexer::addDirectory(ctkDICOMDatabase& database,
|
|
|
- const QString& directoryName,
|
|
|
+void ctkDICOMIndexer::addFile(ctkDICOMDatabase& ctkDICOMDatabase,
|
|
|
+ const QString& filePath,
|
|
|
const QString& destinationDirectoryName,
|
|
|
bool createHierarchy,
|
|
|
bool createThumbnails)
|
|
|
{
|
|
|
Q_D(ctkDICOMIndexer);
|
|
|
|
|
|
- QSqlDatabase db = database.database();
|
|
|
- const std::string src_directory(directoryName.toStdString());
|
|
|
-
|
|
|
- OFList<OFString> originalDcmtkFileNames;
|
|
|
- OFList<OFString> dcmtkFileNames;
|
|
|
- OFStandard::searchDirectoryRecursively( QDir::toNativeSeparators(src_directory.c_str()).toAscii().data(), originalDcmtkFileNames, "", "");
|
|
|
-
|
|
|
- // hack to reverse list of filenames (not neccessary when image loading works correctly)
|
|
|
- for ( OFListIterator(OFString) iter = originalDcmtkFileNames.begin(); iter != originalDcmtkFileNames.end(); ++iter )
|
|
|
- {
|
|
|
- dcmtkFileNames.push_front( *iter );
|
|
|
- }
|
|
|
+ logger.setDebug();
|
|
|
|
|
|
DcmFileFormat fileformat;
|
|
|
DcmDataset *dataset;
|
|
|
|
|
|
- OFListIterator(OFString) iter = dcmtkFileNames.begin();
|
|
|
- OFListIterator(OFString) last = dcmtkFileNames.end();
|
|
|
+ QSqlQuery query(ctkDICOMDatabase.database());
|
|
|
|
|
|
- if(iter == last) return;
|
|
|
+ std::string filename = filePath.toStdString();
|
|
|
|
|
|
- QSqlQuery query(database.database());
|
|
|
+ emit indexingFilePath(filePath);
|
|
|
|
|
|
+ /// first we check if the file is already in the database
|
|
|
+ QSqlQuery fileExists(ctkDICOMDatabase.database());
|
|
|
+ fileExists.prepare("SELECT InsertTimestamp FROM Images WHERE Filename == ?");
|
|
|
+ fileExists.bindValue(0,filePath);
|
|
|
+ fileExists.exec();
|
|
|
+ if (
|
|
|
+ fileExists.next() &&
|
|
|
+ QFileInfo(filePath).lastModified() < QDateTime::fromString(fileExists.value(0).toString(),Qt::ISODate)
|
|
|
+ )
|
|
|
+ {
|
|
|
+ logger.debug( "File " + filePath + " already added.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- /// these are for optimizing the import of image sequences
|
|
|
- /// since most information are identical for all slices
|
|
|
- OFString lastPatientID = "";
|
|
|
- OFString lastPatientsName = "";
|
|
|
- OFString lastPatientsBirthDate = "";
|
|
|
- OFString lastStudyInstanceUID = "";
|
|
|
- OFString lastSeriesInstanceUID = "";
|
|
|
- int lastPatientUID = -1;
|
|
|
-
|
|
|
- /* iterate over all input filenames */
|
|
|
- while (iter != last)
|
|
|
- {
|
|
|
- std::string filename((*iter).c_str());
|
|
|
- QString qfilename(filename.c_str());
|
|
|
- /// first we check if the file is already in the database
|
|
|
- QSqlQuery fileExists(database.database());
|
|
|
- fileExists.prepare("SELECT InsertTimestamp FROM Images WHERE Filename == ?");
|
|
|
- fileExists.bindValue(0,qfilename);
|
|
|
- fileExists.exec();
|
|
|
- if (
|
|
|
- fileExists.next() &&
|
|
|
- QFileInfo(qfilename).lastModified() < QDateTime::fromString(fileExists.value(0).toString(),Qt::ISODate)
|
|
|
- )
|
|
|
- {
|
|
|
- MITK_INFO << "File " << filename << " already added.";
|
|
|
- continue;
|
|
|
- }
|
|
|
+ logger.debug( "Processing " + filePath );
|
|
|
+ OFCondition status = fileformat.loadFile(filename.c_str());
|
|
|
|
|
|
- MITK_INFO << filename << "\n";
|
|
|
- OFCondition status = fileformat.loadFile(filename.c_str());
|
|
|
- ++iter;
|
|
|
+ dataset = fileformat.getDataset();
|
|
|
|
|
|
- dataset = fileformat.getDataset();
|
|
|
+ if (!status.good())
|
|
|
+ {
|
|
|
+ logger.error( "Could not load " + filePath );
|
|
|
+ logger.error( "DCMTK says: " + QString(status.text()) );
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- if (!status.good())
|
|
|
- {
|
|
|
- MITK_ERROR << "Could not load " << filename << "\nDCMTK says: " << status.text();
|
|
|
- continue;
|
|
|
- }
|
|
|
+ OFString patientsName, patientID, patientsBirthDate, patientsBirthTime, patientsSex,
|
|
|
+ patientComments, patientsAge;
|
|
|
|
|
|
- OFString patientsName, patientID, patientsBirthDate, patientsBirthTime, patientsSex,
|
|
|
- patientComments, patientsAge;
|
|
|
+ OFString studyInstanceUID, studyID, studyDate, studyTime,
|
|
|
+ accessionNumber, modalitiesInStudy, institutionName, performingPhysiciansName, referringPhysician, studyDescription;
|
|
|
|
|
|
- OFString studyInstanceUID, studyID, studyDate, studyTime,
|
|
|
- accessionNumber, modalitiesInStudy, institutionName, performingPhysiciansName, referringPhysician, studyDescription;
|
|
|
+ OFString seriesInstanceUID, seriesDate, seriesTime,
|
|
|
+ seriesDescription, bodyPartExamined, frameOfReferenceUID,
|
|
|
+ contrastAgent, scanningSequence;
|
|
|
+ OFString instanceNumber, sopInstanceUID ;
|
|
|
|
|
|
- OFString seriesInstanceUID, seriesDate, seriesTime,
|
|
|
- seriesDescription, bodyPartExamined, frameOfReferenceUID,
|
|
|
- contrastAgent, scanningSequence;
|
|
|
- OFString instanceNumber, sopInstanceUID ;
|
|
|
+ Sint32 seriesNumber = 0, acquisitionNumber = 0, echoNumber = 0, temporalPosition = 0;
|
|
|
|
|
|
- Sint32 seriesNumber = 0, acquisitionNumber = 0, echoNumber = 0, temporalPosition = 0;
|
|
|
+ //The patient UID is a unique number within the database, generated by the sqlite autoincrement
|
|
|
+ //Thus, this is _not_ the DICOM Patient ID.
|
|
|
+ int patientUID = -1;
|
|
|
|
|
|
- //The patient UID is a unique number within the database, generated by the sqlite autoincrement
|
|
|
- //Thus, this is _not_ the DICOM Patient ID.
|
|
|
- int patientUID = -1;
|
|
|
+ //If the following fields can not be evaluated, cancel evaluation of the DICOM file
|
|
|
+ if (!dataset->findAndGetOFString(DCM_PatientName, patientsName).good())
|
|
|
+ {
|
|
|
+ logger.error( "Could not read DCM_PatientName from " + filePath );
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- //If the following fields can not be evaluated, cancel evaluation of the DICOM file
|
|
|
- if (!dataset->findAndGetOFString(DCM_PatientName, patientsName).good())
|
|
|
- {
|
|
|
- MITK_ERROR << "Could not read DCM_PatientName from " << filename;
|
|
|
- continue;
|
|
|
- }
|
|
|
+ if (!dataset->findAndGetOFString(DCM_StudyInstanceUID, studyInstanceUID).good())
|
|
|
+ {
|
|
|
+ logger.error( "Could not read DCM_StudyInstanceUID from " + filePath );
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- if (!dataset->findAndGetOFString(DCM_StudyInstanceUID, studyInstanceUID).good())
|
|
|
- {
|
|
|
- MITK_ERROR << "Could not read DCM_StudyInstanceUID from " << filename;
|
|
|
- continue;
|
|
|
- }
|
|
|
+ if (!dataset->findAndGetOFString(DCM_SeriesInstanceUID, seriesInstanceUID).good())
|
|
|
+ {
|
|
|
+ logger.error( "Could not read DCM_SeriesInstanceUID from " + filePath );
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- if (!dataset->findAndGetOFString(DCM_SeriesInstanceUID, seriesInstanceUID).good())
|
|
|
- {
|
|
|
- MITK_ERROR << "Could not read DCM_SeriesInstanceUID from " << filename;
|
|
|
- continue;
|
|
|
- }
|
|
|
+ if (!dataset->findAndGetOFString(DCM_SOPInstanceUID, sopInstanceUID).good())
|
|
|
+ {
|
|
|
+ logger.error( "Could not read DCM_SOPInstanceUID from " + filePath );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!dataset->findAndGetOFString(DCM_InstanceNumber, instanceNumber).good())
|
|
|
+ {
|
|
|
+ logger.error( "Could not read DCM_InstanceNumber from " + filePath );
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- if (!dataset->findAndGetOFString(DCM_SOPInstanceUID, sopInstanceUID).good())
|
|
|
- {
|
|
|
- MITK_ERROR << "Could not read DCM_SOPInstanceUID from " << filename;
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (!dataset->findAndGetOFString(DCM_InstanceNumber, instanceNumber).good())
|
|
|
- {
|
|
|
- MITK_ERROR << "Could not read DCM_InstanceNumber from " << filename;
|
|
|
- continue;
|
|
|
- }
|
|
|
|
|
|
+ dataset->findAndGetOFString(DCM_PatientID, patientID);
|
|
|
+ dataset->findAndGetOFString(DCM_PatientBirthDate, patientsBirthDate);
|
|
|
+ dataset->findAndGetOFString(DCM_PatientBirthTime, patientsBirthTime);
|
|
|
+ dataset->findAndGetOFString(DCM_PatientSex, patientsSex);
|
|
|
+ dataset->findAndGetOFString(DCM_PatientAge, patientsAge);
|
|
|
+ dataset->findAndGetOFString(DCM_PatientComments, patientComments);
|
|
|
+ dataset->findAndGetOFString(DCM_StudyID, studyID);
|
|
|
+ dataset->findAndGetOFString(DCM_StudyDate, studyDate);
|
|
|
+ dataset->findAndGetOFString(DCM_StudyTime, studyTime);
|
|
|
+ dataset->findAndGetOFString(DCM_AccessionNumber, accessionNumber);
|
|
|
+ dataset->findAndGetOFString(DCM_ModalitiesInStudy, modalitiesInStudy);
|
|
|
+ dataset->findAndGetOFString(DCM_InstitutionName, institutionName);
|
|
|
+ dataset->findAndGetOFString(DCM_PerformingPhysicianName, performingPhysiciansName);
|
|
|
+ dataset->findAndGetOFString(DCM_ReferringPhysicianName, referringPhysician);
|
|
|
+ dataset->findAndGetOFString(DCM_StudyDescription, studyDescription);
|
|
|
+
|
|
|
+ dataset->findAndGetOFString(DCM_SeriesDate, seriesDate);
|
|
|
+ dataset->findAndGetOFString(DCM_SeriesTime, seriesTime);
|
|
|
+ dataset->findAndGetOFString(DCM_SeriesDescription, seriesDescription);
|
|
|
+ dataset->findAndGetOFString(DCM_BodyPartExamined, bodyPartExamined);
|
|
|
+ dataset->findAndGetOFString(DCM_FrameOfReferenceUID, frameOfReferenceUID);
|
|
|
+ dataset->findAndGetOFString(DCM_ContrastBolusAgent, contrastAgent);
|
|
|
+ dataset->findAndGetOFString(DCM_ScanningSequence, scanningSequence);
|
|
|
+
|
|
|
+ dataset->findAndGetSint32(DCM_SeriesNumber, seriesNumber);
|
|
|
+ dataset->findAndGetSint32(DCM_AcquisitionNumber, acquisitionNumber);
|
|
|
+ dataset->findAndGetSint32(DCM_EchoNumbers, echoNumber);
|
|
|
+ dataset->findAndGetSint32(DCM_TemporalPositionIdentifier, temporalPosition);
|
|
|
+
|
|
|
+ logger.debug( "Adding new items to database:" );
|
|
|
+ logger.debug( "studyID: " + QString(studyID.c_str()) );
|
|
|
+ logger.debug( "seriesInstanceUID: " + QString(seriesInstanceUID.c_str()) );
|
|
|
+ logger.debug( "Patient's Name: " + QString(patientsName.c_str()) );
|
|
|
+
|
|
|
+ //-----------------------
|
|
|
+ //Add Patient to Database
|
|
|
+ //-----------------------
|
|
|
+
|
|
|
+ //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
|
|
|
+ bool patientExists = false;
|
|
|
+ if(d->lastPatientID.compare(patientID) || d->lastPatientsBirthDate.compare(patientsBirthDate) || d->lastPatientsName.compare(patientsName))
|
|
|
+ {
|
|
|
+ //Check if patient is already present in the db
|
|
|
+ QSqlQuery check_exists_query(ctkDICOMDatabase.database());
|
|
|
+ std::stringstream check_exists_query_string;
|
|
|
+ check_exists_query_string << "SELECT * FROM Patients WHERE PatientID = '" << patientID << "'";
|
|
|
+ check_exists_query.exec(check_exists_query_string.str().c_str());
|
|
|
|
|
|
- dataset->findAndGetOFString(DCM_PatientID, patientID);
|
|
|
- dataset->findAndGetOFString(DCM_PatientBirthDate, patientsBirthDate);
|
|
|
- dataset->findAndGetOFString(DCM_PatientBirthTime, patientsBirthTime);
|
|
|
- dataset->findAndGetOFString(DCM_PatientSex, patientsSex);
|
|
|
- dataset->findAndGetOFString(DCM_PatientAge, patientsAge);
|
|
|
- dataset->findAndGetOFString(DCM_PatientComments, patientComments);
|
|
|
- dataset->findAndGetOFString(DCM_StudyID, studyID);
|
|
|
- dataset->findAndGetOFString(DCM_StudyDate, studyDate);
|
|
|
- dataset->findAndGetOFString(DCM_StudyTime, studyTime);
|
|
|
- dataset->findAndGetOFString(DCM_AccessionNumber, accessionNumber);
|
|
|
- dataset->findAndGetOFString(DCM_ModalitiesInStudy, modalitiesInStudy);
|
|
|
- dataset->findAndGetOFString(DCM_InstitutionName, institutionName);
|
|
|
- dataset->findAndGetOFString(DCM_PerformingPhysicianName, performingPhysiciansName);
|
|
|
- dataset->findAndGetOFString(DCM_ReferringPhysicianName, referringPhysician);
|
|
|
- dataset->findAndGetOFString(DCM_StudyDescription, studyDescription);
|
|
|
-
|
|
|
- dataset->findAndGetOFString(DCM_SeriesDate, seriesDate);
|
|
|
- dataset->findAndGetOFString(DCM_SeriesTime, seriesTime);
|
|
|
- dataset->findAndGetOFString(DCM_SeriesDescription, seriesDescription);
|
|
|
- dataset->findAndGetOFString(DCM_BodyPartExamined, bodyPartExamined);
|
|
|
- dataset->findAndGetOFString(DCM_FrameOfReferenceUID, frameOfReferenceUID);
|
|
|
- dataset->findAndGetOFString(DCM_ContrastBolusAgent, contrastAgent);
|
|
|
- dataset->findAndGetOFString(DCM_ScanningSequence, scanningSequence);
|
|
|
-
|
|
|
- dataset->findAndGetSint32(DCM_SeriesNumber, seriesNumber);
|
|
|
- dataset->findAndGetSint32(DCM_AcquisitionNumber, acquisitionNumber);
|
|
|
- dataset->findAndGetSint32(DCM_EchoNumbers, echoNumber);
|
|
|
- dataset->findAndGetSint32(DCM_TemporalPositionIdentifier, temporalPosition);
|
|
|
-
|
|
|
- MITK_INFO << "Adding new items to database:";
|
|
|
- MITK_INFO << "studyID: " << studyID;
|
|
|
- MITK_INFO << "seriesInstanceUID: " << seriesInstanceUID;
|
|
|
- MITK_INFO << "Patient's Name: " << patientsName;
|
|
|
-
|
|
|
- //-----------------------
|
|
|
- //Add Patient to Database
|
|
|
- //-----------------------
|
|
|
-
|
|
|
- //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
|
|
|
- bool patientExists = false;
|
|
|
- if(lastPatientID.compare(patientID) || lastPatientsBirthDate.compare(patientsBirthDate) || lastPatientsName.compare(patientsName))
|
|
|
+ /// we check only patients with the same PatientID
|
|
|
+ /// PatientID is not unique in DICOM, so we also compare Name and BirthDate
|
|
|
+ /// and assume this is sufficient
|
|
|
+ while (check_exists_query.next())
|
|
|
{
|
|
|
- //Check if patient is already present in the db
|
|
|
- QSqlQuery check_exists_query(database.database());
|
|
|
- std::stringstream check_exists_query_string;
|
|
|
- check_exists_query_string << "SELECT * FROM Patients WHERE PatientID = '" << patientID << "'";
|
|
|
- check_exists_query.exec(check_exists_query_string.str().c_str());
|
|
|
-
|
|
|
- /// we check only patients with the same PatientID
|
|
|
- /// PatientID is not unique in DICOM, so we also compare Name and BirthDate
|
|
|
- /// and assume this is sufficient
|
|
|
- while (check_exists_query.next())
|
|
|
+ if (
|
|
|
+ check_exists_query.record().value("PatientsName").toString() == patientsName.c_str() &&
|
|
|
+ check_exists_query.record().value("PatientsBirthDate").toString() == patientsBirthDate.c_str()
|
|
|
+ )
|
|
|
{
|
|
|
- if (
|
|
|
- check_exists_query.record().value("PatientsName").toString() == patientsName.c_str() &&
|
|
|
- check_exists_query.record().value("PatientsBirthDate").toString() == patientsBirthDate.c_str()
|
|
|
- )
|
|
|
- {
|
|
|
- /// found it
|
|
|
- patientUID = check_exists_query.value(check_exists_query.record().indexOf("UID")).toInt();
|
|
|
- patientExists = true;
|
|
|
- break;
|
|
|
- }
|
|
|
+ /// found it
|
|
|
+ patientUID = check_exists_query.value(check_exists_query.record().indexOf("UID")).toInt();
|
|
|
+ patientExists = true;
|
|
|
+ break;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- if(!patientExists)
|
|
|
- {
|
|
|
+ if(!patientExists)
|
|
|
+ {
|
|
|
|
|
|
- std::stringstream query_string;
|
|
|
+ std::stringstream query_string;
|
|
|
|
|
|
- query_string << "INSERT INTO Patients VALUES( NULL,'"
|
|
|
- << patientsName << "','"
|
|
|
- << patientID << "','"
|
|
|
- << patientsBirthDate << "','"
|
|
|
- << patientsBirthTime << "','"
|
|
|
- << patientsSex << "','"
|
|
|
- << patientsAge << "','"
|
|
|
- << patientComments << "')";
|
|
|
+ query_string << "INSERT INTO Patients VALUES( NULL,'"
|
|
|
+ << patientsName << "','"
|
|
|
+ << patientID << "','"
|
|
|
+ << patientsBirthDate << "','"
|
|
|
+ << patientsBirthTime << "','"
|
|
|
+ << patientsSex << "','"
|
|
|
+ << patientsAge << "','"
|
|
|
+ << patientComments << "')";
|
|
|
|
|
|
- query.exec(query_string.str().c_str());
|
|
|
+ query.exec(query_string.str().c_str());
|
|
|
|
|
|
- patientUID = query.lastInsertId().toInt();
|
|
|
- MITK_INFO << "New patient inserted: " << patientUID << "\n";
|
|
|
- }
|
|
|
+ patientUID = query.lastInsertId().toInt();
|
|
|
+ QString patientUIDQString;
|
|
|
+ patientUIDQString.setNum(patientUID);
|
|
|
+ logger.debug( "New patient inserted: " + patientUIDQString );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ patientUID = d->lastPatientUID;
|
|
|
}
|
|
|
- else
|
|
|
- {
|
|
|
- patientUID = lastPatientUID;
|
|
|
- }
|
|
|
|
|
|
- /// keep this for the next image
|
|
|
- lastPatientUID = patientUID;
|
|
|
- lastPatientID = patientID;
|
|
|
- lastPatientsBirthDate = patientsBirthDate;
|
|
|
- lastPatientsName = patientsName;
|
|
|
+ /// keep this for the next image
|
|
|
+ d->lastPatientUID = patientUID;
|
|
|
+ d->lastPatientID = patientID;
|
|
|
+ d->lastPatientsBirthDate = patientsBirthDate;
|
|
|
+ d->lastPatientsName = patientsName;
|
|
|
|
|
|
- //---------------------
|
|
|
- //Add Study to Database
|
|
|
- //---------------------
|
|
|
+ //---------------------
|
|
|
+ //Add Study to Database
|
|
|
+ //---------------------
|
|
|
|
|
|
- if(lastStudyInstanceUID.compare(studyInstanceUID))
|
|
|
+ if(d->lastStudyInstanceUID.compare(studyInstanceUID))
|
|
|
+ {
|
|
|
+ QSqlQuery check_exists_query(ctkDICOMDatabase.database());
|
|
|
+ std::stringstream check_exists_query_string;
|
|
|
+ check_exists_query_string << "SELECT * FROM Studies WHERE StudyInstanceUID = '" << studyInstanceUID << "'";
|
|
|
+ check_exists_query.exec(check_exists_query_string.str().c_str());
|
|
|
+
|
|
|
+ if(!check_exists_query.next())
|
|
|
{
|
|
|
- QSqlQuery check_exists_query(database.database());
|
|
|
- std::stringstream check_exists_query_string;
|
|
|
- check_exists_query_string << "SELECT * FROM Studies WHERE StudyInstanceUID = '" << studyInstanceUID << "'";
|
|
|
- check_exists_query.exec(check_exists_query_string.str().c_str());
|
|
|
|
|
|
- if(!check_exists_query.next())
|
|
|
- {
|
|
|
+ std::stringstream query_string;
|
|
|
|
|
|
- std::stringstream query_string;
|
|
|
-
|
|
|
- query_string << "INSERT INTO Studies VALUES('"
|
|
|
- << studyInstanceUID << "','"
|
|
|
- << patientUID << "','"
|
|
|
- << studyID << "','"
|
|
|
- << QDate::fromString(studyDate.c_str(), "yyyyMMdd").toString("yyyy-MM-dd").toStdString() << "','"
|
|
|
- << studyTime << "','"
|
|
|
- << accessionNumber << "','"
|
|
|
- << modalitiesInStudy << "','"
|
|
|
- << institutionName << "','"
|
|
|
- << referringPhysician << "','"
|
|
|
- << performingPhysiciansName << "','"
|
|
|
- << studyDescription << "')";
|
|
|
-
|
|
|
- query.exec(query_string.str().c_str());
|
|
|
- }
|
|
|
+ query_string << "INSERT INTO Studies VALUES('"
|
|
|
+ << studyInstanceUID << "','"
|
|
|
+ << patientUID << "','"
|
|
|
+ << studyID << "','"
|
|
|
+ << QDate::fromString(studyDate.c_str(), "yyyyMMdd").toString("yyyy-MM-dd").toStdString() << "','"
|
|
|
+ << studyTime << "','"
|
|
|
+ << accessionNumber << "','"
|
|
|
+ << modalitiesInStudy << "','"
|
|
|
+ << institutionName << "','"
|
|
|
+ << referringPhysician << "','"
|
|
|
+ << performingPhysiciansName << "','"
|
|
|
+ << studyDescription << "')";
|
|
|
+
|
|
|
+ query.exec(query_string.str().c_str());
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ d->lastStudyInstanceUID = studyInstanceUID;
|
|
|
|
|
|
- lastStudyInstanceUID = studyInstanceUID;
|
|
|
+ //----------------------
|
|
|
+ //Add Series to Database
|
|
|
+ //----------------------
|
|
|
|
|
|
- //----------------------
|
|
|
- //Add Series to Database
|
|
|
- //----------------------
|
|
|
+ if(d->lastSeriesInstanceUID.compare(seriesInstanceUID))
|
|
|
+ {
|
|
|
|
|
|
- if(lastSeriesInstanceUID.compare(seriesInstanceUID))
|
|
|
+ QSqlQuery check_exists_query(ctkDICOMDatabase.database());
|
|
|
+ std::stringstream check_exists_query_string;
|
|
|
+ check_exists_query_string << "SELECT * FROM Series WHERE SeriesInstanceUID = '" << seriesInstanceUID << "'";
|
|
|
+ check_exists_query.exec(check_exists_query_string.str().c_str());
|
|
|
+
|
|
|
+ if(!check_exists_query.next())
|
|
|
{
|
|
|
|
|
|
- QSqlQuery check_exists_query(database.database());
|
|
|
- std::stringstream check_exists_query_string;
|
|
|
- check_exists_query_string << "SELECT * FROM Series WHERE SeriesInstanceUID = '" << seriesInstanceUID << "'";
|
|
|
- check_exists_query.exec(check_exists_query_string.str().c_str());
|
|
|
+ std::stringstream query_string;
|
|
|
|
|
|
- if(!check_exists_query.next())
|
|
|
- {
|
|
|
+ query_string << "INSERT INTO Series VALUES('"
|
|
|
+ << seriesInstanceUID << "','"
|
|
|
+ << studyInstanceUID << "','"
|
|
|
+ << static_cast<int>(seriesNumber) << "','"
|
|
|
+ << QDate::fromString(seriesDate.c_str(), "yyyyMMdd").toString("yyyy-MM-dd").toStdString() << "','"
|
|
|
+ << seriesTime << "','"
|
|
|
+ << seriesDescription << "','"
|
|
|
+ << bodyPartExamined << "','"
|
|
|
+ << frameOfReferenceUID << "','"
|
|
|
+ << static_cast<int>(acquisitionNumber) << "','"
|
|
|
+ << contrastAgent << "','"
|
|
|
+ << scanningSequence << "','"
|
|
|
+ << static_cast<int>(echoNumber) << "','"
|
|
|
+ << static_cast<int>(temporalPosition) << "')";
|
|
|
|
|
|
- std::stringstream query_string;
|
|
|
-
|
|
|
- query_string << "INSERT INTO Series VALUES('"
|
|
|
- << seriesInstanceUID << "','"
|
|
|
- << studyInstanceUID << "','"
|
|
|
- << static_cast<int>(seriesNumber) << "','"
|
|
|
- << QDate::fromString(seriesDate.c_str(), "yyyyMMdd").toString("yyyy-MM-dd").toStdString() << "','"
|
|
|
- << seriesTime << "','"
|
|
|
- << seriesDescription << "','"
|
|
|
- << bodyPartExamined << "','"
|
|
|
- << frameOfReferenceUID << "','"
|
|
|
- << static_cast<int>(acquisitionNumber) << "','"
|
|
|
- << contrastAgent << "','"
|
|
|
- << scanningSequence << "','"
|
|
|
- << static_cast<int>(echoNumber) << "','"
|
|
|
- << static_cast<int>(temporalPosition) << "')";
|
|
|
-
|
|
|
- query.exec(query_string.str().c_str());
|
|
|
- }
|
|
|
+ query.exec(query_string.str().c_str());
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- lastSeriesInstanceUID = seriesInstanceUID;
|
|
|
+ d->lastSeriesInstanceUID = seriesInstanceUID;
|
|
|
|
|
|
- QString studySeriesDirectory = QString(studyInstanceUID.c_str()) + "/" + seriesInstanceUID.c_str();
|
|
|
+ QString studySeriesDirectory = QString(studyInstanceUID.c_str()) + "/" + seriesInstanceUID.c_str();
|
|
|
|
|
|
- //----------------------------------
|
|
|
- //Move file to destination directory
|
|
|
- //----------------------------------
|
|
|
+ //----------------------------------
|
|
|
+ //Move file to destination directory
|
|
|
+ //----------------------------------
|
|
|
|
|
|
- if (!destinationDirectoryName.isEmpty())
|
|
|
- {
|
|
|
- QFile currentFile( qfilename );
|
|
|
- QDir destinationDir(destinationDirectoryName + "/dicom");
|
|
|
- QString destFileName = sopInstanceUID.c_str();
|
|
|
- if (createHierarchy)
|
|
|
- {
|
|
|
- destinationDir.mkpath(studySeriesDirectory);
|
|
|
- destFileName.prepend( destinationDir.absolutePath() + "/" + studySeriesDirectory + "/" );
|
|
|
- }
|
|
|
- currentFile.copy(destFileName);
|
|
|
- qfilename = destFileName;
|
|
|
+ QString finalFilePath(filePath);
|
|
|
+ if (!destinationDirectoryName.isEmpty())
|
|
|
+ {
|
|
|
+ QFile currentFile( filePath );
|
|
|
+ QDir destinationDir(destinationDirectoryName + "/dicom");
|
|
|
+ QString finalFilePath = sopInstanceUID.c_str();
|
|
|
+ if (createHierarchy)
|
|
|
+ {
|
|
|
+ destinationDir.mkpath(studySeriesDirectory);
|
|
|
+ finalFilePath.prepend( destinationDir.absolutePath() + "/" + studySeriesDirectory + "/" );
|
|
|
}
|
|
|
+ currentFile.copy(finalFilePath);
|
|
|
+ }
|
|
|
|
|
|
- if (createThumbnails)
|
|
|
+ if (createThumbnails)
|
|
|
+ {
|
|
|
+ if(d->thumbnailGenerator)
|
|
|
{
|
|
|
- if(d->thumbnailGenerator){
|
|
|
- QString thumbnailBaseDir = database.databaseDirectory() + "/thumbs/";
|
|
|
- QString thumbnailFilename = thumbnailBaseDir + "/" + database.pathForDataset(dataset) + ".png";
|
|
|
- QFileInfo thumbnailInfo(thumbnailFilename);
|
|
|
- if ( ! ( thumbnailInfo.exists() && thumbnailInfo.lastModified() < QFileInfo(qfilename).lastModified() ) )
|
|
|
- {
|
|
|
- QDir(thumbnailBaseDir).mkpath(studySeriesDirectory);
|
|
|
- DicomImage dcmtkImage(QDir::toNativeSeparators(qfilename).toStdString().c_str());
|
|
|
- d->thumbnailGenerator->generateThumbnail(&dcmtkImage, thumbnailFilename);
|
|
|
- }
|
|
|
- }
|
|
|
+ QString thumbnailBaseDir = ctkDICOMDatabase.databaseDirectory() + "/thumbs/";
|
|
|
+ QString thumbnailFilename = thumbnailBaseDir + "/" + ctkDICOMDatabase.pathForDataset(dataset) + ".png";
|
|
|
+ QFileInfo thumbnailInfo(thumbnailFilename);
|
|
|
+ if ( ! ( thumbnailInfo.exists() && thumbnailInfo.lastModified() < QFileInfo(finalFilePath).lastModified() ) )
|
|
|
+ {
|
|
|
+ QDir(thumbnailBaseDir).mkpath(studySeriesDirectory);
|
|
|
+ DicomImage dcmtkImage(QDir::toNativeSeparators(finalFilePath).toStdString().c_str());
|
|
|
+ d->thumbnailGenerator->generateThumbnail(&dcmtkImage, thumbnailFilename);
|
|
|
+ }
|
|
|
}
|
|
|
- //------------------------
|
|
|
- //Add Filename to Database
|
|
|
- //------------------------
|
|
|
+ }
|
|
|
+
|
|
|
+ //------------------------
|
|
|
+ //Add Filename to Database
|
|
|
+ //------------------------
|
|
|
|
|
|
// std::stringstream relativeFilePath;
|
|
|
// relativeFilePath << seriesInstanceUID.c_str() << "/" << currentFilePath.getFileName();
|
|
|
|
|
|
- QSqlQuery check_exists_query(database.database());
|
|
|
- std::stringstream check_exists_query_string;
|
|
|
+ QSqlQuery check_exists_query(ctkDICOMDatabase.database());
|
|
|
+ std::stringstream check_exists_query_string;
|
|
|
// check_exists_query_string << "SELECT * FROM Images WHERE Filename = '" << relativeFilePath.str() << "'";
|
|
|
- check_exists_query_string << "SELECT * FROM Images WHERE SOPInstanceUID = '" << sopInstanceUID << "'";
|
|
|
- check_exists_query.exec(check_exists_query_string.str().c_str());
|
|
|
+ check_exists_query_string << "SELECT * FROM Images WHERE SOPInstanceUID = '" << sopInstanceUID << "'";
|
|
|
+ check_exists_query.exec(check_exists_query_string.str().c_str());
|
|
|
|
|
|
- if(!check_exists_query.next())
|
|
|
- {
|
|
|
- std::stringstream query_string;
|
|
|
+ if(!check_exists_query.next())
|
|
|
+ {
|
|
|
+ std::stringstream query_string;
|
|
|
|
|
|
- //To save absolute path: destDirectoryPath.str()
|
|
|
- query_string << "INSERT INTO Images VALUES('"
|
|
|
- << sopInstanceUID << "','" << qfilename.toStdString() << "','" << seriesInstanceUID << "','" << QDateTime::currentDateTime().toString(Qt::ISODate).toStdString() << "')";
|
|
|
+ //To save absolute path: destDirectoryPath.str()
|
|
|
+ query_string << "INSERT INTO Images VALUES('"
|
|
|
+ << sopInstanceUID << "','" << finalFilePath.toStdString() << "','" << seriesInstanceUID << "','" << QDateTime::currentDateTime().toString(Qt::ISODate).toStdString() << "')";
|
|
|
|
|
|
- query.exec(query_string.str().c_str());
|
|
|
- }
|
|
|
+ query.exec(query_string.str().c_str());
|
|
|
}
|
|
|
|
|
|
- // db.commit();
|
|
|
- // db.close();
|
|
|
+}
|
|
|
+
|
|
|
+//------------------------------------------------------------------------------
|
|
|
+void ctkDICOMIndexer::addDirectory(ctkDICOMDatabase& ctkDICOMDatabase,
|
|
|
+ const QString& directoryName,
|
|
|
+ const QString& destinationDirectoryName,
|
|
|
+ bool createHierarchy,
|
|
|
+ bool createThumbnails)
|
|
|
+{
|
|
|
+ const std::string src_directory(directoryName.toStdString());
|
|
|
+
|
|
|
+ OFList<OFString> originalDcmtkFileNames;
|
|
|
+ OFList<OFString> dcmtkFileNames;
|
|
|
+ OFStandard::searchDirectoryRecursively( QDir::toNativeSeparators(src_directory.c_str()).toAscii().data(), originalDcmtkFileNames, "", "");
|
|
|
|
|
|
+ // hack to reverse list of filenames (not neccessary when image loading works correctly)
|
|
|
+ for ( OFListIterator(OFString) iter = originalDcmtkFileNames.begin(); iter != originalDcmtkFileNames.end(); ++iter )
|
|
|
+ {
|
|
|
+ dcmtkFileNames.push_front( *iter );
|
|
|
+ }
|
|
|
+
|
|
|
+ OFListIterator(OFString) iter = dcmtkFileNames.begin();
|
|
|
+ OFListIterator(OFString) last = dcmtkFileNames.end();
|
|
|
+
|
|
|
+ if(iter == last) return;
|
|
|
+
|
|
|
+ emit foundFilesToIndex(dcmtkFileNames.size());
|
|
|
+
|
|
|
+ /* iterate over all input filenames */
|
|
|
+ int fileNumber = 0;
|
|
|
+ while (iter != last)
|
|
|
+ {
|
|
|
+ emit indexingFileNumber(++fileNumber);
|
|
|
+ QString filePath((*iter).c_str());
|
|
|
+ this->addFile(ctkDICOMDatabase, filePath, destinationDirectoryName, createHierarchy, createThumbnails);
|
|
|
+ ++iter;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
-void ctkDICOMIndexer::refreshDatabase(ctkDICOMDatabase& database, const QString& directoryName)
|
|
|
+void ctkDICOMIndexer::refreshDatabase(ctkDICOMDatabase& ctkDICOMDatabase, const QString& directoryName)
|
|
|
{
|
|
|
/// get all filenames from the database
|
|
|
- QSqlQuery allFilesQuery(database.database());
|
|
|
+ QSqlQuery allFilesQuery(ctkDICOMDatabase.database());
|
|
|
QStringList databaseFileNames;
|
|
|
QStringList filesToRemove;
|
|
|
allFilesQuery.exec("SELECT Filename from Images;");
|
|
@@ -471,6 +499,11 @@ void ctkDICOMIndexer::refreshDatabase(ctkDICOMDatabase& database, const QString&
|
|
|
{
|
|
|
filesytemFiles.insert(dirIt.next());
|
|
|
}
|
|
|
+
|
|
|
+ // TODO: it looks like this function was never finished...
|
|
|
+ //
|
|
|
+ // I guess the next step is to remove all filesToRemove from the database
|
|
|
+ // and also to add filesystemFiles into the database tables
|
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|