Beispiel #1
0
//------------------------------------------------------------------------------
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);
  }
}
Beispiel #2
0
//-----------------------------------------------------------------------------
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();
    }
}
Beispiel #3
0
//------------------------------------------------------------------------------
bool ctkDICOMRetrievePrivate::initializeSCU( const QString& studyInstanceUID,
                                         const QString& seriesInstanceUID,
                                         const RetrieveType retrieveType,
                                         DcmDataset *retrieveParameters)
{
  if ( !this->Database )
    {
    logger.error ( "No Database for retrieve transaction" );
    return false;
    }

  // If we like to query another server than before, be sure to disconnect first
  if (this->SCU.isConnected() && this->ConnectionParamsChanged)
  {
    this->SCU.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
  }
  // Connect to server if not already connected
  if (!this->SCU.isConnected())
    {
    // Check and initialize networking parameters in DCMTK
    if ( !this->SCU.initNetwork().good() )
      {
      logger.error ( "Error initializing the network" );
      return false;
      }
    // Negotiate (i.e. start the) association
    logger.debug ( "Negotiating Association" );

    if ( !this->SCU.negotiateAssociation().good() )
      {
      logger.error ( "Error negotiating association" );
      return false;;
      }
    }

  this->ConnectionParamsChanged = false;
  // Setup query about what to be received from the PACS
  logger.debug ( "Setting Retrieve Parameters" );
  if ( retrieveType == RetrieveSeries )
    {
    retrieveParameters->putAndInsertString ( DCM_QueryRetrieveLevel, "SERIES" );
    retrieveParameters->putAndInsertString ( DCM_SeriesInstanceUID, 
                                                seriesInstanceUID.toStdString().c_str() );
    // Always required to send all highler level unique keys, so add study here (we are in Study Root)
    retrieveParameters->putAndInsertString ( DCM_StudyInstanceUID, 
                                                studyInstanceUID.toStdString().c_str() );  //TODO
    }
  else
    {
    retrieveParameters->putAndInsertString ( DCM_QueryRetrieveLevel, "STUDY" );
    retrieveParameters->putAndInsertString ( DCM_StudyInstanceUID, 
                                                studyInstanceUID.toStdString().c_str() );
    }
  return true;
}
Beispiel #4
0
//------------------------------------------------------------------------------
bool ctkDICOMRetrieve::getStudy(const QString& studyInstanceUID)
{
  if (studyInstanceUID.isEmpty())
    {
    logger.error("Cannot receive series: Study Instance UID empty.");
    return false;
    }
  Q_D(ctkDICOMRetrieve);
  logger.info ( "Starting getStudy" );
  return d->get ( studyInstanceUID, "", ctkDICOMRetrievePrivate::RetrieveStudy );
}
Beispiel #5
0
//------------------------------------------------------------------------------
bool ctkDICOMRetrieve::getSeries(const QString& studyInstanceUID,
                                      const QString& seriesInstanceUID)
{
  if (studyInstanceUID.isEmpty() || seriesInstanceUID.isEmpty())
    {
    logger.error("Cannot receive series: Either Study or Series Instance UID empty.");
    return false;
    }
  Q_D(ctkDICOMRetrieve);
  logger.info ( "Starting getSeries" );
  return d->get ( studyInstanceUID, seriesInstanceUID, ctkDICOMRetrievePrivate::RetrieveSeries );
}
Beispiel #6
0
//-----------------------------------------------------------------------------
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;
    //  }
    }
}
Beispiel #7
0
// --------------------------------------------------------------------------
void ctkWorkflowStep::validate(const QString& desiredBranchId)
{
  Q_D(ctkWorkflowStep);
  logger.info(QString("validate - validating the input from %1").arg(d->Name));

  this->validationComplete(true, desiredBranchId);
}
//-----------------------------------------------------------------------------
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;
}
Beispiel #9
0
//----------------------------------------------------------------------------
void ctkVTKSliceView::forceRender()
{
  Q_D(ctkVTKSliceView);
  if (!d->RenderEnabled  || !this->isVisible())
    {
    return;
    }
  logger.trace("forceRender");
  d->RenderWindow->Render();
  d->RenderPending = false;
}
Beispiel #10
0
// --------------------------------------------------------------------------
void ctkWorkflowStep::setId(const QString& newId)
{
  Q_D(ctkWorkflowStep);
  if (d->Workflow && d->Workflow->hasStep(newId) && !this->id().isEmpty())
    {
    logger.error(QString("ctkWorkflowStep - Failed to change id from '%1' to '%2' - "
                         "Step already added to a workflow !").arg(this->id()).arg(newId));
    return;
    }
  d->Id = newId;
}
// --------------------------------------------------------------------------
void ctkWorkflowGroupBox::updateGroupBox(ctkWorkflowStep* currentStep)
{
  Q_D(ctkWorkflowGroupBox);

  d->StepShownPreviously = d->StepShownCurrently;
  d->StepShownCurrently = currentStep;

  if (currentStep)
    { 
    this->setTitle(currentStep->name());
    this->setSubTitle(currentStep->description());
    this->setErrorText(currentStep->statusText());

    // don't show textual elements if they are empty
    d->SubTitleTextBrowser->setVisible(!this->subTitle().isEmpty());
    d->PreTextBrowser->setVisible(!this->preText().isEmpty());
    d->PostTextBrowser->setVisible(!this->postText().isEmpty());
    d->ErrorTextBrowser->setVisible(!this->errorText().isEmpty());
    }

  // disable/hide the previously shown step
  if (ctkWorkflowWidgetStep* prevStep = dynamic_cast<ctkWorkflowWidgetStep*>(d->StepShownPreviously))
    {
    logger.debug(QString("updateClientArea - hiding %1").arg(prevStep->name()));
    if (QWidget* stepArea = prevStep->stepArea())
      {
      stepArea->setEnabled(false);
      if (d->HideWidgetsOfNonCurrentSteps)
        {
        stepArea->hide();
        }
      }
    }
  
  ctkWorkflowWidgetStep* currentWidgetStep = dynamic_cast<ctkWorkflowWidgetStep*>(currentStep);
  // show/enable the current step
  if (currentWidgetStep)
    {
    currentWidgetStep->showUserInterface();

    if (QWidget* stepArea = currentWidgetStep->stepArea())
      {
      // add the step's client area to the widget if we haven't before
      if (!this->isAncestorOf(stepArea))
        {
        d->ClientAreaLayout->addWidget(stepArea);
        }

      stepArea->setEnabled(true);
      stepArea->show();
      }
      }
    
}
Beispiel #12
0
//------------------------------------------------------------------------------
void ctkDICOMDatabasePrivate::registerCompressionLibraries(){
    logger.debug("Register compression libraries");
    // Register the JPEG libraries in case we need them
    //   (registration only happens once, so it's okay to call repeatedly)
    // register global JPEG decompression codecs
    DJDecoderRegistration::registerCodecs();
    // register global JPEG compression codecs
    DJEncoderRegistration::registerCodecs();
    // register RLE compression codec
    DcmRLEEncoderRegistration::registerCodecs();
    // register RLE decompression codec
    DcmRLEDecoderRegistration::registerCodecs();
}
Beispiel #13
0
//------------------------------------------------------------------------------
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);
}
Beispiel #14
0
//-----------------------------------------------------------------------------
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];
}
Beispiel #15
0
//------------------------------------------------------------------------------
bool ctkDICOMDatabasePrivate::loggedExec(QSqlQuery& query, const QString& queryString)
{
  bool success;
  if (queryString.compare(""))
    {
    success = query.exec(queryString);
    }
  else
    {
    success = query.exec();
    }
  if (!success)
    {
    QSqlError sqlError = query.lastError();
    logger.debug( "SQL failed\n Bad SQL: " + query.lastQuery());
    logger.debug( "Error text: " + sqlError.text());
    }
  else
    {
  logger.debug( "SQL worked!\n SQL: " + query.lastQuery());
    }
  return (success);
}
Beispiel #16
0
// --------------------------------------------------------------------------
void ctkWorkflowWidget::setWorkflow(ctkWorkflow* newWorkflow)
{
  Q_D(ctkWorkflowWidget);

  if (!newWorkflow)
    {
    logger.error(QString("setWorkflow - cannot set workflow to NULL"));
    return;
    }

  if (d->Workflow)
    {
    QObject::disconnect(d->Workflow, SIGNAL(currentStepChanged(ctkWorkflowStep*)), this, SLOT(onCurrentStepChanged(ctkWorkflowStep)));
    }
Beispiel #17
0
//----------------------------------------------------------------------------
void ctkVTKSliceView::scheduleRender()
{
  Q_D(ctkVTKSliceView);

  logger.trace("scheduleRender");
  if (!d->RenderEnabled)
    {
    return;
    }
  if (!d->RenderPending)
    {
    d->RenderPending = true;
    QTimer::singleShot(0, this, SLOT(forceRender()));
    }
}
//-----------------------------------------------------------------------------
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 ctkWorkflowAbstractPagedWidget::associateStepWithPage(ctkWorkflowStep* step, int index)
{
  Q_D(ctkWorkflowAbstractPagedWidget);

  if (index < 0)
    {
    logger.error(QString("Cannot associate step with a page of index -1"));
    return;
    }

  if (step)
    {
    d->StepToIndexMap[step] = index;

    if (!d->IndexToGroupBoxMap.contains(index))
      {
      d->IndexToGroupBoxMap[index] = 0;
      }
    }
}
Beispiel #20
0
// -------------------------------------------------------------------------
void ctkDICOMDatasetView::displayImage(int imageIndex){
  Q_D(ctkDICOMDatasetView);

  if(d->CurrentImageIndex.isValid())
    {
      QModelIndex seriesIndex = d->CurrentImageIndex.parent();
      ctkDICOMModel* model = const_cast<ctkDICOMModel*>(qobject_cast<const ctkDICOMModel*>(seriesIndex.model()));

      if(model)
        {
          if(imageIndex >= 0 && imageIndex < model->rowCount(seriesIndex))
            {
            this->onModelSelected(model->index(imageIndex, 0, seriesIndex));
            }
          else
            {
            logger.debug("out of index");
            }
        }
    }
}
//----------------------------------------------------------------------------
void ctkDICOMThumbnailListWidgetPrivate
::addThumbnailWidget(const QModelIndex& imageIndex,
                     const QModelIndex& sourceIndex, const QString &text)
{
  ctkDICOMModel* model = const_cast<ctkDICOMModel*>(
    qobject_cast<const ctkDICOMModel*>(imageIndex.model()));

  if(!model)
    {
    return;
    }
  QModelIndex seriesIndex = imageIndex.parent();
  QModelIndex studyIndex = seriesIndex.parent();

  QString thumbnailPath = this->DatabaseDirectory +
                          "/thumbs/" + model->data(studyIndex ,ctkDICOMModel::UIDRole).toString() + "/" +
                          model->data(seriesIndex ,ctkDICOMModel::UIDRole).toString() + "/" +
                          model->data(imageIndex, ctkDICOMModel::UIDRole).toString() + ".png";
  if(!QFileInfo(thumbnailPath).exists())
    {
    return;
    }
  ctkThumbnailLabel* widget = new ctkThumbnailLabel(this->ScrollAreaContentWidget);

  QString widgetLabel = text;
  widget->setText( widgetLabel );
  QPixmap pix(thumbnailPath);
  logger.debug("Setting pixmap to " + thumbnailPath);
  if(this->ThumbnailSize.isValid())
    {
    widget->setFixedSize(this->ThumbnailSize);
    }
  widget->setPixmap(pix);

  QVariant var;
  var.setValue(QPersistentModelIndex(sourceIndex));
  widget->setProperty("sourceIndex", var);

  this->addThumbnail(widget);
}
Beispiel #22
0
// --------------------------------------------------------------------------
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 ctkDICOMThumbnailListWidgetPrivate
::addSeriesThumbnails(const QModelIndex &index)
{
  QModelIndex studyIndex = index.parent();
  QModelIndex seriesIndex = index;

  ctkDICOMModel* model = const_cast<ctkDICOMModel*>(qobject_cast<const ctkDICOMModel*>(index.model()));

  if (!model)
    {
    return;
    }
  model->fetchMore(seriesIndex);

  const int imageCount = model->rowCount(seriesIndex);
  logger.debug(QString("Thumbs: %1").arg(imageCount));
  for (int i = 0 ; i < imageCount ; i++ )
    {
    QModelIndex imageIndex = seriesIndex.child(i,0);

    this->addThumbnailWidget(imageIndex, imageIndex, QString("Image %1").arg(i));
    }
}
Beispiel #24
0
//------------------------------------------------------------------------------
ctkDICOMRetrievePrivate::ctkDICOMRetrievePrivate(ctkDICOMRetrieve& obj)
  : q_ptr(&obj)
{
  this->Database = QSharedPointer<ctkDICOMDatabase> (0);
  this->WasCanceled = false;
  this->KeepAssociationOpen = true;
  this->ConnectionParamsChanged = false;
  this->LastRetrieveType = RetrieveNone;

  // Register the JPEG libraries in case we need them
  // (registration only happens once, so it's okay to call repeatedly)
  // register global JPEG decompression codecs
  DJDecoderRegistration::registerCodecs();
  // register global JPEG compression codecs
  DJEncoderRegistration::registerCodecs();
  // register RLE compression codec
  DcmRLEEncoderRegistration::registerCodecs();
  // register RLE decompression codec
  DcmRLEDecoderRegistration::registerCodecs();

  logger.info ( "Setting Transfer Syntaxes" );
  OFList<OFString> transferSyntaxes;
  transferSyntaxes.push_back ( UID_LittleEndianExplicitTransferSyntax );
  transferSyntaxes.push_back ( UID_BigEndianExplicitTransferSyntax );
  transferSyntaxes.push_back ( UID_LittleEndianImplicitTransferSyntax );
  this->SCU.addPresentationContext ( 
      UID_MOVEStudyRootQueryRetrieveInformationModel, transferSyntaxes );
  this->SCU.addPresentationContext ( 
      UID_GETStudyRootQueryRetrieveInformationModel, transferSyntaxes );

  for (Uint16 i = 0; i < numberOfDcmLongSCUStorageSOPClassUIDs; i++)
    {
    this->SCU.addPresentationContext(dcmLongSCUStorageSOPClassUIDs[i], 
        transferSyntaxes, ASC_SC_ROLE_SCP);
    }
}
Beispiel #25
0
//------------------------------------------------------------------------------
bool ctkDICOMRetrieve::retrieveStudy( const QString& studyInstanceUID )
{
  Q_D(ctkDICOMRetrieve);
  logger.info ( "Starting retrieveStudy" );
  return d->retrieve ( studyInstanceUID, ctkDICOMRetrievePrivate::RetrieveStudy );
}
Beispiel #26
0
//------------------------------------------------------------------------------
bool ctkDICOMRetrieve::retrieveSeries( const QString& seriesInstanceUID )
{
  Q_D(ctkDICOMRetrieve);
  logger.info ( "Starting retrieveSeries" );
  return d->retrieve ( seriesInstanceUID, ctkDICOMRetrievePrivate::RetrieveSeries );
}
Beispiel #27
0
//------------------------------------------------------------------------------
bool ctkDICOMRetrievePrivate::retrieve ( QString UID, RetrieveType retriveType ) {

  if ( !this->RetrieveDatabase )
    {
    logger.error ( "Must have RetrieveDatabase for retrieve transaction" );
    return false;
    }

  // Register the JPEG libraries in case we need them
  //   (registration only happens once, so it's okay to call repeatedly)
  // register global JPEG decompression codecs
  DJDecoderRegistration::registerCodecs();
  // register global JPEG compression codecs
  DJEncoderRegistration::registerCodecs();
  // register RLE compression codec
  DcmRLEEncoderRegistration::registerCodecs();
  // register RLE decompression codec
  DcmRLEDecoderRegistration::registerCodecs();

  // Set the DCMTK log level
  log4cplus::Logger rootLogger = log4cplus::Logger::getRoot();
  rootLogger.setLogLevel(log4cplus::DEBUG_LOG_LEVEL);

  // TODO: use this->SCU instead ?
  DcmSCU scu;
  scu.setAETitle ( OFString(this->CallingAETitle.toStdString().c_str()) );
  scu.setPort ( this->CallingPort );
  scu.setPeerAETitle ( OFString(this->CalledAETitle.toStdString().c_str()) );
  scu.setPeerHostName ( OFString(this->Host.toStdString().c_str()) );
  scu.setPeerPort ( this->CalledPort );
  scu.setMoveDestinationAETitle ( OFString(this->MoveDestinationAETitle.toStdString().c_str()) );

  logger.info ( "Setting Transfer Syntaxes" );
  OFList<OFString> transferSyntaxes;
  transferSyntaxes.push_back ( UID_LittleEndianExplicitTransferSyntax );
  transferSyntaxes.push_back ( UID_BigEndianExplicitTransferSyntax );
  transferSyntaxes.push_back ( UID_LittleEndianImplicitTransferSyntax );
  scu.addPresentationContext ( UID_FINDStudyRootQueryRetrieveInformationModel, transferSyntaxes );
  scu.addPresentationContext ( UID_MOVEStudyRootQueryRetrieveInformationModel, transferSyntaxes );

  if ( !scu.initNetwork().good() ) 
    {
    logger.error ( "Error initializing the network" );
    return false;
    }
  logger.debug ( "Negotiating Association" );
  if ( !scu.negotiateAssociation().good() )
    {
    logger.error ( "Error negotiating association" );
    return false;;
    }

  logger.debug ( "Setting Parameters" );
  // Clear the query
  unsigned long elements = this->parameters->card();
  // Clean it out
  for ( unsigned long i = 0; i < elements; i++ ) 
    {
    this->parameters->remove ( 0ul );
    }
  if ( retriveType == RetrieveSeries )
    {
    this->parameters->putAndInsertString ( DCM_QueryRetrieveLevel, "SERIES" );
    this->parameters->putAndInsertString ( DCM_SeriesInstanceUID, UID.toStdString().c_str() );
    } 
  else
    {
    this->parameters->putAndInsertString ( DCM_QueryRetrieveLevel, "STUDY" );
    this->parameters->putAndInsertString ( DCM_StudyInstanceUID, UID.toStdString().c_str() );  
    }

  logger.debug ( "Sending Move Request" );
  MOVEResponses *responses = new MOVEResponses();
  OFCondition status = scu.sendMOVERequest ( 0, this->parameters, responses );
  if (!status.good())
    {
    logger.error ( "MOVE Request failed: " + QString ( status.text() ) );
    return false;
    }

  logger.debug ( "Find succeded" );

  logger.debug ( "Making Output Directory" );
  QDir directory = QDir( RetrieveDatabase->databaseDirectory() );

  if ( responses->begin() == responses->end() )
    {
    logger.error ( "No responses!" );
    throw std::runtime_error( std::string("No responses!") );
    }

  // Write the responses out to disk
  for ( OFListIterator(FINDResponse*) it = responses->begin(); it != responses->end(); it++ )
    {
    DcmDataset *dataset = (*it)->m_dataset;
    if ( dataset != NULL )
      {
      logger.debug ( "Got a valid dataset" );
      // Save in correct directory
      E_TransferSyntax output_transfersyntax = dataset->getOriginalXfer();
      dataset->chooseRepresentation( output_transfersyntax, NULL );
        
      if ( !dataset->canWriteXfer( output_transfersyntax ) )
        {
        // Pick EXS_LittleEndianExplicit as our default
        output_transfersyntax = EXS_LittleEndianExplicit;
        }
        
      DcmXfer opt_oxferSyn( output_transfersyntax );
      if ( !dataset->chooseRepresentation( opt_oxferSyn.getXfer(), NULL ).bad() )
        {
        DcmFileFormat* fileformat = new DcmFileFormat ( dataset );
          
        // Follow dcmdjpeg example
        fileformat->loadAllDataIntoMemory();
        OFString SOPInstanceUID;
        dataset->findAndGetOFString ( DCM_SOPInstanceUID, SOPInstanceUID );
        QFileInfo fi ( directory, QString ( SOPInstanceUID.c_str() ) );
        logger.debug ( "Saving file: " + fi.absoluteFilePath() );
        status = fileformat->saveFile ( fi.absoluteFilePath().toStdString().c_str(), opt_oxferSyn.getXfer() );
        if ( !status.good() )
          {
          logger.error ( "Error saving file: " + fi.absoluteFilePath() + " Error is " + status.text() );
          }

        RetrieveDatabase->insert( dataset, true );
          
        delete fileformat;
        }
      }
    }


  delete responses;
  //if ( !scu.dropNetwork().good() ) 
    //{
    //logger.error ( "Error dropping the network" );
    //return false;
    //}
  return true;
}
Beispiel #28
0
//------------------------------------------------------------------------------
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();
    }
}
Beispiel #29
0
// -------------------------------------------------------------------------
void ctkDICOMDatasetView::addImage( DicomImage & dcmImage, bool defaultIntensity )
{
    Q_D(ctkDICOMDatasetView);
    QImage image;
    // Check whether we have a valid image
    EI_Status result = dcmImage.getStatus();
    if (result != EIS_Normal)
    {
      logger.error(QString("Rendering of DICOM image failed for thumbnail failed: ") + DicomImage::getString(result));
      return;
    }
    // Select first window defined in image. If none, compute min/max window as best guess.
    // Only relevant for monochrome
    if (d->AutoWindowLevel)
    {
      if (dcmImage.isMonochrome())
      {
          if (defaultIntensity && dcmImage.getWindowCount() > 0)
          {
            dcmImage.setWindow(0);
          }
          else
          {
            dcmImage.setMinMaxWindow(OFTrue /* ignore extreme values */);
            dcmImage.getWindow(d->DicomIntensityLevel, d->DicomIntensityWindow);
          }
      }
    } 
    else 
    {
      dcmImage.setWindow(d->DicomIntensityLevel, d->DicomIntensityWindow);
    }
    /* get image extension and prepare image header */
    const unsigned long width = dcmImage.getWidth();
    const unsigned long height = dcmImage.getHeight();
    unsigned long offset = 0;
    unsigned long length = 0;
    QString header;

    if (dcmImage.isMonochrome())
    {
      // write PGM header (binary monochrome image format)
      header = QString("P5 %1 %2 255\n").arg(width).arg(height);
      offset = header.length();
      length = width * height + offset;
    }
    else
    {
      // write PPM header (binary color image format)
      header = QString("P6 %1 %2 255\n").arg(width).arg(height);
      offset = header.length();
      length = width * height * 3 /* RGB */ + offset;
    }
    /* create output buffer for DicomImage class */
    QByteArray buffer;
    /* copy header to output buffer and resize it for pixel data */
    buffer.append(header);
    buffer.resize(length);

    /* render pixel data to buffer */
    if (dcmImage.getOutputData(static_cast<void *>(buffer.data() + offset), length - offset, 8, 0))
    {  
      if (!image.loadFromData( buffer ))
        {
            logger.error("QImage couldn't created");
        }
    }
    this->addImage(image);
}
Beispiel #30
0
//------------------------------------------------------------------------------
bool ctkDICOMRetrievePrivate::get ( const QString& studyInstanceUID,
                                         const QString& seriesInstanceUID,
                                         const RetrieveType retrieveType )
{
  Q_Q(ctkDICOMRetrieve);

  DcmDataset *retrieveParameters = new DcmDataset();
  if (! this->initializeSCU(studyInstanceUID, seriesInstanceUID, retrieveType, retrieveParameters) )
    {
    delete retrieveParameters;
    return false;
    }

  // Issue request
  logger.debug ( "Sending Get Request" );
  emit q->progress("Sending Get Request");
  emit q->progress(0);
  OFList<RetrieveResponse*> responses;
  T_ASC_PresentationContextID presID = this->SCU.findPresentationContextID(
                                          UID_GETStudyRootQueryRetrieveInformationModel, 
                                          "" /* don't care about transfer syntax */ );
  if (presID == 0)
    {
    logger.error ( "GET Request failed: No valid Study Root GET Presentation Context available" );
    if (!this->KeepAssociationOpen)
      {
      this->SCU.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
      }
    delete retrieveParameters;
    return false;
    }

  emit q->progress("Found Presentation Context");
  emit q->progress(1);

  // do the actual move request
  OFCondition status = this->SCU.sendCGETRequest ( 
                          presID, retrieveParameters, &responses );

  emit q->progress("Sent Get Request");
  emit q->progress(2);

  // Close association if we do not want to explicitly keep it open
  if (!this->KeepAssociationOpen)
    {
    this->SCU.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
    }
  // Free some (little) memory
  delete retrieveParameters;

  // If we do not receive a single response, something is fishy
  if ( responses.begin() == responses.end() )
    {
    logger.error ( "No responses received at all! (at least one empty response always expected)" );
    //throw std::runtime_error( std::string("No responses received from server!") );
    emit q->progress("No Responses from Server!");
    return false;
    }

  emit q->progress("Got Responses");
  emit q->progress(3);

  /* The server is permitted to acknowledge every image that was received, or
   * to send a single move response.
   * If there is only a single response, this can mean the following:
   * 1) No images to transfer (Status Success and Number of Completed Subops = 0)
   * 2) All images transferred (Status Success and Number of Completed Subops > 0)
   * 3) Error code, i.e. no images transferred
   * 4) Warning (one or more failures, i.e. some images transferred)
   */
  if ( responses.size() == 1 )
    {
    RetrieveResponse* rsp = *responses.begin();
    logger.debug ( "GET response receveid with status: " + 
                      QString(DU_cmoveStatusString(rsp->m_status)) );

    if ( (rsp->m_status == STATUS_Success) 
            || (rsp->m_status == STATUS_GET_Warning_SubOperationsCompleteOneOrMoreFailures))
      {
      if (rsp->m_numberOfCompletedSubops == 0)
        {
        logger.error ( "No images transferred by PACS!" );
        //throw std::runtime_error( std::string("No images transferred by PACS!") );
        return false;
        }
      }
    else
      {
      logger.error("GET request failed, server does report error");
      QString statusDetail("No details");
      if (rsp->m_statusDetail != NULL)
        {
         std::ostringstream out;
        rsp->m_statusDetail->print(out);
        statusDetail = "Status Detail: " + statusDetail.fromStdString(out.str());
        }
      statusDetail.prepend("GET request failed: ");
      logger.error(statusDetail);
      //throw std::runtime_error( statusDetail.toStdString() );
      return false;
      }
    }
  // Select the last GET response to output meaningful status information
  OFIterator<RetrieveResponse*> it = responses.begin();
  Uint32 numResults = responses.size();
  for (Uint32 i = 1; i < numResults; i++)
    {
    it++;
    }
  logger.debug ( "GET responses report for study: " + studyInstanceUID +"\n"
    + QString::number(static_cast<unsigned int>((*it)->m_numberOfCompletedSubops))
        + " images transferred, and\n"
    + QString::number(static_cast<unsigned int>((*it)->m_numberOfWarningSubops))
        + " images transferred with warning, and\n"
    + QString::number(static_cast<unsigned int>((*it)->m_numberOfFailedSubops))
        + " images transfers failed");

  emit q->progress("Finished Get");
  emit q->progress(100);

  return true;
}