//----------------------------------------------------------------------------- void ctkVTKHistogram::setRange(qreal minRange, qreal maxRange) { Q_D(const ctkVTKHistogram); if (d->DataArray.GetPointer() == 0) { //Q_ASSERT(d->DataArray.GetPointer()); logger.warn("no data array. range will be reset when setting array."); minRange = 1.; // set incorrect values maxRange = 0.; return; } if (minRange >= maxRange) { //Q_ASSERT(d->DataArray.GetPointer()); logger.warn("minRange >= maxRange"); qreal pivot = minRange; minRange = maxRange; maxRange = pivot; } int numberOfBinsBefore = d->computeNumberOfBins(); d->Range[0] = minRange; d->Range[1] = maxRange; if (d->computeNumberOfBins() != numberOfBinsBefore) { this->build(); } }
//------------------------------------------------------------------------------ void ctkDICOMDatabase::insert ( const QString& filePath, bool storeFile, bool generateThumbnail, bool createHierarchy, const QString& destinationDirectoryName) { Q_D(ctkDICOMDatabase); Q_UNUSED(createHierarchy); Q_UNUSED(destinationDirectoryName); /// first we check if the file is already in the database if (fileExistsAndUpToDate(filePath)) { logger.debug( "File " + filePath + " already added."); return; } logger.debug( "Processing " + filePath ); std::string filename = filePath.toStdString(); DcmFileFormat fileformat; ctkDICOMDataset ctkDataset; ctkDataset.InitializeFromFile(filePath); if ( ctkDataset.IsInitialized() ) { d->insert( ctkDataset, filePath, storeFile, generateThumbnail ); } else { logger.warn(QString("Could not read DICOM file:") + filePath); } }
//----------------------------------------------------------------------------- QVariant ctkVTKColorTransferFunction::maxValue()const { Q_D(const ctkVTKColorTransferFunction); if (d->ColorTransferFunction.GetPointer() == 0) { //Q_ASSERT(d->ColorTransferFunction.GetPointer()); logger.warn("no ColorTransferFunction"); return -1; } double rgb[3]; QColor minValue = QColor::fromRgbF(0.,0.,0.); for (int i = 0; i < this->count(); ++i) { d->ColorTransferFunction->GetColor(i, rgb); Q_ASSERT(rgb[0] >= 0. && rgb[0] <= 1. && rgb[1] >= 0. && rgb[1] <= 1. && rgb[2] >= 0. && rgb[2] <= 1.); QColor color = QColor::fromRgbF(rgb[0], rgb[1], rgb[2]); if ( qGray(color.red(), color.green(), color.blue()) > qGray(minValue.red(), minValue.green(), minValue.blue())) { minValue = color; } } return minValue; }
//----------------------------------------------------------------------------- void ctkVTKHistogram::resetRange() { Q_D(ctkVTKHistogram); if (d->DataArray.GetPointer() == 0) { //Q_ASSERT(d->DataArray.GetPointer()); logger.warn("no dataArray"); d->Range[0] = 1.; // set incorrect values d->Range[1] = 0.; return; } if (d->DataArray->GetDataType() == VTK_CHAR || d->DataArray->GetDataType() == VTK_SIGNED_CHAR || d->DataArray->GetDataType() == VTK_UNSIGNED_CHAR) { d->Range[0] = d->DataArray->GetDataTypeMin(); d->Range[1] = d->DataArray->GetDataTypeMax(); } else { d->DataArray->GetRange(d->Range, d->Component); if (d->DataArray->GetDataType() == VTK_FLOAT || d->DataArray->GetDataType() == VTK_DOUBLE) { d->Range[1] += 0.01; } //else // { // this->Range[1] += 1; // } } }
//----------------------------------------------------------------------------- void ctkVTKHistogram::range(qreal& minRange, qreal& maxRange)const { Q_D(const ctkVTKHistogram); if (d->DataArray.GetPointer() == 0) { //Q_ASSERT(d->DataArray.GetPointer()); logger.warn("no dataArray"); minRange = 1.; // set incorrect values maxRange = 0.; return; } minRange = d->Range[0]; maxRange = d->Range[1]; }
//------------------------------------------------------------------------------ void ctkDICOMIndexer::addFile(ctkDICOMDatabase& database, const QString filePath, const QString& destinationDirectoryName) { std::cout << filePath.toStdString(); if (!destinationDirectoryName.isEmpty()) { logger.warn("Ignoring destinationDirectoryName parameter, just taking it as indication we should copy!"); } emit indexingFilePath(filePath); database.insert(filePath, !destinationDirectoryName.isEmpty(), true); }
//----------------------------------------------------------------------------- void ctkVTKColorTransferFunction::range(qreal& minRange, qreal& maxRange)const { Q_D(const ctkVTKColorTransferFunction); if (d->ColorTransferFunction.GetPointer() == 0) { //Q_ASSERT(d->ColorTransferFunction.GetPointer()); logger.warn("no ColorTransferFunction"); minRange = 1.; maxRange = 0.; return; } double rangeValues[2]; d->ColorTransferFunction->GetRange(rangeValues); minRange = rangeValues[0]; maxRange = rangeValues[1]; }
// -------------------------------------------------------------------------- void ctkSettingsPanel::setSetting(const QString& key, const QVariant& newVal) { Q_D(ctkSettingsPanel); QSettings* settings = d->settings(key); if (!settings) { return; } QVariant oldVal = settings->value(key); settings->setValue(key, newVal); d->Properties[key].setValue(newVal); if (settings->status() != QSettings::NoError) { logger.warn( QString("Error #%1 while writing setting \"%2\"") .arg(static_cast<int>(settings->status())) .arg(key)); } if (oldVal != newVal) { emit settingChanged(key, newVal); } }
//------------------------------------------------------------------------------ void ctkDICOMDatabase::insert ( DcmDataset *dataset, bool storeFile, bool generateThumbnail) { Q_D(ctkDICOMDatabase); if (!dataset) { return; } // Check to see if the file has already been loaded OFString sopInstanceUID ; dataset->findAndGetOFString(DCM_SOPInstanceUID, sopInstanceUID); QSqlQuery fileExists ( d->Database ); fileExists.prepare("SELECT InsertTimestamp,Filename FROM Images WHERE SOPInstanceUID == ?"); fileExists.bindValue(0,QString(sopInstanceUID.c_str())); fileExists.exec(); if ( fileExists.next() && QFileInfo(fileExists.value(1).toString()).lastModified() < QDateTime::fromString(fileExists.value(0).toString(),Qt::ISODate) ) { logger.debug ( "File " + fileExists.value(1).toString() + " already added" ); return; } OFString patientsName, patientID, patientsBirthDate, patientsBirthTime, patientsSex, patientComments, patientsAge; OFString studyInstanceUID, studyID, studyDate, studyTime, accessionNumber, modalitiesInStudy, institutionName, performingPhysiciansName, referringPhysician, studyDescription; OFString seriesInstanceUID, seriesDate, seriesTime, seriesDescription, bodyPartExamined, frameOfReferenceUID, contrastAgent, scanningSequence; OFString instanceNumber; Sint32 seriesNumber = 0, acquisitionNumber = 0, echoNumber = 0, temporalPosition = 0; //If the following fields can not be evaluated, cancel evaluation of the DICOM file dataset->findAndGetOFString(DCM_PatientName, patientsName); dataset->findAndGetOFString(DCM_StudyInstanceUID, studyInstanceUID); dataset->findAndGetOFString(DCM_SeriesInstanceUID, seriesInstanceUID); 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); // store the file if the database is not in memomry QString filename; if ( storeFile && !this->isInMemory() ) { DcmFileFormat* fileformat = new DcmFileFormat ( dataset ); QString destinationDirectoryName = databaseDirectory() + "/dicom/"; QDir destinationDir(destinationDirectoryName); QString studySeriesDirectory = QString(studyInstanceUID.c_str()) + "/" + seriesInstanceUID.c_str(); destinationDir.mkpath(studySeriesDirectory); filename = databaseDirectory() + "/dicom/" + pathForDataset(dataset); logger.debug ( "Saving file: " + filename ); OFCondition status = fileformat->saveFile ( filename.toAscii() ); if ( !status.good() ) { logger.error ( "Error saving file: " + filename + "\nError is " + status.text() ); delete fileformat; return; } delete fileformat; } QSqlQuery check_exists_query(d->Database); //The patient UID is a unique number within the database, generated by the sqlite autoincrement int patientUID = -1; if ( patientID != "" && patientsName != "" ) { //Check if patient is already present in the db check_exists_query.prepare ( "SELECT * FROM Patients WHERE PatientID = ? AND PatientsName = ?" ); check_exists_query.bindValue ( 0, QString ( patientID.c_str() ) ); check_exists_query.bindValue ( 1, QString ( patientsName.c_str() ) ); check_exists_query.exec(); if (check_exists_query.next()) { patientUID = check_exists_query.value(check_exists_query.record().indexOf("UID")).toInt(); } else { // Insert it QSqlQuery statement ( d->Database ); statement.prepare ( "INSERT INTO Patients ('UID', 'PatientsName', 'PatientID', 'PatientsBirthDate', 'PatientsBirthTime', 'PatientsSex', 'PatientsAge', 'PatientsComments' ) values ( NULL, ?, ?, ?, ?, ?, ?, ? )" ); statement.bindValue ( 0, QString ( patientsName.c_str() ) ); statement.bindValue ( 1, QString ( patientID.c_str() ) ); statement.bindValue ( 2, QString ( patientsBirthDate.c_str() ) ); statement.bindValue ( 3, QString ( patientsBirthTime.c_str() ) ); statement.bindValue ( 4, QString ( patientsSex.c_str() ) ); // TODO: shift patient's age to study, since this is not a patient level attribute in images // statement.bindValue ( 5, QString ( patientsAge.c_str() ) ); statement.bindValue ( 6, QString ( patientComments.c_str() ) ); statement.exec (); patientUID = statement.lastInsertId().toInt(); logger.debug ( "New patient inserted: " + QString().setNum ( patientUID ) ); } } if ( studyInstanceUID != "" ) { check_exists_query.prepare ( "SELECT * FROM Studies WHERE StudyInstanceUID = ?" ); check_exists_query.bindValue ( 0, QString ( studyInstanceUID.c_str() ) ); check_exists_query.exec(); if(!check_exists_query.next()) { QSqlQuery statement ( d->Database ); statement.prepare ( "INSERT INTO Studies ( 'StudyInstanceUID', 'PatientsUID', 'StudyID', 'StudyDate', 'StudyTime', 'AccessionNumber', 'ModalitiesInStudy', 'InstitutionName', 'ReferringPhysician', 'PerformingPhysiciansName', 'StudyDescription' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" ); statement.bindValue ( 0, QString ( studyInstanceUID.c_str() ) ); statement.bindValue ( 1, patientUID ); statement.bindValue ( 2, QString ( studyID.c_str() ) ); statement.bindValue ( 3, QDate::fromString ( studyDate.c_str(), "yyyyMMdd" ) ); statement.bindValue ( 4, QString ( studyTime.c_str() ) ); statement.bindValue ( 5, QString ( accessionNumber.c_str() ) ); statement.bindValue ( 6, QString ( modalitiesInStudy.c_str() ) ); statement.bindValue ( 7, QString ( institutionName.c_str() ) ); statement.bindValue ( 8, QString ( referringPhysician.c_str() ) ); statement.bindValue ( 9, QString ( performingPhysiciansName.c_str() ) ); statement.bindValue ( 10, QString ( studyDescription.c_str() ) ); if ( !statement.exec() ) { logger.error ( "Error executing statament: " + statement.lastQuery() + " Error: " + statement.lastError().text() ); } } } if ( seriesInstanceUID != "" ) { check_exists_query.prepare ( "SELECT * FROM Series WHERE SeriesInstanceUID = ?" ); check_exists_query.bindValue ( 0, QString ( seriesInstanceUID.c_str() ) ); logger.warn ( "Statement: " + check_exists_query.lastQuery() ); check_exists_query.exec(); if(!check_exists_query.next()) { QSqlQuery statement ( d->Database ); statement.prepare ( "INSERT INTO Series ( 'SeriesInstanceUID', 'StudyInstanceUID', 'SeriesNumber', 'SeriesDate', 'SeriesTime', 'SeriesDescription', 'BodyPartExamined', 'FrameOfReferenceUID', 'AcquisitionNumber', 'ContrastAgent', 'ScanningSequence', 'EchoNumber', 'TemporalPosition' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" ); statement.bindValue ( 0, QString ( seriesInstanceUID.c_str() ) ); statement.bindValue ( 1, QString ( studyInstanceUID.c_str() ) ); statement.bindValue ( 2, static_cast<int>(seriesNumber) ); statement.bindValue ( 3, QString ( seriesDate.c_str() ) ); statement.bindValue ( 4, QDate::fromString ( seriesTime.c_str(), "yyyyMMdd" ) ); statement.bindValue ( 5, QString ( seriesDescription.c_str() ) ); statement.bindValue ( 6, QString ( bodyPartExamined.c_str() ) ); statement.bindValue ( 7, QString ( frameOfReferenceUID.c_str() ) ); statement.bindValue ( 8, static_cast<int>(acquisitionNumber) ); statement.bindValue ( 9, QString ( contrastAgent.c_str() ) ); statement.bindValue ( 10, QString ( scanningSequence.c_str() ) ); statement.bindValue ( 11, static_cast<int>(echoNumber) ); statement.bindValue ( 12, static_cast<int>(temporalPosition) ); if ( !statement.exec() ) { logger.error ( "Error executing statament: " + statement.lastQuery() + " Error: " + statement.lastError().text() ); } } } if ( !filename.isEmpty() ) { check_exists_query.prepare ( "SELECT * FROM Images WHERE Filename = ?" ); check_exists_query.bindValue ( 0, filename ); check_exists_query.exec(); if(!check_exists_query.next()) { QSqlQuery statement ( d->Database ); statement.prepare ( "INSERT INTO Images ( 'SOPInstanceUID', 'Filename', 'SeriesInstanceUID', 'InsertTimestamp' ) VALUES ( ?, ?, ?, ? )" ); statement.bindValue ( 0, QString ( sopInstanceUID.c_str() ) ); statement.bindValue ( 1, filename ); statement.bindValue ( 2, QString ( seriesInstanceUID.c_str() ) ); statement.bindValue ( 3, QDateTime::currentDateTime() ); statement.exec(); } } if(generateThumbnail){ if(d->thumbnailGenerator){ QString studySeriesDirectory = QString(studyInstanceUID.c_str()) + "/" + QString(seriesInstanceUID.c_str()); //Create thumbnail here QString thumbnailPath = databaseDirectory() + "/thumbs/" + this->pathForDataset(dataset) + ".png"; //QString(studyInstanceUID.c_str()) + "/" + //QString(seriesInstanceUID.c_str()) + "/" + //QString(sopInstanceUID.c_str()) + ".png"; QFileInfo thumbnailInfo(thumbnailPath); if(!(thumbnailInfo.exists() && (thumbnailInfo.lastModified() > QFileInfo(filename).lastModified()))){ QDir(databaseDirectory() + "/thumbs/").mkpath(studySeriesDirectory); DicomImage dcmImage(QDir::toNativeSeparators(filename).toAscii()); d->thumbnailGenerator->generateThumbnail(&dcmImage, thumbnailPath); } } } if (isInMemory()) { emit databaseChanged(); } }
bool ctkDICOMDatabase::removeSeries(const QString& seriesInstanceUID) { Q_D(ctkDICOMDatabase); // get all images from series QSqlQuery fileExists ( d->Database ); fileExists.prepare("SELECT Filename, SOPInstanceUID, StudyInstanceUID FROM Images,Series WHERE Series.SeriesInstanceUID = Images.SeriesInstanceUID AND Images.SeriesInstanceUID = :seriesID"); fileExists.bindValue(":seriesID",seriesInstanceUID); bool success = fileExists.exec(); if (!success) { logger.error("SQLITE ERROR: " + fileExists.lastError().driverText()); return false; } QList< QPair<QString,QString> > removeList; while ( fileExists.next() ) { QString dbFilePath = fileExists.value(fileExists.record().indexOf("Filename")).toString(); QString sopInstanceUID = fileExists.value(fileExists.record().indexOf("SOPInstanceUID")).toString(); QString studyInstanceUID = fileExists.value(fileExists.record().indexOf("StudyInstanceUID")).toString(); QString internalFilePath = studyInstanceUID + "/" + seriesInstanceUID + "/" + sopInstanceUID; removeList << qMakePair(dbFilePath,internalFilePath); } QSqlQuery fileRemove ( d->Database ); fileRemove.prepare("DELETE FROM Images WHERE SeriesInstanceUID == :seriesID"); fileRemove.bindValue(":seriesID",seriesInstanceUID); logger.debug("SQLITE: removing seriesInstanceUID " + seriesInstanceUID); success = fileRemove.exec(); if (!success) { logger.error("SQLITE ERROR: could not remove seriesInstanceUID " + seriesInstanceUID); logger.error("SQLITE ERROR: " + fileRemove.lastError().driverText()); } QPair<QString,QString> fileToRemove; foreach (fileToRemove, removeList) { QString dbFilePath = fileToRemove.first; QString thumbnailToRemove = databaseDirectory() + "/thumbs/" + fileToRemove.second + ".png"; // check that the file is below our internal storage if (dbFilePath.startsWith( databaseDirectory() + "/dicom/")) { if (!dbFilePath.endsWith(fileToRemove.second)) { logger.error("Database inconsistency detected during delete!"); continue; } if (QFile( dbFilePath ).remove()) { logger.debug("Removed file " + dbFilePath ); } else { logger.warn("Failed to remove file " + dbFilePath ); } } if (QFile( thumbnailToRemove ).remove()) { logger.debug("Removed thumbnail " + thumbnailToRemove); } else { logger.warn("Failed to remove thumbnail " + thumbnailToRemove); } }
//------------------------------------------------------------------------------ void ctkDICOMDatabasePrivate::insert( const ctkDICOMDataset& ctkDataset, const QString& filePath, bool storeFile, bool generateThumbnail) { Q_Q(ctkDICOMDatabase); // Check to see if the file has already been loaded // TODO: // It could make sense to actually remove the dataset and re-add it. This needs the remove // method we still have to write. // QString sopInstanceUID ( ctkDataset.GetElementAsString(DCM_SOPInstanceUID) ); QSqlQuery fileExists ( Database ); fileExists.prepare("SELECT InsertTimestamp,Filename FROM Images WHERE SOPInstanceUID == :sopInstanceUID"); fileExists.bindValue(":sopInstanceUID",sopInstanceUID); bool success = fileExists.exec(); if (!success) { logger.error("SQLITE ERROR: " + fileExists.lastError().driverText()); return; } qDebug() << "filename is: " << fileExists.value(1).toString(); qDebug() << "modified date is: " << QFileInfo(fileExists.value(1).toString()).lastModified(); qDebug() << "db mod date is: " << QDateTime::fromString(fileExists.value(0).toString(),Qt::ISODate); if ( fileExists.next() && QFileInfo(fileExists.value(1).toString()).lastModified() < QDateTime::fromString(fileExists.value(0).toString(),Qt::ISODate) ) { logger.debug ( "File " + fileExists.value(1).toString() + " already added" ); return; } //If the following fields can not be evaluated, cancel evaluation of the DICOM file QString patientsName(ctkDataset.GetElementAsString(DCM_PatientName) ); QString studyInstanceUID(ctkDataset.GetElementAsString(DCM_StudyInstanceUID) ); QString seriesInstanceUID(ctkDataset.GetElementAsString(DCM_SeriesInstanceUID) ); QString patientID(ctkDataset.GetElementAsString(DCM_PatientID) ); if ( patientsName.isEmpty() && !patientID.isEmpty() ) { // Use patient id as name if name is empty - can happen on anonymized datasets // see: http://www.na-mic.org/Bug/view.php?id=1643 patientsName = patientID; } if ( patientsName.isEmpty() || studyInstanceUID.isEmpty() || patientID.isEmpty() ) { logger.error("Dataset is missing necessary information!"); return; } QString patientsBirthDate(ctkDataset.GetElementAsString(DCM_PatientBirthDate) ); QString patientsBirthTime(ctkDataset.GetElementAsString(DCM_PatientBirthTime) ); QString patientsSex(ctkDataset.GetElementAsString(DCM_PatientSex) ); QString patientsAge(ctkDataset.GetElementAsString(DCM_PatientAge) ); QString patientComments(ctkDataset.GetElementAsString(DCM_PatientComments) ); QString studyID(ctkDataset.GetElementAsString(DCM_StudyID) ); QString studyDate(ctkDataset.GetElementAsString(DCM_StudyDate) ); QString studyTime(ctkDataset.GetElementAsString(DCM_StudyTime) ); QString accessionNumber(ctkDataset.GetElementAsString(DCM_AccessionNumber) ); QString modalitiesInStudy(ctkDataset.GetElementAsString(DCM_ModalitiesInStudy) ); QString institutionName(ctkDataset.GetElementAsString(DCM_InstitutionName) ); QString performingPhysiciansName(ctkDataset.GetElementAsString(DCM_PerformingPhysicianName) ); QString referringPhysician(ctkDataset.GetElementAsString(DCM_ReferringPhysicianName) ); QString studyDescription(ctkDataset.GetElementAsString(DCM_StudyDescription) ); QString seriesDate(ctkDataset.GetElementAsString(DCM_SeriesDate) ); QString seriesTime(ctkDataset.GetElementAsString(DCM_SeriesTime) ); QString seriesDescription(ctkDataset.GetElementAsString(DCM_SeriesDescription) ); QString bodyPartExamined(ctkDataset.GetElementAsString(DCM_BodyPartExamined) ); QString frameOfReferenceUID(ctkDataset.GetElementAsString(DCM_FrameOfReferenceUID) ); QString contrastAgent(ctkDataset.GetElementAsString(DCM_ContrastBolusAgent) ); QString scanningSequence(ctkDataset.GetElementAsString(DCM_ScanningSequence) ); long seriesNumber(ctkDataset.GetElementAsInteger(DCM_SeriesNumber) ); long acquisitionNumber(ctkDataset.GetElementAsInteger(DCM_AcquisitionNumber) ); long echoNumber(ctkDataset.GetElementAsInteger(DCM_EchoNumbers) ); long temporalPosition(ctkDataset.GetElementAsInteger(DCM_TemporalPositionIdentifier) ); // store the file if the database is not in memomry // TODO: if we are called from insert(file) we // have to do something else // QString filename = filePath; if ( storeFile && !q->isInMemory() && !seriesInstanceUID.isEmpty() ) { // QString studySeriesDirectory = studyInstanceUID + "/" + seriesInstanceUID; QString destinationDirectoryName = q->databaseDirectory() + "/dicom/"; QDir destinationDir(destinationDirectoryName); filename = destinationDirectoryName + studyInstanceUID + "/" + seriesInstanceUID + "/" + sopInstanceUID; destinationDir.mkpath(studyInstanceUID + "/" + seriesInstanceUID); if(filePath.isEmpty()) { logger.debug ( "Saving file: " + filename ); if ( !ctkDataset.SaveToFile( filename) ) { logger.error ( "Error saving file: " + filename ); return; } } else { // we're inserting an existing file QFile currentFile( filePath ); currentFile.copy(filename); logger.debug( "Copy file from: " + filePath ); logger.debug( "Copy file to : " + filename ); } } QSqlQuery checkPatientExistsQuery(Database); //The dbPatientID is a unique number within the database, //generated by the sqlite autoincrement //The patientID is the (non-unique) DICOM patient id int dbPatientID = -1; if ( patientID != "" && patientsName != "" ) { //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 if ( lastPatientID != patientID || lastPatientsBirthDate != patientsBirthDate || lastPatientsName != patientsName ) { // Ok, something is different from last insert, let's insert him if he's not // already in the db. // // Check if patient is already present in the db // TODO: maybe add birthdate check for extra safety checkPatientExistsQuery.prepare ( "SELECT * FROM Patients WHERE PatientID = ? AND PatientsName = ?" ); checkPatientExistsQuery.bindValue ( 0, patientID ); checkPatientExistsQuery.bindValue ( 1, patientsName ); loggedExec(checkPatientExistsQuery); if (checkPatientExistsQuery.next()) { // we found him dbPatientID = checkPatientExistsQuery.value(checkPatientExistsQuery.record().indexOf("UID")).toInt(); } else { // Insert it QSqlQuery insertPatientStatement ( Database ); insertPatientStatement.prepare ( "INSERT INTO Patients ('UID', 'PatientsName', 'PatientID', 'PatientsBirthDate', 'PatientsBirthTime', 'PatientsSex', 'PatientsAge', 'PatientsComments' ) values ( NULL, ?, ?, ?, ?, ?, ?, ? )" ); insertPatientStatement.bindValue ( 0, patientsName ); insertPatientStatement.bindValue ( 1, patientID ); insertPatientStatement.bindValue ( 2, patientsBirthDate ); insertPatientStatement.bindValue ( 3, patientsBirthTime ); insertPatientStatement.bindValue ( 4, patientsSex ); // TODO: shift patient's age to study, // since this is not a patient level attribute in images // insertPatientStatement.bindValue ( 5, patientsAge ); insertPatientStatement.bindValue ( 6, patientComments ); loggedExec(insertPatientStatement); dbPatientID = insertPatientStatement.lastInsertId().toInt(); logger.debug ( "New patient inserted: " + QString().setNum ( dbPatientID ) ); } /// keep this for the next image lastPatientUID = dbPatientID; lastPatientID = patientID; lastPatientsBirthDate = patientsBirthDate; lastPatientsName = patientsName; } // Patient is in now. Let's continue with the study if ( studyInstanceUID != "" && lastStudyInstanceUID != studyInstanceUID ) { QSqlQuery checkStudyExistsQuery (Database); checkStudyExistsQuery.prepare ( "SELECT * FROM Studies WHERE StudyInstanceUID = ?" ); checkStudyExistsQuery.bindValue ( 0, studyInstanceUID ); checkStudyExistsQuery.exec(); if(!checkStudyExistsQuery.next()) { QSqlQuery insertStudyStatement ( Database ); insertStudyStatement.prepare ( "INSERT INTO Studies ( 'StudyInstanceUID', 'PatientsUID', 'StudyID', 'StudyDate', 'StudyTime', 'AccessionNumber', 'ModalitiesInStudy', 'InstitutionName', 'ReferringPhysician', 'PerformingPhysiciansName', 'StudyDescription' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" ); insertStudyStatement.bindValue ( 0, studyInstanceUID ); insertStudyStatement.bindValue ( 1, dbPatientID ); insertStudyStatement.bindValue ( 2, studyID ); insertStudyStatement.bindValue ( 3, QDate::fromString ( studyDate, "yyyyMMdd" ) ); insertStudyStatement.bindValue ( 4, studyTime ); insertStudyStatement.bindValue ( 5, accessionNumber ); insertStudyStatement.bindValue ( 6, modalitiesInStudy ); insertStudyStatement.bindValue ( 7, institutionName ); insertStudyStatement.bindValue ( 8, referringPhysician ); insertStudyStatement.bindValue ( 9, performingPhysiciansName ); insertStudyStatement.bindValue ( 10, studyDescription ); if ( !insertStudyStatement.exec() ) { logger.error ( "Error executing statament: " + insertStudyStatement.lastQuery() + " Error: " + insertStudyStatement.lastError().text() ); } else { lastStudyInstanceUID = studyInstanceUID; } } } if ( seriesInstanceUID != "" && seriesInstanceUID != lastSeriesInstanceUID ) { QSqlQuery checkSeriesExistsQuery (Database); checkSeriesExistsQuery.prepare ( "SELECT * FROM Series WHERE SeriesInstanceUID = ?" ); checkSeriesExistsQuery.bindValue ( 0, seriesInstanceUID ); logger.warn ( "Statement: " + checkSeriesExistsQuery.lastQuery() ); loggedExec(checkSeriesExistsQuery); if(!checkSeriesExistsQuery.next()) { QSqlQuery insertSeriesStatement ( Database ); insertSeriesStatement.prepare ( "INSERT INTO Series ( 'SeriesInstanceUID', 'StudyInstanceUID', 'SeriesNumber', 'SeriesDate', 'SeriesTime', 'SeriesDescription', 'BodyPartExamined', 'FrameOfReferenceUID', 'AcquisitionNumber', 'ContrastAgent', 'ScanningSequence', 'EchoNumber', 'TemporalPosition' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" ); insertSeriesStatement.bindValue ( 0, seriesInstanceUID ); insertSeriesStatement.bindValue ( 1, studyInstanceUID ); insertSeriesStatement.bindValue ( 2, static_cast<int>(seriesNumber) ); insertSeriesStatement.bindValue ( 3, seriesDate ); insertSeriesStatement.bindValue ( 4, QDate::fromString ( seriesTime, "yyyyMMdd" ) ); insertSeriesStatement.bindValue ( 5, seriesDescription ); insertSeriesStatement.bindValue ( 6, bodyPartExamined ); insertSeriesStatement.bindValue ( 7, frameOfReferenceUID ); insertSeriesStatement.bindValue ( 8, static_cast<int>(acquisitionNumber) ); insertSeriesStatement.bindValue ( 9, contrastAgent ); insertSeriesStatement.bindValue ( 10, scanningSequence ); insertSeriesStatement.bindValue ( 11, static_cast<int>(echoNumber) ); insertSeriesStatement.bindValue ( 12, static_cast<int>(temporalPosition) ); if ( !insertSeriesStatement.exec() ) { logger.error ( "Error executing statament: " + insertSeriesStatement.lastQuery() + " Error: " + insertSeriesStatement.lastError().text() ); lastSeriesInstanceUID = ""; } else { lastSeriesInstanceUID = seriesInstanceUID; } } } // TODO: what to do with imported files // if ( !filename.isEmpty() && !seriesInstanceUID.isEmpty() ) { QSqlQuery checkImageExistsQuery (Database); checkImageExistsQuery.prepare ( "SELECT * FROM Images WHERE Filename = ?" ); checkImageExistsQuery.bindValue ( 0, filename ); checkImageExistsQuery.exec(); if(!checkImageExistsQuery.next()) { QSqlQuery insertImageStatement ( Database ); insertImageStatement.prepare ( "INSERT INTO Images ( 'SOPInstanceUID', 'Filename', 'SeriesInstanceUID', 'InsertTimestamp' ) VALUES ( ?, ?, ?, ? )" ); insertImageStatement.bindValue ( 0, sopInstanceUID ); insertImageStatement.bindValue ( 1, filename ); insertImageStatement.bindValue ( 2, seriesInstanceUID ); insertImageStatement.bindValue ( 3, QDateTime::currentDateTime() ); insertImageStatement.exec(); } } if( generateThumbnail && thumbnailGenerator && !seriesInstanceUID.isEmpty() ) { QString studySeriesDirectory = studyInstanceUID + "/" + seriesInstanceUID; //Create thumbnail here QString thumbnailPath = q->databaseDirectory() + "/thumbs/" + studyInstanceUID + "/" + seriesInstanceUID + "/" + sopInstanceUID + ".png"; QFileInfo thumbnailInfo(thumbnailPath); if( !(thumbnailInfo.exists() && (thumbnailInfo.lastModified() > QFileInfo(filename).lastModified()))) { QDir(q->databaseDirectory() + "/thumbs/").mkpath(studySeriesDirectory); DicomImage dcmImage(QDir::toNativeSeparators(filename).toAscii()); thumbnailGenerator->generateThumbnail(&dcmImage, thumbnailPath); } } if (q->isInMemory()) { emit q->databaseChanged(); } } }
void ctkDICOMIndexerBase::insert ( DcmDataset *dataset, QString filename ) { CTK_D(ctkDICOMIndexerBase); // Check to see if the file has already been loaded QSqlQuery fileExists ( d->db ); fileExists.prepare("SELECT InsertTimestamp FROM Images WHERE Filename == ?"); fileExists.bindValue(0,filename); fileExists.exec(); if ( fileExists.next() && QFileInfo(filename).lastModified() < QDateTime::fromString(fileExists.value(0).toString(),Qt::ISODate) ) { logger.debug ( "File " + filename + " already added" ); return; } OFString patientsName, patientID, patientsBirthDate, patientsBirthTime, patientsSex, patientComments, patientsAge; OFString studyInstanceUID, studyID, studyDate, studyTime, accessionNumber, modalitiesInStudy, institutionName, performingPhysiciansName, referringPhysician, studyDescription; OFString seriesInstanceUID, seriesDate, seriesTime, seriesDescription, bodyPartExamined, frameOfReferenceUID, contrastAgent, scanningSequence; OFString instanceNumber; Sint32 seriesNumber = 0, acquisitionNumber = 0, echoNumber = 0, temporalPosition = 0; //If the following fields can not be evaluated, cancel evaluation of the DICOM file dataset->findAndGetOFString(DCM_PatientsName, patientsName); dataset->findAndGetOFString(DCM_StudyInstanceUID, studyInstanceUID); dataset->findAndGetOFString(DCM_SeriesInstanceUID, seriesInstanceUID); dataset->findAndGetOFString(DCM_PatientID, patientID); dataset->findAndGetOFString(DCM_PatientsBirthDate, patientsBirthDate); dataset->findAndGetOFString(DCM_PatientsBirthTime, patientsBirthTime); dataset->findAndGetOFString(DCM_PatientsSex, patientsSex); dataset->findAndGetOFString(DCM_PatientsAge, 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_PerformingPhysiciansName, performingPhysiciansName); dataset->findAndGetOFString(DCM_ReferringPhysiciansName, 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); QSqlQuery check_exists_query(d->db); //The patient UID is a unique number within the database, generated by the sqlite autoincrement int patientUID = -1; if ( patientID != "" && patientsName != "" ) { //Check if patient is already present in the db check_exists_query.prepare ( "SELECT * FROM Patients WHERE PatientID = ? AND PatientsName = ?" ); check_exists_query.bindValue ( 0, QString ( patientID.c_str() ) ); check_exists_query.bindValue ( 1, QString ( patientsName.c_str() ) ); check_exists_query.exec(); if (check_exists_query.next()) { patientUID = check_exists_query.value(check_exists_query.record().indexOf("UID")).toInt(); } else { // Insert it QSqlQuery statement ( d->db ); statement.prepare ( "INSERT INTO Patients ('UID', 'PatientsName', 'PatientID', 'PatientsBirthDate', 'PatientsBirthTime', 'PatientsSex', 'PatientsAge', 'PatientsComments' ) values ( NULL, ?, ?, ?, ?, ?, ?, ? )" ); statement.bindValue ( 0, QString ( patientsName.c_str() ) ); statement.bindValue ( 1, QString ( patientID.c_str() ) ); statement.bindValue ( 2, QString ( patientsBirthDate.c_str() ) ); statement.bindValue ( 3, QString ( patientsBirthTime.c_str() ) ); statement.bindValue ( 4, QString ( patientsSex.c_str() ) ); statement.bindValue ( 5, QString ( patientsAge.c_str() ) ); statement.bindValue ( 6, QString ( patientComments.c_str() ) ); statement.exec (); patientUID = statement.lastInsertId().toInt(); logger.debug ( "New patient inserted: " + QString().setNum ( patientUID ) ); } } if ( studyInstanceUID != "" ) { check_exists_query.prepare ( "SELECT * FROM Studies WHERE StudyInstanceUID = ?" ); check_exists_query.bindValue ( 0, QString ( studyInstanceUID.c_str() ) ); check_exists_query.exec(); if(!check_exists_query.next()) { QSqlQuery statement ( d->db ); statement.prepare ( "INSERT INTO Studies ( 'StudyInstanceUID', 'PatientsUID', 'StudyID', 'StudyDate', 'StudyTime', 'AccessionNumber', 'ModalitiesInStudy', 'InstitutionName', 'ReferringPhysician', 'PerformingPhysiciansName', 'StudyDescription' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" ); statement.bindValue ( 0, QString ( studyInstanceUID.c_str() ) ); statement.bindValue ( 1, patientUID ); statement.bindValue ( 2, QString ( studyID.c_str() ) ); statement.bindValue ( 3, QDate::fromString ( studyDate.c_str(), "yyyyMMdd" ) ); statement.bindValue ( 4, QString ( studyTime.c_str() ) ); statement.bindValue ( 5, QString ( accessionNumber.c_str() ) ); statement.bindValue ( 6, QString ( modalitiesInStudy.c_str() ) ); statement.bindValue ( 7, QString ( institutionName.c_str() ) ); statement.bindValue ( 8, QString ( referringPhysician.c_str() ) ); statement.bindValue ( 9, QString ( performingPhysiciansName.c_str() ) ); statement.bindValue ( 10, QString ( studyDescription.c_str() ) ); if ( !statement.exec() ) { logger.error ( "Error executing statament: " + statement.lastQuery() + " Error: " + statement.lastError().text() ); } } } if ( seriesInstanceUID != "" ) { check_exists_query.prepare ( "SELECT * FROM Series WHERE SeriesInstanceUID = ?" ); check_exists_query.bindValue ( 0, QString ( seriesInstanceUID.c_str() ) ); logger.warn ( "Statement: " + check_exists_query.lastQuery() ); check_exists_query.exec(); if(!check_exists_query.next()) { QSqlQuery statement ( d->db ); statement.prepare ( "INSERT INTO Series ( 'SeriesInstanceUID', 'StudyInstanceUID', 'SeriesNumber', 'SeriesDate', 'SeriesTime', 'SeriesDescription', 'BodyPartExamined', 'FrameOfReferenceUID', 'AcquisitionNumber', 'ContrastAgent', 'ScanningSequence', 'EchoNumber', 'TemporalPosition' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" ); statement.bindValue ( 0, QString ( seriesInstanceUID.c_str() ) ); statement.bindValue ( 1, QString ( studyInstanceUID.c_str() ) ); statement.bindValue ( 2, static_cast<int>(seriesNumber) ); statement.bindValue ( 3, QString ( seriesDate.c_str() ) ); statement.bindValue ( 4, QDate::fromString ( seriesTime.c_str(), "yyyyMMdd" ) ); statement.bindValue ( 5, QString ( seriesDescription.c_str() ) ); statement.bindValue ( 6, QString ( bodyPartExamined.c_str() ) ); statement.bindValue ( 7, QString ( frameOfReferenceUID.c_str() ) ); statement.bindValue ( 8, static_cast<int>(acquisitionNumber) ); statement.bindValue ( 9, QString ( contrastAgent.c_str() ) ); statement.bindValue ( 10, QString ( scanningSequence.c_str() ) ); statement.bindValue ( 11, static_cast<int>(echoNumber) ); statement.bindValue ( 12, static_cast<int>(temporalPosition) ); if ( !statement.exec() ) { logger.error ( "Error executing statament: " + statement.lastQuery() + " Error: " + statement.lastError().text() ); } } } if ( !filename.isEmpty() ) { check_exists_query.prepare ( "SELECT * FROM Images WHERE Filename = ?" ); check_exists_query.bindValue ( 0, filename ); check_exists_query.exec(); if(!check_exists_query.next()) { QSqlQuery statement ( d->db ); statement.prepare ( "INSERT INTO Images ( 'Filename', 'SeriesInstanceUID', 'InsertTimestamp' ) VALUES ( ?, ?, ? )" ); statement.bindValue ( 0, filename ); statement.bindValue ( 1, QString ( seriesInstanceUID.c_str() ) ); statement.bindValue ( 2, QDateTime::currentDateTime() ); statement.exec(); } } }