瀏覽代碼

Add cached accessors and helper methods

Should improve performance for multiple accesses to the
same element values in different parts of the code and
accross runs of the application.
Steve Pieper 13 年之前
父節點
當前提交
8dad059d2b

+ 13 - 6
Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp

@@ -67,11 +67,11 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] )
     {
     std::cerr << "ctkDICOMDatabase::openDatabase() failed: "
               << "database should not be in memory" << std::endl;
-    return EXIT_FAILURE;    
+    return EXIT_FAILURE;
     }
 
   bool res = database.initializeDatabase();
-  
+
   if (!res)
     {
     std::cerr << "ctkDICOMDatabase::initializeDatabase() failed." << std::endl;
@@ -104,7 +104,6 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] )
     }
 
 
-
   //
   // Basic test:
   // - insert the file specified on the command line
@@ -120,7 +119,15 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] )
     std::cerr << "ctkDICOMDatabase: didn't get back the original file path" << std::endl;
     return EXIT_FAILURE;
     }
-  
+
+  QString foundInstance = database.instanceForFile(dicomFilePath);
+
+  if (foundInstance != instanceUID)
+    {
+    std::cerr << "ctkDICOMDatabase: didn't get back the original instance uid" << std::endl;
+    return EXIT_FAILURE;
+    }
+
 
   QString knownSeriesDescription("3D Cor T1 FAST IR-prepped GRE");
 
@@ -160,13 +167,13 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] )
     return EXIT_FAILURE;
     }
 
-  if (!database.cacheTag(instanceUID, tag, knownSeriesDescription)) 
+  if (!database.cacheTag(instanceUID, tag, knownSeriesDescription))
     {
     std::cerr << "ctkDICOMDatabase: could not insert instance tag" << std::endl;
     return EXIT_FAILURE;
     }
 
-  if (database.cachedTag(instanceUID, tag) != knownSeriesDescription) 
+  if (database.cachedTag(instanceUID, tag) != knownSeriesDescription)
     {
     std::cerr << "ctkDICOMDatabase: could not retrieve cached tag" << std::endl;
     return EXIT_FAILURE;

+ 62 - 3
Libs/DICOM/Core/ctkDICOMDatabase.cpp

@@ -335,6 +335,10 @@ void ctkDICOMDatabase::closeDatabase()
   d->Database.close();
 }
 
+//
+// Patient/study/series convenience methods
+//
+
 //------------------------------------------------------------------------------
 QStringList ctkDICOMDatabase::patients()
 {
@@ -407,13 +411,33 @@ QString ctkDICOMDatabase::fileForInstance(QString sopInstanceUID)
   query.bindValue ( 0, sopInstanceUID );
   query.exec();
   QString result;
-  if (query.next()) 
+  if (query.next())
+    {
+    result = query.value(0).toString();
+    }
+  return( result );
+}
+
+//------------------------------------------------------------------------------
+QString ctkDICOMDatabase::instanceForFile(QString fileName)
+{
+  Q_D(ctkDICOMDatabase);
+  QSqlQuery query(d->Database);
+  query.prepare ( "SELECT SOPInstanceUID FROM Images WHERE Filename=?");
+  query.bindValue ( 0, fileName );
+  query.exec();
+  QString result;
+  if (query.next())
     {
     result = query.value(0).toString();
     }
   return( result );
 }
 
+//
+// instance header methods
+//
+
 //------------------------------------------------------------------------------
 void ctkDICOMDatabase::loadInstanceHeader (QString sopInstanceUID)
 {
@@ -469,9 +493,18 @@ QString ctkDICOMDatabase::headerValue (QString key)
   return (d->LoadedHeader[key]);
 }
 
+//
+// instanceValue and fileValue methods
+//
+
 //------------------------------------------------------------------------------
 QString ctkDICOMDatabase::instanceValue(QString sopInstanceUID, QString tag)
 {
+  QString value = this->cachedTag(sopInstanceUID, tag);
+  if (value != "")
+    {
+    return value;
+    }
   unsigned short group, element;
   this->tagToGroupElement(tag, group, element);
   return( this->instanceValue(sopInstanceUID, group, element) );
@@ -480,6 +513,12 @@ QString ctkDICOMDatabase::instanceValue(QString sopInstanceUID, QString tag)
 //------------------------------------------------------------------------------
 QString ctkDICOMDatabase::instanceValue(const QString sopInstanceUID, const unsigned short group, const unsigned short element)
 {
+  QString tag = this->groupElementToTag(group,element);
+  QString value = this->cachedTag(sopInstanceUID, tag);
+  if (value != "")
+    {
+    return value;
+    }
   QString filePath = this->fileForInstance(sopInstanceUID);
   if (filePath != "" )
     {
@@ -497,6 +536,12 @@ QString ctkDICOMDatabase::fileValue(const QString fileName, QString tag)
 {
   unsigned short group, element;
   this->tagToGroupElement(tag, group, element);
+  QString sopInstanceUID = this->instanceForFile(fileName);
+  QString value = this->cachedTag(sopInstanceUID, tag);
+  if (value != "")
+    {
+    return value;
+    }
   return( this->fileValue(fileName, group, element) );
 }
 
@@ -504,6 +549,8 @@ QString ctkDICOMDatabase::fileValue(const QString fileName, QString tag)
 QString ctkDICOMDatabase::fileValue(const QString fileName, const unsigned short group, const unsigned short element)
 {
   // here is where the real lookup happens
+  // - first we check the tagCache to see if the value exists for this instance tag
+  // If not,
   // - for now we create a ctkDICOMDataset and extract the value from there
   // - then we convert to the appropriate type of string
   //
@@ -514,9 +561,17 @@ QString ctkDICOMDatabase::fileValue(const QString fileName, const unsigned short
   //   -- if so, keep looking for the requested group/element
   //   -- if not, start again from the begining
 
+  QString tag = this->groupElementToTag(group, element);
+  QString sopInstanceUID = this->instanceForFile(fileName);
+  QString value = this->cachedTag(sopInstanceUID, tag);
+  if (value != "")
+    {
+    return value;
+    }
+
   ctkDICOMDataset dataset;
   dataset.InitializeFromFile(fileName);
-  
+
   DcmTagKey tagKey(group, element);
 
   return( dataset.GetAllElementValuesAsString(tagKey) );
@@ -539,6 +594,10 @@ QString ctkDICOMDatabase::groupElementToTag(const unsigned short& group, const u
   return QString("%1,%2").arg(group,4,16,QLatin1Char('0')).arg(element,4,16,QLatin1Char('0'));
 }
 
+//
+// methods related to insert
+//
+
 //------------------------------------------------------------------------------
 void ctkDICOMDatabase::insert( DcmDataset *dataset, bool storeFile, bool generateThumbnail)
 {
@@ -1169,7 +1228,7 @@ QString ctkDICOMDatabase::cachedTag(const QString sopInstanceUID, const QString
   selectValue.bindValue(":tag",tag);
   d->loggedExec(selectValue);
   QString result("");
-  if (selectValue.next()) 
+  if (selectValue.next())
     {
     result = selectValue.value(0).toString();
     }

+ 1 - 0
Libs/DICOM/Core/ctkDICOMDatabase.h

@@ -117,6 +117,7 @@ public:
   Q_INVOKABLE QStringList seriesForStudy (const QString studyUID);
   Q_INVOKABLE QStringList filesForSeries (const QString seriesUID);
   Q_INVOKABLE QString fileForInstance (const QString sopInstanceUID);
+  Q_INVOKABLE QString instanceForFile (const QString fileName);
 
   ///
   /// \brief load the header from a file and allow access to elements