diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsBetweennessHistogram.cpp b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsBetweennessHistogram.cpp index 31f1e3ead5..02641a153c 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsBetweennessHistogram.cpp +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsBetweennessHistogram.cpp @@ -1,130 +1,130 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include mitk::ConnectomicsBetweennessHistogram::ConnectomicsBetweennessHistogram() : m_Mode( UnweightedUndirectedMode ) , m_CentralityMap() { m_Subject = "Node Betweenness"; } mitk::ConnectomicsBetweennessHistogram::~ConnectomicsBetweennessHistogram() { } void mitk::ConnectomicsBetweennessHistogram::SetBetweennessCalculationMode( const mitk::ConnectomicsBetweennessHistogram::BetweennessCalculationMode & mode ) { m_Mode = mode; } mitk::ConnectomicsBetweennessHistogram::BetweennessCalculationMode mitk::ConnectomicsBetweennessHistogram::GetBetweennessCalculationMode() { return m_Mode; } void mitk::ConnectomicsBetweennessHistogram::ComputeFromConnectomicsNetwork( ConnectomicsNetwork* source ) { NetworkType* boostGraph = source->GetBoostGraph(); IteratorType vertex_iterator_begin, vertex_iterator_end; m_CentralityMap.clear(); m_CentralityMap.resize( source->GetNumberOfVertices() ); switch( m_Mode ) { case UnweightedUndirectedMode: { CalculateUnweightedUndirectedBetweennessCentrality( boostGraph, vertex_iterator_begin, vertex_iterator_end ); break; } case WeightedUndirectedMode: { CalculateWeightedUndirectedBetweennessCentrality( boostGraph, vertex_iterator_begin, vertex_iterator_end ); break; } } ConvertCentralityMapToHistogram(); } void mitk::ConnectomicsBetweennessHistogram::CalculateUnweightedUndirectedBetweennessCentrality( NetworkType* boostGraph, IteratorType vertex_iterator_begin, IteratorType vertex_iterator_end ) { boost::brandes_betweenness_centrality( *boostGraph, boost::centrality_map( boost::make_iterator_property_map( m_CentralityMap.begin(), boost::get( &mitk::ConnectomicsNetwork::NetworkNode::id, *boostGraph ), double() ) ).vertex_index_map( boost::get( &mitk::ConnectomicsNetwork::NetworkNode::id, *boostGraph ) ) ); } void mitk::ConnectomicsBetweennessHistogram::CalculateWeightedUndirectedBetweennessCentrality( NetworkType* boostGraph, IteratorType vertex_iterator_begin, IteratorType vertex_iterator_end ) { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_UNIMPLEMENTED_FEATURE; } void mitk::ConnectomicsBetweennessHistogram::ConvertCentralityMapToHistogram() { double maximumFloat( 0.0 ); - for ( int index( 0 ); index < m_CentralityMap.size(); index++ ) + for ( unsigned int index( 0 ); index < m_CentralityMap.size(); index++ ) { if( m_CentralityMap[ index ] > maximumFloat ) { maximumFloat = m_CentralityMap[ index ]; } } // use the boost double to int converter // it defaults to trunc typedef boost::numeric::converter Double2Int ; // for rounding, reduces the number of nodes classed as zero maximumFloat += 0.5; int maximumInt( 0 ); try { maximumInt = Double2Int::convert( maximumFloat ); } catch ( boost::numeric::positive_overflow const& ) { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_OUTSIDE_INTEGER_RANGE; } m_HistogramVector.resize( maximumInt + 1 ); - for ( int index( 0 ); index < m_CentralityMap.size(); index++ ) + for ( unsigned int index( 0 ); index < m_CentralityMap.size(); index++ ) { int value( 0 ); value = Double2Int::convert( ( m_CentralityMap[index ] + 0.5 ) ); m_HistogramVector[ value ]++; } UpdateYMax(); m_Valid = true; } diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsDegreeHistogram.cpp b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsDegreeHistogram.cpp index 59c4d839b0..e6440634c5 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsDegreeHistogram.cpp +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsDegreeHistogram.cpp @@ -1,58 +1,58 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include mitk::ConnectomicsDegreeHistogram::ConnectomicsDegreeHistogram() { m_Subject = "Node degree"; } mitk::ConnectomicsDegreeHistogram::~ConnectomicsDegreeHistogram() { } void mitk::ConnectomicsDegreeHistogram::ComputeFromConnectomicsNetwork( ConnectomicsNetwork* source ) { std::vector< int > degreeOfNodesVector = source->GetDegreeOfNodes(); int maximumDegree( 0 ); - for( int index( 0 ); index < degreeOfNodesVector.size(); index++ ) + for(unsigned int index( 0 ); index < degreeOfNodesVector.size(); index++ ) { if( maximumDegree < degreeOfNodesVector[ index ] ) { maximumDegree = degreeOfNodesVector[ index ]; } } this->m_HistogramVector.resize( maximumDegree + 1 ); - for( int index( 0 ); index < m_HistogramVector.size(); index++ ) + for(unsigned int index( 0 ); index < m_HistogramVector.size(); index++ ) { this->m_HistogramVector[ index ] = 0; } this->m_TopValue = maximumDegree; - for( int index( 0 ); index < degreeOfNodesVector.size(); index++ ) + for(unsigned int index( 0 ); index < degreeOfNodesVector.size(); index++ ) { this->m_HistogramVector[ degreeOfNodesVector[ index ] ]++; } // successfully created a valid histogram this->m_Valid = true; } diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsHistogramBase.cpp b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsHistogramBase.cpp index fdc160e587..3f8d2a8d47 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsHistogramBase.cpp +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsHistogramBase.cpp @@ -1,226 +1,226 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include mitk::ConnectomicsHistogramBase::ConnectomicsHistogramBase() : m_Valid( false ) , m_BaselineValue( 0 ) , m_TopValue( 1 ) , m_StartValue( 0 ) , m_Subject( "" ) { } mitk::ConnectomicsHistogramBase::~ConnectomicsHistogramBase() { } double mitk::ConnectomicsHistogramBase::GetYMin() const { return m_BaselineValue; } double mitk::ConnectomicsHistogramBase::GetYMax() const { return m_TopValue; } double mitk::ConnectomicsHistogramBase::GetMin() const { return this->GetXMin(); } double mitk::ConnectomicsHistogramBase::GetMax() const { return this->GetXMax(); } double mitk::ConnectomicsHistogramBase::GetXMin() const { return m_StartValue; } double mitk::ConnectomicsHistogramBase::GetXMax() const { return ( m_StartValue + this->GetRange() ); } int mitk::ConnectomicsHistogramBase::GetRange() const { return m_HistogramVector.size(); } bool mitk::ConnectomicsHistogramBase::IsValid() const { return m_Valid; } void mitk::ConnectomicsHistogramBase::PrintToConsole() const { MITK_INFO << "Histogram - Maximum " << this->GetYMax() << " Minimum " << this->GetYMin() << " Range " << this->GetRange(); - for( int index( 0 ); index < m_HistogramVector.size(); index++ ) + for(unsigned int index( 0 ); index < m_HistogramVector.size(); index++ ) { MITK_INFO << " Bin: " << index << " Value: " << m_HistogramVector[ index ]; } } std::string mitk::ConnectomicsHistogramBase::GetSubject() const { return m_Subject; } void mitk::ConnectomicsHistogramBase::SetSubject( std::string subject ) { m_Subject = subject; } void mitk::ConnectomicsHistogramBase::ComputeFromBaseData( BaseData* source ) { m_Valid = false; m_HistogramVector.clear(); //check if input is valid if (source==NULL) { // empty base data return; } mitk::ConnectomicsNetwork* networkSource = dynamic_cast(source); if (networkSource==NULL) { // base data but no network return; } ComputeFromConnectomicsNetwork( networkSource ); } float mitk::ConnectomicsHistogramBase::GetRelativeBin( double start, double end ) const { // use the boost double to int converter // it defaults to trunc typedef boost::numeric::converter Double2Int ; float result( 0.0 ); if( !m_Valid ) { MITK_ERROR << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_TRIED_TO_ACCESS_INVALID_HISTOGRAM; return result; } if( ( start < 0.0 ) || ( end < 0.0 ) ) { MITK_ERROR << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_PASSED_NEGATIVE_INDEX_TO_HISTOGRAM; return result; } // calculate result if( std::abs( end - start ) <= 1.0 ) { // if the bin size is one or less, we can do not need to interpolate - int index( 0 ); + unsigned int index( 0 ); try { // show the value for n between n - .5 and n + .5 double temp = ( start + end ) / 2.0; index = Double2Int::convert( temp ); // By default throws positive_overflow() } catch ( boost::numeric::positive_overflow const& ) { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_OUTSIDE_INTEGER_RANGE; } if( index < m_HistogramVector.size() ) { result = m_HistogramVector[ index ]; } else { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_BEYOND_SCOPE << index << " on vector sized: " << m_HistogramVector.size(); } } else { // if the bin size is more than one we need to interpolate - int indexStart( 0 ), indexEnd( 0 ); + unsigned int indexStart( 0 ), indexEnd( 0 ); try { indexStart = Double2Int::convert( start ); indexEnd = Double2Int::convert( end ); } catch ( boost::numeric::positive_overflow const& ) { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_OUTSIDE_INTEGER_RANGE; } if( ( indexStart < m_HistogramVector.size() ) && ( indexEnd < m_HistogramVector.size() ) ) { // add up weighted values and divide by range // add partial start and end bin double startPercentage = 1.0 - start + indexStart; double endPercentage = end - indexEnd; result += startPercentage * m_HistogramVector[ indexStart ]; result += endPercentage * m_HistogramVector[ indexEnd ]; // add whole inbetween bins - for( int tempIndex = indexStart + 1; tempIndex < indexEnd; tempIndex++ ) + for( unsigned int tempIndex = indexStart + 1; tempIndex < indexEnd; tempIndex++ ) { result += m_HistogramVector[ tempIndex ]; } } else { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_BEYOND_SCOPE << indexStart << " to " << indexEnd << " on vector sized: " << m_HistogramVector.size(); } } // normalizeresult by dividing through maximum degree result = result / GetYMax(); return result; } void mitk::ConnectomicsHistogramBase::UpdateYMax() { - for ( int index( 0 ); index < m_HistogramVector.size(); index++ ) + for ( unsigned int index( 0 ); index < m_HistogramVector.size(); index++ ) { if( m_HistogramVector[ index ] > m_TopValue ) { m_TopValue = m_HistogramVector[ index ]; } } } std::vector< double > mitk::ConnectomicsHistogramBase::GetHistogramVector() { return m_HistogramVector; } diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsHistogramBase.h b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsHistogramBase.h index 93d780ec35..75c7fec4f7 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsHistogramBase.h +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsHistogramBase.h @@ -1,102 +1,101 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_ConnectomicsHistogramBase_H #define _MITK_ConnectomicsHistogramBase_H #include "mitkSimpleHistogram.h" #include "mitkCommon.h" #include "mitkConnectomicsNetwork.h" namespace mitk { /** * \brief Superclass for histograms working with connectomic networks */ class ConnectomicsHistogramBase : public mitk::SimpleHistogram { public: ConnectomicsHistogramBase(); virtual ~ConnectomicsHistogramBase(); /** @brief Returns the minimal y=f(x) value of the histogram. */ virtual double GetYMin() const; /** @brief Returns the maximum y=f(x) value of the histogram. */ virtual double GetYMax() const; /** @brief Returns the minimal x value of the histogram. */ virtual double GetXMin() const; /** @brief Returns the maximum x value of the histogram. */ virtual double GetXMax() const; /** @brief Returns the range of the histogram. */ virtual int GetRange() const; /** @brief Update the Y maximum to the maximal value in the histogram */ virtual void UpdateYMax(); /** @brief Creates a new histogram from the source. */ virtual void ComputeFromBaseData( BaseData* source ); /** @brief Print values to console. */ virtual void PrintToConsole( ) const; /** @brief Returns whether the histogram can be considered valid. */ virtual bool IsValid() const; /** @brief Returns the subject of the histogram as a string. */ virtual std::string GetSubject() const; /** @brief Set the subject of the histogram as a string. */ virtual void SetSubject( std::string ); /** @brief Get bin height for the bin between start and end*/ virtual float GetRelativeBin( double start, double end ) const; /** @brief Get the double vector*/ virtual std::vector< double > GetHistogramVector(); protected: // Functions /** @brief Creates a new histogram from the network source. */ virtual void ComputeFromConnectomicsNetwork( ConnectomicsNetwork* source ) = 0; /** @brief Legacy method, do no use */ virtual double GetMin() const; /** @brief Legacy method, do no use */ virtual double GetMax() const; // Variables /** @brief Is this a valid histogram*/ bool m_Valid; /** @brief Which is the baseline value for the histogram - /* - /* This value should be zero for all network histograms */ + This value should be zero for all network histograms */ int m_BaselineValue; /** @brief Which is the top value for the histogram */ int m_TopValue; /** @brief Which is the starting x value for the histogram */ int m_StartValue; /** @brief We expect not continuous but discrete histograms */ std::vector< double > m_HistogramVector; /** @brief Subject of the histogram as a string. */ std::string m_Subject; }; } #endif /* _MITK_ConnectomicsHistogramBase_H */ diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsNetworkCreator.cpp b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsNetworkCreator.cpp index 3439575f09..ff5ffc92a4 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsNetworkCreator.cpp +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsNetworkCreator.cpp @@ -1,864 +1,864 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkConnectomicsNetworkCreator.h" #include #include #include "mitkConnectomicsConstantsManager.h" #include "mitkImageAccessByItk.h" #include "mitkImageStatisticsHolder.h" #include "mitkImageCast.h" #include "itkImageRegionIteratorWithIndex.h" // VTK #include #include #include mitk::ConnectomicsNetworkCreator::ConnectomicsNetworkCreator() : m_FiberBundle() , m_Segmentation() , m_ConNetwork( mitk::ConnectomicsNetwork::New() ) , idCounter(0) , m_LabelToVertexMap() , m_LabelToNodePropertyMap() , allowLoops( false ) , m_UseCoMCoordinates( false ) , m_LabelsToCoordinatesMap() , m_MappingStrategy( EndElementPositionAvoidingWhiteMatter ) , m_EndPointSearchRadius( 10.0 ) , m_ZeroLabelInvalid( true ) , m_AbortConnection( false ) { } mitk::ConnectomicsNetworkCreator::ConnectomicsNetworkCreator( mitk::Image::Pointer segmentation, mitk::FiberBundleX::Pointer fiberBundle ) : m_FiberBundle(fiberBundle) , m_Segmentation(segmentation) , m_ConNetwork( mitk::ConnectomicsNetwork::New() ) , idCounter(0) , m_LabelToVertexMap() , m_LabelToNodePropertyMap() , allowLoops( false ) , m_LabelsToCoordinatesMap() , m_MappingStrategy( EndElementPositionAvoidingWhiteMatter ) , m_EndPointSearchRadius( 10.0 ) , m_ZeroLabelInvalid( true ) , m_AbortConnection( false ) { mitk::CastToItkImage( segmentation, m_SegmentationItk ); } mitk::ConnectomicsNetworkCreator::~ConnectomicsNetworkCreator() { } void mitk::ConnectomicsNetworkCreator::SetFiberBundle(mitk::FiberBundleX::Pointer fiberBundle) { m_FiberBundle = fiberBundle; } void mitk::ConnectomicsNetworkCreator::SetSegmentation(mitk::Image::Pointer segmentation) { m_Segmentation = segmentation; mitk::CastToItkImage( segmentation, m_SegmentationItk ); } itk::Point mitk::ConnectomicsNetworkCreator::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } void mitk::ConnectomicsNetworkCreator::CreateNetworkFromFibersAndSegmentation() { //empty graph m_ConNetwork = mitk::ConnectomicsNetwork::New(); m_LabelToVertexMap.clear(); m_LabelToNodePropertyMap.clear(); idCounter = 0; vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); vtkSmartPointer vLines = fiberPolyData->GetLines(); vLines->InitTraversal(); int numFibers = m_FiberBundle->GetNumFibers(); for( int fiberID( 0 ); fiberID < numFibers; fiberID++ ) { vtkIdType numPointsInCell(0); vtkIdType* pointsInCell(NULL); vLines->GetNextCell ( numPointsInCell, pointsInCell ); TractType::Pointer singleTract = TractType::New(); for( int pointInCellID( 0 ); pointInCellID < numPointsInCell ; pointInCellID++) { // push back point PointType point = GetItkPoint( fiberPolyData->GetPoint( pointsInCell[ pointInCellID ] ) ); singleTract->InsertElement( singleTract->Size(), point ); } if ( singleTract && ( singleTract->Size() > 0 ) ) { AddConnectionToNetwork( ReturnAssociatedVertexPairForLabelPair( ReturnLabelForFiberTract( singleTract, m_MappingStrategy ) ) ); m_AbortConnection = false; } } // Prune unconnected nodes //m_ConNetwork->PruneUnconnectedSingleNodes(); // provide network with geometry m_ConNetwork->SetGeometry( dynamic_cast(m_Segmentation->GetGeometry()->Clone().GetPointer()) ); m_ConNetwork->UpdateBounds(); m_ConNetwork->SetIsModified( true ); MBI_INFO << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_INFO_NETWORK_CREATED; } void mitk::ConnectomicsNetworkCreator::AddConnectionToNetwork(ConnectionType newConnection) { if( m_AbortConnection ) { MITK_DEBUG << "Connection aborted"; return; } VertexType vertexA = newConnection.first; VertexType vertexB = newConnection.second; // check for loops (if they are not allowed) if( allowLoops || !( vertexA == vertexB ) ) { // If the connection already exists, increment weight, else create connection if ( m_ConNetwork->EdgeExists( vertexA, vertexB ) ) { m_ConNetwork->IncreaseEdgeWeight( vertexA, vertexB ); } else { m_ConNetwork->AddEdge( vertexA, vertexB ); } } } mitk::ConnectomicsNetworkCreator::VertexType mitk::ConnectomicsNetworkCreator::ReturnAssociatedVertexForLabel( ImageLabelType label ) { if( m_ZeroLabelInvalid && ( label == 0 ) ) { m_AbortConnection = true; - return NULL; + return ULONG_MAX; } // if label is not known, create entry if( ! ( m_LabelToVertexMap.count( label ) > 0 ) ) { VertexType newVertex = m_ConNetwork->AddVertex( idCounter ); idCounter++; SupplyVertexWithInformation(label, newVertex); m_LabelToVertexMap.insert( std::pair< ImageLabelType, VertexType >( label, newVertex ) ); } //return associated vertex return m_LabelToVertexMap.find( label )->second; } mitk::ConnectomicsNetworkCreator::ConnectionType mitk::ConnectomicsNetworkCreator::ReturnAssociatedVertexPairForLabelPair( ImageLabelPairType labelpair ) { //hand both labels through to the single label function ConnectionType connection( ReturnAssociatedVertexForLabel(labelpair.first), ReturnAssociatedVertexForLabel(labelpair.second) ); return connection; } mitk::ConnectomicsNetworkCreator::ImageLabelPairType mitk::ConnectomicsNetworkCreator::ReturnLabelForFiberTract( TractType::Pointer singleTract, mitk::ConnectomicsNetworkCreator::MappingStrategy strategy) { switch( strategy ) { case EndElementPosition: { return EndElementPositionLabel( singleTract ); } case JustEndPointVerticesNoLabel: { return JustEndPointVerticesNoLabelTest( singleTract ); } case EndElementPositionAvoidingWhiteMatter: { return EndElementPositionLabelAvoidingWhiteMatter( singleTract ); } case PrecomputeAndDistance: { return PrecomputeVertexLocationsBySegmentation( singleTract ); } } // To remove warnings, this code should never be reached MBI_ERROR << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_INVALID_MAPPING; - ImageLabelPairType nullPair( NULL, NULL ); + ImageLabelPairType nullPair( 0,0 ); return nullPair; } mitk::ConnectomicsNetworkCreator::ImageLabelPairType mitk::ConnectomicsNetworkCreator::EndElementPositionLabel( TractType::Pointer singleTract ) { ImageLabelPairType labelpair; {// Note: .fib image tracts are safed using index coordinates mitk::Point3D firstElementFiberCoord, lastElementFiberCoord; mitk::Point3D firstElementSegCoord, lastElementSegCoord; mitk::Index3D firstElementSegIndex, lastElementSegIndex; if( singleTract->front().Size() != 3 ) { MBI_ERROR << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_INVALID_DIMENSION_NEED_3; } - for( int index = 0; index < singleTract->front().Size(); index++ ) + for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { firstElementFiberCoord.SetElement( index, singleTract->front().GetElement( index ) ); lastElementFiberCoord.SetElement( index, singleTract->back().GetElement( index ) ); } // convert from fiber index coordinates to segmentation index coordinates FiberToSegmentationCoords( firstElementFiberCoord, firstElementSegCoord ); FiberToSegmentationCoords( lastElementFiberCoord, lastElementSegCoord ); for( int index = 0; index < 3; index++ ) { firstElementSegIndex.SetElement( index, firstElementSegCoord.GetElement( index ) ); lastElementSegIndex.SetElement( index, lastElementSegCoord.GetElement( index ) ); } int firstLabel = m_SegmentationItk->GetPixel(firstElementSegIndex); int lastLabel = m_SegmentationItk->GetPixel(lastElementSegIndex ); labelpair.first = firstLabel; labelpair.second = lastLabel; // Add property to property map CreateNewNode( firstLabel, firstElementSegIndex, m_UseCoMCoordinates ); CreateNewNode( lastLabel, lastElementSegIndex, m_UseCoMCoordinates ); } return labelpair; } -mitk::ConnectomicsNetworkCreator::ImageLabelPairType mitk::ConnectomicsNetworkCreator::PrecomputeVertexLocationsBySegmentation( TractType::Pointer singleTract ) +mitk::ConnectomicsNetworkCreator::ImageLabelPairType mitk::ConnectomicsNetworkCreator::PrecomputeVertexLocationsBySegmentation( TractType::Pointer /*singleTract*/ ) { ImageLabelPairType labelpair; return labelpair; } mitk::ConnectomicsNetworkCreator::ImageLabelPairType mitk::ConnectomicsNetworkCreator::EndElementPositionLabelAvoidingWhiteMatter( TractType::Pointer singleTract ) { ImageLabelPairType labelpair; {// Note: .fib image tracts are safed using index coordinates mitk::Point3D firstElementFiberCoord, lastElementFiberCoord; mitk::Point3D firstElementSegCoord, lastElementSegCoord; mitk::Index3D firstElementSegIndex, lastElementSegIndex; if( singleTract->front().Size() != 3 ) { MBI_ERROR << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_INVALID_DIMENSION_NEED_3; } - for( int index = 0; index < singleTract->front().Size(); index++ ) + for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { firstElementFiberCoord.SetElement( index, singleTract->front().GetElement( index ) ); lastElementFiberCoord.SetElement( index, singleTract->back().GetElement( index ) ); } // convert from fiber index coordinates to segmentation index coordinates FiberToSegmentationCoords( firstElementFiberCoord, firstElementSegCoord ); FiberToSegmentationCoords( lastElementFiberCoord, lastElementSegCoord ); for( int index = 0; index < 3; index++ ) { firstElementSegIndex.SetElement( index, firstElementSegCoord.GetElement( index ) ); lastElementSegIndex.SetElement( index, lastElementSegCoord.GetElement( index ) ); } int firstLabel = m_SegmentationItk->GetPixel(firstElementSegIndex); int lastLabel = m_SegmentationItk->GetPixel(lastElementSegIndex ); // Check whether the labels belong to the white matter (which means, that the fibers ended early) bool extendFront(false), extendEnd(false), retractFront(false), retractEnd(false); extendFront = !IsNonWhiteMatterLabel( firstLabel ); extendEnd = !IsNonWhiteMatterLabel( lastLabel ); retractFront = IsBackgroundLabel( firstLabel ); retractEnd = IsBackgroundLabel( lastLabel ); //if( extendFront || extendEnd ) //{ //MBI_INFO << "Before Start: " << firstLabel << " at " << firstElementSegIndex[ 0 ] << " " << firstElementSegIndex[ 1 ] << " " << firstElementSegIndex[ 2 ] << " End: " << lastLabel << " at " << lastElementSegIndex[ 0 ] << " " << lastElementSegIndex[ 1 ] << " " << lastElementSegIndex[ 2 ]; //} if ( extendFront ) { std::vector< int > indexVectorOfPointsToUse; //Use first two points for direction indexVectorOfPointsToUse.push_back( 1 ); indexVectorOfPointsToUse.push_back( 0 ); // label and coordinate temp storage int tempLabel( firstLabel ); mitk::Index3D tempIndex = firstElementSegIndex; LinearExtensionUntilGreyMatter( indexVectorOfPointsToUse, singleTract, tempLabel, tempIndex ); firstLabel = tempLabel; firstElementSegIndex = tempIndex; } if ( extendEnd ) { std::vector< int > indexVectorOfPointsToUse; //Use last two points for direction indexVectorOfPointsToUse.push_back( singleTract->Size() - 2 ); indexVectorOfPointsToUse.push_back( singleTract->Size() - 1 ); // label and coordinate temp storage int tempLabel( lastLabel ); mitk::Index3D tempIndex = lastElementSegIndex; LinearExtensionUntilGreyMatter( indexVectorOfPointsToUse, singleTract, tempLabel, tempIndex ); lastLabel = tempLabel; lastElementSegIndex = tempIndex; } if ( retractFront ) { // label and coordinate temp storage int tempLabel( firstLabel ); mitk::Index3D tempIndex = firstElementSegIndex; RetractionUntilBrainMatter( true, singleTract, tempLabel, tempIndex ); firstLabel = tempLabel; firstElementSegIndex = tempIndex; } if ( retractEnd ) { // label and coordinate temp storage int tempLabel( lastLabel ); mitk::Index3D tempIndex = lastElementSegIndex; RetractionUntilBrainMatter( false, singleTract, tempLabel, tempIndex ); lastLabel = tempLabel; lastElementSegIndex = tempIndex; } //if( extendFront || extendEnd ) //{ // MBI_INFO << "After Start: " << firstLabel << " at " << firstElementSegIndex[ 0 ] << " " << firstElementSegIndex[ 1 ] << " " << firstElementSegIndex[ 2 ] << " End: " << lastLabel << " at " << lastElementSegIndex[ 0 ] << " " << lastElementSegIndex[ 1 ] << " " << lastElementSegIndex[ 2 ]; //} labelpair.first = firstLabel; labelpair.second = lastLabel; // Add property to property map CreateNewNode( firstLabel, firstElementSegIndex, m_UseCoMCoordinates ); CreateNewNode( lastLabel, lastElementSegIndex, m_UseCoMCoordinates ); } return labelpair; } mitk::ConnectomicsNetworkCreator::ImageLabelPairType mitk::ConnectomicsNetworkCreator::JustEndPointVerticesNoLabelTest( TractType::Pointer singleTract ) { ImageLabelPairType labelpair; {// Note: .fib image tracts are safed using index coordinates mitk::Point3D firstElementFiberCoord, lastElementFiberCoord; mitk::Point3D firstElementSegCoord, lastElementSegCoord; mitk::Index3D firstElementSegIndex, lastElementSegIndex; if( singleTract->front().Size() != 3 ) { MBI_ERROR << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_INVALID_DIMENSION_NEED_3; } - for( int index = 0; index < singleTract->front().Size(); index++ ) + for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { firstElementFiberCoord.SetElement( index, singleTract->front().GetElement( index ) ); lastElementFiberCoord.SetElement( index, singleTract->back().GetElement( index ) ); } // convert from fiber index coordinates to segmentation index coordinates FiberToSegmentationCoords( firstElementFiberCoord, firstElementSegCoord ); FiberToSegmentationCoords( lastElementFiberCoord, lastElementSegCoord ); for( int index = 0; index < 3; index++ ) { firstElementSegIndex.SetElement( index, firstElementSegCoord.GetElement( index ) ); lastElementSegIndex.SetElement( index, lastElementSegCoord.GetElement( index ) ); } int firstLabel = 1 * firstElementSegIndex[ 0 ] + 1000 * firstElementSegIndex[ 1 ] + 1000000 * firstElementSegIndex[ 2 ]; int lastLabel = 1 * firstElementSegIndex[ 0 ] + 1000 * firstElementSegIndex[ 1 ] + 1000000 * firstElementSegIndex[ 2 ]; labelpair.first = firstLabel; labelpair.second = lastLabel; // Add property to property map CreateNewNode( firstLabel, firstElementSegIndex, m_UseCoMCoordinates ); CreateNewNode( lastLabel, lastElementSegIndex, m_UseCoMCoordinates ); } return labelpair; } void mitk::ConnectomicsNetworkCreator::SupplyVertexWithInformation( ImageLabelType& label, VertexType& vertex ) { // supply a vertex with the additional information belonging to the label // TODO: Implement additional information acquisition m_ConNetwork->SetLabel( vertex, m_LabelToNodePropertyMap.find( label )->second.label ); m_ConNetwork->SetCoordinates( vertex, m_LabelToNodePropertyMap.find( label )->second.coordinates ); } std::string mitk::ConnectomicsNetworkCreator::LabelToString( ImageLabelType& label ) { int tempInt = (int) label; std::stringstream ss;//create a stringstream std::string tempString; ss << tempInt;//add number to the stream tempString = ss.str(); return tempString;//return a string with the contents of the stream } mitk::ConnectomicsNetwork::Pointer mitk::ConnectomicsNetworkCreator::GetNetwork() { return m_ConNetwork; } void mitk::ConnectomicsNetworkCreator::FiberToSegmentationCoords( mitk::Point3D& fiberCoord, mitk::Point3D& segCoord ) { mitk::Point3D tempPoint; // convert from fiber index coordinates to segmentation index coordinates m_FiberBundle->GetGeometry()->IndexToWorld( fiberCoord, tempPoint ); m_Segmentation->GetGeometry()->WorldToIndex( tempPoint, segCoord ); } void mitk::ConnectomicsNetworkCreator::SegmentationToFiberCoords( mitk::Point3D& segCoord, mitk::Point3D& fiberCoord ) { mitk::Point3D tempPoint; // convert from fiber index coordinates to segmentation index coordinates m_Segmentation->GetGeometry()->IndexToWorld( segCoord, tempPoint ); m_FiberBundle->GetGeometry()->WorldToIndex( tempPoint, fiberCoord ); } bool mitk::ConnectomicsNetworkCreator::IsNonWhiteMatterLabel( int labelInQuestion ) { bool isWhite( false ); isWhite = ( ( labelInQuestion == freesurfer_Left_Cerebral_White_Matter ) || ( labelInQuestion == freesurfer_Left_Cerebellum_White_Matter ) || ( labelInQuestion == freesurfer_Right_Cerebral_White_Matter ) || ( labelInQuestion == freesurfer_Right_Cerebellum_White_Matter )|| ( labelInQuestion == freesurfer_Left_Cerebellum_Cortex ) || ( labelInQuestion == freesurfer_Right_Cerebellum_Cortex ) || ( labelInQuestion == freesurfer_Brain_Stem ) ); return !isWhite; } bool mitk::ConnectomicsNetworkCreator::IsBackgroundLabel( int labelInQuestion ) { bool isBackground( false ); isBackground = ( labelInQuestion == 0 ); return isBackground; } void mitk::ConnectomicsNetworkCreator::LinearExtensionUntilGreyMatter( std::vector & indexVectorOfPointsToUse, TractType::Pointer singleTract, int & label, mitk::Index3D & mitkIndex ) { if( indexVectorOfPointsToUse.size() > singleTract->Size() ) { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_MORE_POINTS_THAN_PRESENT; return; } if( indexVectorOfPointsToUse.size() < 2 ) { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_ESTIMATING_LESS_THAN_2; return; } - for( int index( 0 ); index < indexVectorOfPointsToUse.size(); index++ ) + for( unsigned int index( 0 ); index < indexVectorOfPointsToUse.size(); index++ ) { - if( indexVectorOfPointsToUse[ index ] > singleTract->Size() ) + if( indexVectorOfPointsToUse[ index ] < 0 ) { - MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_ESTIMATING_BEYOND_END; + MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_ESTIMATING_BEYOND_START; return; } - if( indexVectorOfPointsToUse[ index ] < 0 ) + if( (unsigned int)indexVectorOfPointsToUse[ index ] > singleTract->Size() ) { - MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_ESTIMATING_BEYOND_START; + MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_ESTIMATING_BEYOND_END; return; } } mitk::Point3D startPoint, endPoint; std::vector< double > differenceVector; differenceVector.resize( singleTract->front().Size() ); { // which points to use, currently only last two //TODO correct using all points int endPointIndex = indexVectorOfPointsToUse.size() - 1; int startPointIndex = indexVectorOfPointsToUse.size() - 2; // convert to segmentation coords mitk::Point3D startFiber, endFiber; - for( int index = 0; index < singleTract->front().Size(); index++ ) + for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { endFiber.SetElement( index, singleTract->GetElement( indexVectorOfPointsToUse[ endPointIndex ] ).GetElement( index ) ); startFiber.SetElement( index, singleTract->GetElement( indexVectorOfPointsToUse[ startPointIndex ] ).GetElement( index ) ); } FiberToSegmentationCoords( endFiber, endPoint ); FiberToSegmentationCoords( startFiber, startPoint ); // calculate straight line - for( int index = 0; index < singleTract->front().Size(); index++ ) + for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { differenceVector[ index ] = endPoint.GetElement( index ) - startPoint.GetElement( index ); } // normalizing direction vector double length( 0.0 ); double sum( 0.0 ); - for( int index = 0; index < differenceVector.size() ; index++ ) + for( unsigned int index = 0; index < differenceVector.size() ; index++ ) { sum = sum + differenceVector[ index ] * differenceVector[ index ]; } length = std::sqrt( sum ); - for( int index = 0; index < differenceVector.size() ; index++ ) + for( unsigned int index = 0; index < differenceVector.size() ; index++ ) { differenceVector[ index ] = differenceVector[ index ] / length; } // follow line until first non white matter label mitk::Index3D tempIndex; int tempLabel( label ); bool keepOn( true ); itk::ImageRegion<3> itkRegion = m_SegmentationItk->GetLargestPossibleRegion(); for( int parameter( 0 ) ; keepOn ; parameter++ ) { if( parameter > 1000 ) { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_DID_NOT_FIND_WHITE; break; } for( int index( 0 ); index < 3; index++ ) { tempIndex.SetElement( index, endPoint.GetElement( index ) + parameter * differenceVector[ index ] ); } if( itkRegion.IsInside( tempIndex ) ) { tempLabel = m_SegmentationItk->GetPixel( tempIndex ); } else { tempLabel = -1; } if( IsNonWhiteMatterLabel( tempLabel ) ) { if( tempLabel < 1 ) { keepOn = false; //MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_NOT_EXTEND_TO_WHITE; } else { label = tempLabel; mitkIndex = tempIndex; keepOn = false; } } } } } void mitk::ConnectomicsNetworkCreator::RetractionUntilBrainMatter( bool retractFront, TractType::Pointer singleTract, int & label, mitk::Index3D & mitkIndex ) { int retractionStartIndex( singleTract->Size() - 1 ); int retractionStepIndexSize( -1 ); int retractionTerminationIndex( 0 ); if( retractFront ) { retractionStartIndex = 0; retractionStepIndexSize = 1; retractionTerminationIndex = singleTract->Size() - 1; } int currentRetractionIndex = retractionStartIndex; bool keepRetracting( true ); mitk::Point3D currentPoint, nextPoint; std::vector< double > differenceVector; differenceVector.resize( singleTract->front().Size() ); while( keepRetracting && ( currentRetractionIndex != retractionTerminationIndex ) ) { // convert to segmentation coords mitk::Point3D currentPointFiberCoord, nextPointFiberCoord; - for( int index = 0; index < singleTract->front().Size(); index++ ) + for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { currentPointFiberCoord.SetElement( index, singleTract->GetElement( currentRetractionIndex ).GetElement( index ) ); nextPointFiberCoord.SetElement( index, singleTract->GetElement( currentRetractionIndex + retractionStepIndexSize ).GetElement( index ) ); } FiberToSegmentationCoords( currentPointFiberCoord, currentPoint ); FiberToSegmentationCoords( nextPointFiberCoord, nextPoint ); // calculate straight line - for( int index = 0; index < singleTract->front().Size(); index++ ) + for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { differenceVector[ index ] = nextPoint.GetElement( index ) - currentPoint.GetElement( index ); } // calculate length of direction vector double length( 0.0 ); double sum( 0.0 ); - for( int index = 0; index < differenceVector.size() ; index++ ) + for( unsigned int index = 0; index < differenceVector.size() ; index++ ) { sum = sum + differenceVector[ index ] * differenceVector[ index ]; } length = std::sqrt( sum ); // retract mitk::Index3D tempIndex; int tempLabel( label ); for( int parameter( 0 ) ; parameter < length ; parameter++ ) { for( int index( 0 ); index < 3; index++ ) { tempIndex.SetElement( index, currentPoint.GetElement( index ) + ( 1.0 + parameter ) / ( 1.0 + length ) * differenceVector[ index ] ); } tempLabel = m_SegmentationItk->GetPixel( tempIndex ); if( !IsBackgroundLabel( tempLabel ) ) { // check whether result is within the search space { mitk::Point3D endPoint, foundPointSegmentation, foundPointFiber; - for( int index = 0; index < singleTract->front().Size(); index++ ) + for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { // this is in fiber (world) coordinates endPoint.SetElement( index, singleTract->GetElement( retractionStartIndex ).GetElement( index ) ); } for( int index( 0 ); index < 3; index++ ) { foundPointSegmentation.SetElement( index, currentPoint.GetElement( index ) + ( 1.0 + parameter ) / ( 1.0 + length ) * differenceVector[ index ] ); } SegmentationToFiberCoords( foundPointSegmentation, foundPointFiber ); std::vector< double > finalDistance; finalDistance.resize( singleTract->front().Size() ); - for( int index = 0; index < singleTract->front().Size(); index++ ) + for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { finalDistance[ index ] = foundPointFiber.GetElement( index ) - endPoint.GetElement( index ); } // calculate length of direction vector double finalLength( 0.0 ); double finalSum( 0.0 ); - for( int index = 0; index < finalDistance.size() ; index++ ) + for( unsigned int index = 0; index < finalDistance.size() ; index++ ) { finalSum = finalSum + finalDistance[ index ] * finalDistance[ index ]; } finalLength = std::sqrt( finalSum ); if( finalLength > m_EndPointSearchRadius ) { // the found point was not within the search space return; } } label = tempLabel; mitkIndex = tempIndex; return; } // hit next point without finding brain matter currentRetractionIndex = currentRetractionIndex + retractionStepIndexSize; - if( ( currentRetractionIndex < 1 ) || ( currentRetractionIndex > ( singleTract->Size() - 2 ) ) ) + if( ( currentRetractionIndex < 1 ) || ( (unsigned int)currentRetractionIndex > ( singleTract->Size() - 2 ) ) ) { keepRetracting = false; } } } } void mitk::ConnectomicsNetworkCreator::CalculateCenterOfMass() { const int dimensions = 3; int max = m_Segmentation->GetStatistics()->GetScalarValueMax(); int min = m_Segmentation->GetStatistics()->GetScalarValueMin(); int range = max - min +1; // each label owns a vector of coordinates std::vector< std::vector< std::vector< double> > > coordinatesPerLabelVector; coordinatesPerLabelVector.resize( range ); itk::ImageRegionIteratorWithIndex it_itkImage( m_SegmentationItk, m_SegmentationItk->GetLargestPossibleRegion() ); for( it_itkImage.GoToBegin(); !it_itkImage.IsAtEnd(); ++it_itkImage ) { std::vector< double > coordinates; coordinates.resize(dimensions); itk::Index< dimensions > index = it_itkImage.GetIndex(); for( int loop(0); loop < dimensions; loop++) { coordinates.at( loop ) = index.GetElement( loop ); } // add the coordinates to the corresponding label vector coordinatesPerLabelVector.at( it_itkImage.Value() - min ).push_back( coordinates ); } for(int currentIndex(0), currentLabel( min ); currentIndex < range; currentIndex++, currentLabel++ ) { std::vector< double > currentCoordinates; currentCoordinates.resize(dimensions); int numberOfPoints = coordinatesPerLabelVector.at( currentIndex ).size(); std::vector< double > sumCoords; sumCoords.resize( dimensions ); for( int loop(0); loop < numberOfPoints; loop++ ) { for( int loopDimension( 0 ); loopDimension < dimensions; loopDimension++ ) { sumCoords.at( loopDimension ) += coordinatesPerLabelVector.at( currentIndex ).at( loop ).at( loopDimension ); } } for( int loopDimension( 0 ); loopDimension < dimensions; loopDimension++ ) { currentCoordinates.at( loopDimension ) = sumCoords.at( loopDimension ) / numberOfPoints; } m_LabelsToCoordinatesMap.insert( std::pair< int, std::vector >( currentLabel, currentCoordinates ) ); } //can now use center of mass coordinates m_UseCoMCoordinates = true; } std::vector< double > mitk::ConnectomicsNetworkCreator::GetCenterOfMass( int label ) { // if label is not known, warn if( ! ( m_LabelsToCoordinatesMap.count( label ) > 0 ) ) { MITK_ERROR << "Label " << label << " not found. Could not return coordinates."; std::vector< double > nullVector; nullVector.resize(3); return nullVector; } //return associated coordinates return m_LabelsToCoordinatesMap.find( label )->second; } void mitk::ConnectomicsNetworkCreator::CreateNewNode( int label, mitk::Index3D index, bool useCoM ) { // Only create node if it does not exist yet if( ! ( m_LabelToNodePropertyMap.count( label ) > 0 ) ) { NetworkNode newNode; newNode.coordinates.resize( 3 ); if( !useCoM ) { for( unsigned int loop = 0; loop < newNode.coordinates.size() ; loop++ ) { newNode.coordinates[ loop ] = index[ loop ] ; } } else { std::vector labelCoords = GetCenterOfMass( label ); for( unsigned int loop = 0; loop < newNode.coordinates.size() ; loop++ ) { newNode.coordinates[ loop ] = labelCoords.at( loop ) ; } } newNode.label = LabelToString( label ); m_LabelToNodePropertyMap.insert( std::pair< ImageLabelType, NetworkNode >( label, newNode ) ); } } diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsShortestPathHistogram.cpp b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsShortestPathHistogram.cpp index 0e4e3d0d14..8325b2c58b 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsShortestPathHistogram.cpp +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsShortestPathHistogram.cpp @@ -1,184 +1,184 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include "mitkConnectomicsConstantsManager.h" mitk::ConnectomicsShortestPathHistogram::ConnectomicsShortestPathHistogram() : m_Mode( UnweightedUndirectedMode ) , m_EverythingConnected( true ) { m_Subject = "Shortest path"; } mitk::ConnectomicsShortestPathHistogram::~ConnectomicsShortestPathHistogram() { } void mitk::ConnectomicsShortestPathHistogram::SetShortestPathCalculationMode( const mitk::ConnectomicsShortestPathHistogram::ShortestPathCalculationMode & mode) { m_Mode = mode; } mitk::ConnectomicsShortestPathHistogram::ShortestPathCalculationMode mitk::ConnectomicsShortestPathHistogram::GetShortestPathCalculationMode() { return m_Mode; } void mitk::ConnectomicsShortestPathHistogram::ComputeFromConnectomicsNetwork( ConnectomicsNetwork* source ) { NetworkType* boostGraph = source->GetBoostGraph(); switch( m_Mode ) { case UnweightedUndirectedMode: { CalculateUnweightedUndirectedShortestPaths( boostGraph ); break; } case WeightedUndirectedMode: { CalculateWeightedUndirectedShortestPaths( boostGraph ); break; } } ConvertDistanceMapToHistogram(); } void mitk::ConnectomicsShortestPathHistogram::CalculateUnweightedUndirectedShortestPaths( NetworkType* boostGraph ) { std::vector< DescriptorType > predecessorMap( boost::num_vertices( *boostGraph ) ); int numberOfNodes( boost::num_vertices( *boostGraph ) ); m_DistanceMatrix.resize( numberOfNodes ); - for( int index(0); index < m_DistanceMatrix.size(); index++ ) + for(unsigned int index(0); index < m_DistanceMatrix.size(); index++ ) { m_DistanceMatrix[ index ].resize( numberOfNodes ); } IteratorType iterator, end; boost::tie(iterator, end) = boost::vertices( *boostGraph ); for ( int index(0) ; iterator != end; ++iterator, index++) { boost::dijkstra_shortest_paths(*boostGraph, *iterator, boost::predecessor_map(&predecessorMap[ 0 ]).distance_map(&m_DistanceMatrix[ index ][ 0 ]).weight_map( boost::get( &mitk::ConnectomicsNetwork::NetworkEdge::edge_weight ,*boostGraph ) ) ) ; } } void mitk::ConnectomicsShortestPathHistogram::CalculateWeightedUndirectedShortestPaths( NetworkType* boostGraph ) { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_UNIMPLEMENTED_FEATURE; } void mitk::ConnectomicsShortestPathHistogram::ConvertDistanceMapToHistogram() { // get the longest path between any two nodes in the network // we assume that no nodes are farther apart than there are nodes, // this is to filter unconnected nodes int longestPath( 0 ); int numberOfNodes( m_DistanceMatrix.size() ); m_EverythingConnected = true; - for( int index(0); index < m_DistanceMatrix.size(); index++ ) + for(unsigned int index(0); index < m_DistanceMatrix.size(); index++ ) { - for( int innerIndex(0); innerIndex < m_DistanceMatrix[ index ].size(); innerIndex++ ) + for(unsigned int innerIndex(0); innerIndex < m_DistanceMatrix[ index ].size(); innerIndex++ ) { if( m_DistanceMatrix[ index ][ innerIndex ] > longestPath ) { if( m_DistanceMatrix[ index ][ innerIndex ] < numberOfNodes ) { longestPath = m_DistanceMatrix[ index ][ innerIndex ]; } else { // these nodes are not connected m_EverythingConnected = false; } } } } m_HistogramVector.resize( longestPath + 1 ); - for( int index(0); index < m_DistanceMatrix.size(); index++ ) + for(unsigned int index(0); index < m_DistanceMatrix.size(); index++ ) { - for( int innerIndex(0); innerIndex < m_DistanceMatrix[ index ].size(); innerIndex++ ) + for( unsigned int innerIndex(0); innerIndex < m_DistanceMatrix[ index ].size(); innerIndex++ ) { if( m_DistanceMatrix[ index ][ innerIndex ] < numberOfNodes ) { m_HistogramVector[ m_DistanceMatrix[ index ][ innerIndex ] ]++; } } } // correct for every path being counted twice - for( int index(1); index < m_HistogramVector.size(); index++ ) + for( unsigned int index(1); index < m_HistogramVector.size(); index++ ) { m_HistogramVector[ index ] = m_HistogramVector[ index ] / 2; } // correct for every node being distance zero to itself if( m_HistogramVector[ 0 ] >= numberOfNodes ) { m_HistogramVector[ 0 ] = m_HistogramVector[ 0 ] - numberOfNodes; } else { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_ZERO_DISTANCE_NODES; } UpdateYMax(); this->m_Valid = true; } double mitk::ConnectomicsShortestPathHistogram::GetEfficiency() { if( !this->m_Valid ) { MBI_INFO << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_CAN_NOT_COMPUTE_EFFICIENCY << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_NETWORK_NOT_VALID; return 0.0; } if( !m_EverythingConnected ) { // efficiency of disconnected graphs is 0 MBI_INFO << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_NETWORK_DISCONNECTED; return 0.0; } double efficiency( 0.0 ); double overallDistance( 0.0 ); double numberOfPairs( 0.0 ); // add up all distances - for( int index(0); index < m_HistogramVector.size(); index++ ) + for( unsigned int index(0); index < m_HistogramVector.size(); index++ ) { overallDistance = overallDistance + m_HistogramVector[ index ] * index; numberOfPairs = numberOfPairs + m_HistogramVector[ index ]; } // efficiency = 1 / averageDistance = 1 / ( overallDistance / numberofPairs ) efficiency = numberOfPairs / overallDistance; return efficiency; } diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSimulatedAnnealingCostFunctionModularity.cpp b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSimulatedAnnealingCostFunctionModularity.cpp index f931c8911b..6d8af03eaa 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSimulatedAnnealingCostFunctionModularity.cpp +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSimulatedAnnealingCostFunctionModularity.cpp @@ -1,125 +1,125 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkConnectomicsSimulatedAnnealingCostFunctionModularity.h" mitk::ConnectomicsSimulatedAnnealingCostFunctionModularity::ConnectomicsSimulatedAnnealingCostFunctionModularity() { } mitk::ConnectomicsSimulatedAnnealingCostFunctionModularity::~ConnectomicsSimulatedAnnealingCostFunctionModularity() { } double mitk::ConnectomicsSimulatedAnnealingCostFunctionModularity::Evaluate( mitk::ConnectomicsNetwork::Pointer network, ToModuleMapType* vertexToModuleMap ) const { double cost( 0.0 ); cost = 100.0 * ( 1.0 - CalculateModularity( network, vertexToModuleMap ) ); return cost; } double mitk::ConnectomicsSimulatedAnnealingCostFunctionModularity::CalculateModularity( mitk::ConnectomicsNetwork::Pointer network, ToModuleMapType* vertexToModuleMap ) const { double modularity( 0.0 ); int numberOfModules = getNumberOfModules( vertexToModuleMap ); - if( network->GetNumberOfVertices() != vertexToModuleMap->size() ) + if( network->GetNumberOfVertices() != (int)vertexToModuleMap->size() ) { MBI_ERROR << "Number of vertices and vertex to module map size do not match!"; return modularity; } int numberOfLinksInNetwork( 0 ); std::vector< int > numberOfLinksInModule, sumOfDegreesInModule; numberOfLinksInModule.resize( numberOfModules, 0 ); sumOfDegreesInModule.resize( numberOfModules, 0 ); // get vector of all vertex descriptors in the network const std::vector< VertexDescriptorType > allNodesVector = network->GetVectorOfAllVertexDescriptors(); - for( int nodeNumber( 0 ); nodeNumber < allNodesVector.size() ; nodeNumber++) + for( unsigned int nodeNumber( 0 ); nodeNumber < allNodesVector.size() ; nodeNumber++) { int correspondingModule = vertexToModuleMap->find( allNodesVector[ nodeNumber ] )->second; const std::vector< VertexDescriptorType > adjacentNodexVector = network->GetVectorOfAdjacentNodes( allNodesVector[ nodeNumber ] ); numberOfLinksInNetwork += adjacentNodexVector.size(); sumOfDegreesInModule[ correspondingModule ] += adjacentNodexVector.size(); - for( int adjacentNodeNumber( 0 ); adjacentNodeNumber < adjacentNodexVector.size() ; adjacentNodeNumber++) + for( unsigned int adjacentNodeNumber( 0 ); adjacentNodeNumber < adjacentNodexVector.size() ; adjacentNodeNumber++) { if( correspondingModule == vertexToModuleMap->find( adjacentNodexVector[ adjacentNodeNumber ] )->second ) { numberOfLinksInModule[ correspondingModule ]++; } } } // the numbers for links have to be halved, as each edge was counted twice numberOfLinksInNetwork = numberOfLinksInNetwork / 2; // if the network contains no links return 0 if( numberOfLinksInNetwork < 1) { return 0; } for( int index( 0 ); index < numberOfModules ; index++) { numberOfLinksInModule[ index ] = numberOfLinksInModule[ index ] / 2; } //Calculate modularity M: //M = sum_{s=1}^{N_{M}} [ (l_{s} / L) - (d_{s} / ( 2L ))^2 ] //where N_{M} is the number of modules //L is the number of links in the network //l_{s} is the number of links between nodes in the module //s is the module //d_{s} is the sum of degrees of the nodes in the module //( taken from Guimera, R. AND Amaral, L. A. N. // Cartography of complex networks: modules and universal roles // Journal of Statistical Mechanics: Theory and Experiment, 2005, 2005, P02001 ) for( int moduleID( 0 ); moduleID < numberOfModules; moduleID++ ) { modularity += (((double) numberOfLinksInModule[ moduleID ]) / ((double) numberOfLinksInNetwork)) - ( (((double) sumOfDegreesInModule[ moduleID ]) / ((double) 2 * numberOfLinksInNetwork) ) * (((double) sumOfDegreesInModule[ moduleID ]) / ((double) 2 * numberOfLinksInNetwork) ) ); } return modularity; } int mitk::ConnectomicsSimulatedAnnealingCostFunctionModularity::getNumberOfModules( ToModuleMapType *vertexToModuleMap ) const { int maxModule( 0 ); ToModuleMapType::iterator iter = vertexToModuleMap->begin(); ToModuleMapType::iterator end = vertexToModuleMap->end(); while( iter != end ) { if( iter->second > maxModule ) { maxModule = iter->second; } iter++; } return maxModule + 1; } diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSimulatedAnnealingPermutationBase.h b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSimulatedAnnealingPermutationBase.h index ca2efacb41..887af96de4 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSimulatedAnnealingPermutationBase.h +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSimulatedAnnealingPermutationBase.h @@ -1,74 +1,74 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkConnectomicsSimulatedAnnealingPermutationBase_h #define mitkConnectomicsSimulatedAnnealingPermutationBase_h #include #include #include #include "mitkCommon.h" #include "ConnectomicsExports.h" #include "mitkConnectomicsSimulatedAnnealingCostFunctionBase.h" namespace mitk { /** * \brief Base class of a permutation to be used in simulated annealing */ class Connectomics_EXPORT ConnectomicsSimulatedAnnealingPermutationBase : public itk::Object { public: /** Standard class typedefs. */ /** Method for creation through the object factory. */ mitkClassMacro(ConnectomicsSimulatedAnnealingPermutationBase, itk::Object); itkNewMacro(Self); // Set the cost function void SetCostFunction( mitk::ConnectomicsSimulatedAnnealingCostFunctionBase::Pointer costFunction ); // Returns true if a cost function is assigned bool HasCostFunction( ); // Initialize the permutation virtual void Initialize(){}; // Do a permutation for a specific temperature - virtual void Permutate( double temperature ){}; + virtual void Permutate( double /*temperature*/ ){}; // Do clean up necessary after a permutation virtual void CleanUp(){}; protected: //////////////////// Functions /////////////////////// ConnectomicsSimulatedAnnealingPermutationBase(); ~ConnectomicsSimulatedAnnealingPermutationBase(); /////////////////////// Variables //////////////////////// // The cost function assigned to the permutation mitk::ConnectomicsSimulatedAnnealingCostFunctionBase::Pointer m_CostFunction; }; }// end namespace mitk #endif // mitkConnectomicsSimulatedAnnealingPermutationBase_h diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSimulatedAnnealingPermutationModularity.cpp b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSimulatedAnnealingPermutationModularity.cpp index f829603066..5ab335a777 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSimulatedAnnealingPermutationModularity.cpp +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSimulatedAnnealingPermutationModularity.cpp @@ -1,544 +1,540 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkConnectomicsSimulatedAnnealingPermutationModularity.h" #include "mitkConnectomicsSimulatedAnnealingCostFunctionModularity.h" #include "mitkConnectomicsSimulatedAnnealingManager.h" //for random number generation #include "vnl/vnl_random.h" #include "vnl/vnl_math.h" mitk::ConnectomicsSimulatedAnnealingPermutationModularity::ConnectomicsSimulatedAnnealingPermutationModularity() { } mitk::ConnectomicsSimulatedAnnealingPermutationModularity::~ConnectomicsSimulatedAnnealingPermutationModularity() { } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::SetNetwork( mitk::ConnectomicsNetwork::Pointer theNetwork ) { m_Network = theNetwork; } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::Initialize() { // create entry for every vertex std::vector< VertexDescriptorType > vertexVector = m_Network->GetVectorOfAllVertexDescriptors(); const int vectorSize = vertexVector.size(); for( int index( 0 ); index < vectorSize; index++) { m_BestSolution.insert( std::pair( vertexVector[ index ], 0 ) ); } // initialize with random distribution of n modules int n( 5 ); randomlyAssignNodesToModules( &m_BestSolution, n ); } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::Permutate( double temperature ) { ToModuleMapType currentSolution = m_BestSolution; ToModuleMapType currentBestSolution = m_BestSolution; int factor = 1; int numberOfVertices = m_BestSolution.size(); int singleNodeMaxNumber = factor * numberOfVertices * numberOfVertices; int moduleMaxNumber = factor * numberOfVertices; double currentBestCost = Evaluate( ¤tBestSolution ); // do singleNodeMaxNumber node permutations and evaluate for(int loop( 0 ); loop < singleNodeMaxNumber; loop++) { permutateMappingSingleNodeShift( ¤tSolution, m_Network ); if( AcceptChange( currentBestCost, Evaluate( ¤tSolution ), temperature ) ) { currentBestSolution = currentSolution; currentBestCost = Evaluate( ¤tBestSolution ); } } // do moduleMaxNumber module permutations for(int loop( 0 ); loop < moduleMaxNumber; loop++) { permutateMappingModuleChange( ¤tSolution, temperature, m_Network ); if( AcceptChange( currentBestCost, Evaluate( ¤tSolution ), temperature ) ) { currentBestSolution = currentSolution; currentBestCost = Evaluate( ¤tBestSolution ); } } // store the best solution after the run m_BestSolution = currentBestSolution; } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::CleanUp() { // delete empty modules, if any for( int loop( 0 ); loop < getNumberOfModules( &m_BestSolution ) ; loop++ ) { if( getNumberOfVerticesInModule( &m_BestSolution, loop ) < 1 ) { removeModule( &m_BestSolution, loop ); } } } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::permutateMappingSingleNodeShift( ToModuleMapType *vertexToModuleMap, mitk::ConnectomicsNetwork::Pointer network ) { const int nodeCount = vertexToModuleMap->size(); const int moduleCount = getNumberOfModules( vertexToModuleMap ); // the random number generators vnl_random rng( (unsigned int) rand() ); unsigned long randomNode = rng.lrand32( nodeCount - 1 ); // move the node either to any existing module, or to its own //unsigned long randomModule = rng.lrand32( moduleCount ); unsigned long randomModule = rng.lrand32( moduleCount - 1 ); // do some sanity checks if ( nodeCount < 2 ) { // no sense in doing anything return; } const std::vector< VertexDescriptorType > allNodesVector = network->GetVectorOfAllVertexDescriptors(); ToModuleMapType::iterator iter = vertexToModuleMap->find( allNodesVector[ randomNode ] ); const int previousModuleNumber = iter->second; // if we move the node to its own module, do nothing - if( previousModuleNumber == randomModule ) + if( previousModuleNumber == (long)randomModule ) { return; } iter->second = randomModule; if( getNumberOfVerticesInModule( vertexToModuleMap, previousModuleNumber ) < 1 ) { removeModule( vertexToModuleMap, previousModuleNumber ); } } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::permutateMappingModuleChange( ToModuleMapType *vertexToModuleMap, double currentTemperature, mitk::ConnectomicsNetwork::Pointer network ) { //the random number generators vnl_random rng( (unsigned int) rand() ); //randomly generate threshold const double threshold = rng.drand64( 0.0 , 1.0); //for deciding whether to join two modules or split one double splitThreshold = 0.5; //stores whether to join or two split bool joinModules( false ); //select random module int numberOfModules = getNumberOfModules( vertexToModuleMap ); unsigned long randomModuleA = rng.lrand32( numberOfModules - 1 ); //select the second module to join, if joining unsigned long randomModuleB = rng.lrand32( numberOfModules - 1 ); if( ( threshold < splitThreshold ) && ( randomModuleA != randomModuleB ) ) { joinModules = true; } if( joinModules ) { // this being an kommutative operation, we will always join B to A joinTwoModules( vertexToModuleMap, randomModuleA, randomModuleB ); //eliminate the empty module removeModule( vertexToModuleMap, randomModuleB ); } else { //split module splitModule( vertexToModuleMap, currentTemperature, network, randomModuleA ); } } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::joinTwoModules( ToModuleMapType *vertexToModuleMap, int moduleA, int moduleB ) { ToModuleMapType::iterator iter = vertexToModuleMap->begin(); ToModuleMapType::iterator end = vertexToModuleMap->end(); while( iter != end ) { // if vertex belongs to module B move it to A if( iter->second == moduleB ) { iter->second = moduleA; } iter++; }// end while( iter != end ) } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::splitModule( ToModuleMapType *vertexToModuleMap, double currentTemperature, mitk::ConnectomicsNetwork::Pointer network, int moduleToSplit ) { if( m_Depth == 0 ) { // do nothing return; } // if the module contains only one node, no more division is sensible if( getNumberOfVerticesInModule( vertexToModuleMap, moduleToSplit ) < 2 ) { // do nothing return; } // create subgraph of the module, that is to be splitted mitk::ConnectomicsNetwork::Pointer subNetwork = mitk::ConnectomicsNetwork::New(); VertexToVertexMapType graphToSubgraphVertexMap; VertexToVertexMapType subgraphToGraphVertexMap; extractModuleSubgraph( vertexToModuleMap, network, moduleToSplit, subNetwork, &graphToSubgraphVertexMap, &subgraphToGraphVertexMap ); // The submap ToModuleMapType vertexToModuleSubMap; - // copy vertices - VertexToVertexMapType::iterator iter = graphToSubgraphVertexMap.begin(); - VertexToVertexMapType::iterator end = graphToSubgraphVertexMap.end(); - // run simulated annealing on the subgraph to determine how the module should be split if( m_Depth > 0 && m_StepSize > 0 ) { mitk::ConnectomicsSimulatedAnnealingManager::Pointer manager = mitk::ConnectomicsSimulatedAnnealingManager::New(); mitk::ConnectomicsSimulatedAnnealingPermutationModularity::Pointer permutation = mitk::ConnectomicsSimulatedAnnealingPermutationModularity::New(); mitk::ConnectomicsSimulatedAnnealingCostFunctionModularity::Pointer costFunction = mitk::ConnectomicsSimulatedAnnealingCostFunctionModularity::New(); permutation->SetCostFunction( costFunction.GetPointer() ); permutation->SetNetwork( subNetwork ); permutation->SetDepth( m_Depth - 1 ); permutation->SetStepSize( m_StepSize * 2 ); manager->SetPermutation( permutation.GetPointer() ); manager->RunSimulatedAnnealing( currentTemperature, m_StepSize * 2 ); vertexToModuleSubMap = permutation->GetMapping(); } // now carry the information over to the original map std::vector< int > moduleTranslationVector; moduleTranslationVector.resize( getNumberOfModules( &vertexToModuleSubMap ), 0 ); int originalNumber = getNumberOfModules( vertexToModuleMap ); // the new parts are added at the end - for(int index( 0 ); index < moduleTranslationVector.size() ; index++) + for(unsigned int index( 0 ); index < moduleTranslationVector.size() ; index++) { moduleTranslationVector[ index ] = originalNumber + index; } ToModuleMapType::iterator iter2 = vertexToModuleSubMap.begin(); ToModuleMapType::iterator end2 = vertexToModuleSubMap.end(); while( iter2 != end2 ) { // translate vertex descriptor from subgraph to graph VertexDescriptorType key = subgraphToGraphVertexMap.find( iter2->first )->second; // translate module number from subgraph to graph int value = moduleTranslationVector[ iter2->second ]; // change the corresponding entry vertexToModuleMap->find( key )->second = value; iter2++; } // remove the now empty module, that was splitted removeModule( vertexToModuleMap, moduleToSplit ); } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::extractModuleSubgraph( ToModuleMapType *vertexToModuleMap, mitk::ConnectomicsNetwork::Pointer network, int moduleToSplit, mitk::ConnectomicsNetwork::Pointer subNetwork, VertexToVertexMapType* graphToSubgraphVertexMap, VertexToVertexMapType* subgraphToGraphVertexMap ) { const std::vector< VertexDescriptorType > allNodesVector = network->GetVectorOfAllVertexDescriptors(); // add vertices to subgraph - for( int nodeNumber( 0 ); nodeNumber < allNodesVector.size() ; nodeNumber++) + for( unsigned int nodeNumber( 0 ); nodeNumber < allNodesVector.size() ; nodeNumber++) { - int correspondingModule = vertexToModuleMap->find( allNodesVector[ nodeNumber ] )->second; if( moduleToSplit == vertexToModuleMap->find( allNodesVector[ nodeNumber ] )->second ) { int id = network->GetNode( allNodesVector[ nodeNumber ] ).id; VertexDescriptorType newVertex = subNetwork->AddVertex( id ); graphToSubgraphVertexMap->insert( std::pair( allNodesVector[ nodeNumber ], newVertex ) ); subgraphToGraphVertexMap->insert( std::pair( newVertex, allNodesVector[ nodeNumber ] ) ); } } // add edges to subgraph VertexToVertexMapType::iterator iter = graphToSubgraphVertexMap->begin(); VertexToVertexMapType::iterator end = graphToSubgraphVertexMap->end(); while( iter != end ) { const std::vector< VertexDescriptorType > adjacentNodexVector = network->GetVectorOfAdjacentNodes( iter->first ); - for( int adjacentNodeNumber( 0 ); adjacentNodeNumber < adjacentNodexVector.size() ; adjacentNodeNumber++) + for( unsigned int adjacentNodeNumber( 0 ); adjacentNodeNumber < adjacentNodexVector.size() ; adjacentNodeNumber++) { // if the adjacent vertex is part of the subgraph, // add edge, if it does not exist yet, else do nothing VertexDescriptorType adjacentVertex = adjacentNodexVector[ adjacentNodeNumber ]; if( graphToSubgraphVertexMap->count( adjacentVertex ) > 0 ) { if( !subNetwork->EdgeExists( iter->second, graphToSubgraphVertexMap->find( adjacentVertex )->second ) ) { //edge exists in parent network, but not yet in sub network const VertexDescriptorType vertexA = iter->second; const VertexDescriptorType vertexB = graphToSubgraphVertexMap->find( adjacentVertex )->second; const int sourceID = network->GetNode( vertexA ).id; const int targetID = network->GetNode( vertexB ).id; const int weight = network->GetEdge( iter->first, graphToSubgraphVertexMap->find( adjacentVertex )->first ).weight; subNetwork->AddEdge( vertexA , vertexB, sourceID, targetID, weight ); } } } iter++; }// end while( iter != end ) } int mitk::ConnectomicsSimulatedAnnealingPermutationModularity::getNumberOfModules( ToModuleMapType *vertexToModuleMap ) const { int maxModule( 0 ); ToModuleMapType::iterator iter = vertexToModuleMap->begin(); ToModuleMapType::iterator end = vertexToModuleMap->end(); while( iter != end ) { if( iter->second > maxModule ) { maxModule = iter->second; } iter++; } return maxModule + 1; } int mitk::ConnectomicsSimulatedAnnealingPermutationModularity::getNumberOfVerticesInModule( ToModuleMapType *vertexToModuleMap, int module ) const { int number( 0 ); ToModuleMapType::iterator iter = vertexToModuleMap->begin(); ToModuleMapType::iterator end = vertexToModuleMap->end(); while( iter != end ) { if( iter->second == module ) { number++; } iter++; } return number; } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::removeModule( ToModuleMapType *vertexToModuleMap, int module ) { int lastModuleNumber = getNumberOfModules( vertexToModuleMap ) - 1; if( module == lastModuleNumber ) { // no need to do anything, the last module is deleted "automatically" return; } if( getNumberOfVerticesInModule( vertexToModuleMap, module ) > 0 ) { MBI_WARN << "Trying to remove non-empty module"; return; } ToModuleMapType::iterator iter = vertexToModuleMap->begin(); ToModuleMapType::iterator end = vertexToModuleMap->end(); while( iter != end ) { if( iter->second == lastModuleNumber ) { // renumber last module to to-be-deleted module iter->second = module; } iter++; } } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::randomlyAssignNodesToModules( ToModuleMapType *vertexToModuleMap, int numberOfIntendedModules ) { // we make sure that each intended module contains *at least* one node // thus if more modules are asked for than node exists we will only generate // as many modules as there are nodes - if( numberOfIntendedModules > vertexToModuleMap->size() ) + if( numberOfIntendedModules > 0 && + (unsigned int)numberOfIntendedModules > vertexToModuleMap->size() ) { MBI_ERROR << "Tried to generate more modules than vertices were provided"; numberOfIntendedModules = vertexToModuleMap->size(); } //the random number generators vnl_random rng( (unsigned int) rand() ); std::vector< int > histogram; std::vector< int > nodeList; histogram.resize( numberOfIntendedModules, 0 ); nodeList.resize( vertexToModuleMap->size(), 0 ); int numberOfVertices = vertexToModuleMap->size(); //randomly distribute nodes to modules - for( int nodeIndex( 0 ); nodeIndex < nodeList.size(); nodeIndex++ ) + for( unsigned int nodeIndex( 0 ); nodeIndex < nodeList.size(); nodeIndex++ ) { //select random module nodeList[ nodeIndex ] = rng.lrand32( numberOfIntendedModules - 1 ); histogram[ nodeList[ nodeIndex ] ]++; } // make sure no module contains no node, if one does assign it one of a random module // that does contain at least two - for( int moduleIndex( 0 ); moduleIndex < histogram.size(); moduleIndex++ ) + for( unsigned int moduleIndex( 0 ); moduleIndex < histogram.size(); moduleIndex++ ) { while( histogram[ moduleIndex ] == 0 ) { int randomNodeIndex = rng.lrand32( numberOfVertices - 1 ); if( histogram[ nodeList[ randomNodeIndex ] ] > 1 ) { histogram[ moduleIndex ]++; histogram[ nodeList[ randomNodeIndex ] ]--; nodeList[ randomNodeIndex ] = moduleIndex; } } } ToModuleMapType::iterator iter = vertexToModuleMap->begin(); ToModuleMapType::iterator end = vertexToModuleMap->end(); - for( int index( 0 ); ( iter != end ) && ( index < nodeList.size() ); index++, iter++ ) + for( unsigned int index( 0 ); ( iter != end ) && ( index < nodeList.size() ); index++, iter++ ) { iter->second = nodeList[ index ] ; } } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::SetMapping( ToModuleMapType mapping ) { m_BestSolution = mapping; } mitk::ConnectomicsSimulatedAnnealingPermutationModularity::ToModuleMapType mitk::ConnectomicsSimulatedAnnealingPermutationModularity::GetMapping() { return m_BestSolution; } double mitk::ConnectomicsSimulatedAnnealingPermutationModularity::Evaluate( ToModuleMapType* mapping ) const { mitk::ConnectomicsSimulatedAnnealingCostFunctionModularity* costMapping = dynamic_cast( m_CostFunction.GetPointer() ); if( costMapping ) { return costMapping->Evaluate( m_Network, mapping ); } else { return 0; } } bool mitk::ConnectomicsSimulatedAnnealingPermutationModularity::AcceptChange( double costBefore, double costAfter, double temperature ) const { if( costAfter <= costBefore ) {// if cost is lower after return true; } //the random number generators vnl_random rng( (unsigned int) rand() ); //randomly generate threshold const double threshold = rng.drand64( 0.0 , 1.0); //the likelihood of acceptance double likelihood = std::exp( - ( costAfter - costBefore ) / temperature ); if( threshold < likelihood ) { return true; } return false; } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::SetDepth( int depth ) { m_Depth = depth; } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::SetStepSize( double size ) { m_StepSize = size; } diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsStatisticsCalculator.cpp b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsStatisticsCalculator.cpp index fe797bba49..141db5e68c 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsStatisticsCalculator.cpp +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsStatisticsCalculator.cpp @@ -1,739 +1,739 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkConnectomicsStatisticsCalculator.h" #include "mitkConnectomicsNetworkConverter.h" #include #include #include #include #include #include "vnl/algo/vnl_symmetric_eigensystem.h" template class all_pairs_shortest_recorder : public boost::default_bfs_visitor { public: typedef typename boost::graph_traits::vertex_descriptor VertexType; typedef typename boost::graph_traits::edge_descriptor EdgeType; all_pairs_shortest_recorder(int* dist, int &max, unsigned int &size) { d = dist; ecc = &max; component_size = &size; } void tree_edge(EdgeType edge, const GraphType& graph) { VertexType u = boost::source(edge, graph); VertexType v = boost::target(edge, graph); d[v] = d[u] + 1; *ecc = d[v]; *component_size = *component_size + 1; } private: int* d; int* ecc; unsigned int* component_size; }; mitk::ConnectomicsStatisticsCalculator::ConnectomicsStatisticsCalculator() : m_Network( 0 ) , m_NumberOfVertices( 0 ) , m_NumberOfEdges( 0 ) , m_AverageDegree( 0.0 ) , m_ConnectionDensity( 0.0 ) , m_NumberOfConnectedComponents( 0 ) , m_AverageComponentSize( 0.0 ) , m_Components(0) , m_LargestComponentSize( 0 ) , m_HopPlotExponent( 0.0 ) , m_EffectiveHopDiameter( 0.0 ) , m_VectorOfClusteringCoefficientsC( 0 ) , m_VectorOfClusteringCoefficientsD( 0 ) , m_VectorOfClusteringCoefficientsE( 0 ) , m_AverageClusteringCoefficientsC( 0.0 ) , m_AverageClusteringCoefficientsD( 0.0 ) , m_AverageClusteringCoefficientsE( 0.0 ) , m_VectorOfVertexBetweennessCentralities( 0 ) , m_PropertyMapOfVertexBetweennessCentralities( ) , m_AverageVertexBetweennessCentrality( 0.0 ) , m_VectorOfEdgeBetweennessCentralities( 0 ) , m_PropertyMapOfEdgeBetweennessCentralities( ) , m_AverageEdgeBetweennessCentrality( 0.0 ) , m_NumberOfIsolatedPoints( 0 ) , m_RatioOfIsolatedPoints( 0.0 ) , m_NumberOfEndPoints( 0 ) , m_RatioOfEndPoints( 0.0 ) , m_VectorOfEccentrities( 0 ) , m_VectorOfEccentrities90( 0 ) , m_VectorOfAveragePathLengths( 0.0 ) , m_Diameter( 0 ) , m_Diameter90( 0 ) , m_Radius( 0 ) , m_Radius90( 0 ) , m_AverageEccentricity( 0.0 ) , m_AverageEccentricity90( 0.0 ) , m_AveragePathLength( 0.0 ) , m_NumberOfCentralPoints( 0 ) , m_RatioOfCentralPoints( 0.0 ) , m_VectorOfSortedEigenValues( 0 ) , m_SpectralRadius( 0.0 ) , m_SecondLargestEigenValue( 0.0 ) , m_AdjacencyTrace( 0.0 ) , m_AdjacencyEnergy( 0.0 ) , m_VectorOfSortedLaplacianEigenValues( 0 ) , m_LaplacianTrace( 0.0 ) , m_LaplacianEnergy( 0.0 ) , m_LaplacianSpectralGap( 0.0 ) , m_VectorOfSortedNormalizedLaplacianEigenValues( 0 ) , m_NormalizedLaplacianTrace( 0.0 ) , m_NormalizedLaplacianEnergy( 0.0 ) , m_NormalizedLaplacianNumberOf2s( 0 ) , m_NormalizedLaplacianNumberOf1s( 0 ) , m_NormalizedLaplacianNumberOf0s( 0 ) , m_NormalizedLaplacianLowerSlope( 0.0 ) , m_NormalizedLaplacianUpperSlope( 0.0 ) , m_SmallWorldness( 0.0 ) { } mitk::ConnectomicsStatisticsCalculator::~ConnectomicsStatisticsCalculator() { } void mitk::ConnectomicsStatisticsCalculator::Update() { CalculateNumberOfVertices(); CalculateNumberOfEdges(); CalculateAverageDegree(); CalculateConnectionDensity(); CalculateNumberOfConnectedComponents(); CalculateAverageComponentSize(); CalculateLargestComponentSize(); CalculateRatioOfNodesInLargestComponent(); CalculateHopPlotValues(); CalculateClusteringCoefficients(); CalculateBetweennessCentrality(); CalculateIsolatedAndEndPoints(); CalculateShortestPathMetrics(); CalculateSpectralMetrics(); CalculateLaplacianMetrics(); CalculateNormalizedLaplacianMetrics(); CalculateSmallWorldness(); } void mitk::ConnectomicsStatisticsCalculator::CalculateNumberOfVertices() { m_NumberOfVertices = boost::num_vertices( *(m_Network->GetBoostGraph()) ); } void mitk::ConnectomicsStatisticsCalculator::CalculateNumberOfEdges() { m_NumberOfEdges = boost::num_edges( *(m_Network->GetBoostGraph()) ); } void mitk::ConnectomicsStatisticsCalculator::CalculateAverageDegree() { m_AverageDegree = ( ( (double) m_NumberOfEdges * 2.0 ) / (double) m_NumberOfVertices ); } void mitk::ConnectomicsStatisticsCalculator::CalculateConnectionDensity() { double numberOfPossibleEdges = (double) m_NumberOfVertices * ( (double) m_NumberOfVertices - 1 ) / 2; m_ConnectionDensity = (double) m_NumberOfEdges / numberOfPossibleEdges; } void mitk::ConnectomicsStatisticsCalculator::CalculateNumberOfConnectedComponents() { m_Components.resize( m_NumberOfVertices ); m_NumberOfConnectedComponents = boost::connected_components( *(m_Network->GetBoostGraph()), &m_Components[0] ); } void mitk::ConnectomicsStatisticsCalculator::CalculateAverageComponentSize() { m_AverageComponentSize = (double) m_NumberOfVertices / (double) m_NumberOfConnectedComponents ; } void mitk::ConnectomicsStatisticsCalculator::CalculateLargestComponentSize() { m_LargestComponentSize = 0; - std::vector bins( m_NumberOfConnectedComponents ); + std::vector bins( m_NumberOfConnectedComponents ); for(unsigned int i=0; i < m_NumberOfVertices; i++) { bins[ m_Components[i] ]++; } for(unsigned int i=0; i < m_NumberOfConnectedComponents; i++) { if (bins[i] > m_LargestComponentSize ) { m_LargestComponentSize = bins[i]; } } } void mitk::ConnectomicsStatisticsCalculator::CalculateRatioOfNodesInLargestComponent() { m_RatioOfNodesInLargestComponent = (double) m_LargestComponentSize / (double) m_NumberOfVertices ; } void mitk::ConnectomicsStatisticsCalculator::CalculateHopPlotValues() { std::vector bins( m_NumberOfVertices ); VertexIteratorType vi, vi_end; unsigned int index( 0 ); for( boost::tie( vi, vi_end ) = boost::vertices( *(m_Network->GetBoostGraph()) ); vi != vi_end; ++vi) { std::vector distances(m_NumberOfVertices, 0); int max_distance = 0; VertexDescriptorType src = *vi; distances[src] = 0; unsigned int size = 0; boost::breadth_first_search(*(m_Network->GetBoostGraph()), src, visitor(all_pairs_shortest_recorder< NetworkType > (&distances[0], max_distance, size))); for(index=0; index < distances.size(); index++) { if(distances[index] > 0) { bins[distances[index]]++; } } } bins[0] = m_NumberOfVertices; for(index=1; index < bins.size(); index++) { bins[index] = bins[index] + bins[index-1]; } int counter = 0; double C=0, D=0, E=0, F=0; for (unsigned int i=1; i m_VectorOfClusteringCoefficientsC; std::vector m_VectorOfClusteringCoefficientsD; std::vector m_VectorOfClusteringCoefficientsE; typedef std::set NeighborSetType; typedef NetworkType::out_edge_iterator OutEdgeIterType; for(boost::tie(vi,vi_end) = boost::vertices( *(m_Network->GetBoostGraph()) ); vi!=vi_end; ++vi) { // Get the list of vertices which are in the neighborhood of vi. std::pair adjacent = boost::adjacent_vertices(*vi, *(m_Network->GetBoostGraph()) ); //Populate a set with the neighbors of vi NeighborSetType neighbors; for(; adjacent.first!=adjacent.second; ++adjacent.first) { neighbors.insert(*adjacent.first); } // Now, count the edges between vertices in the neighborhood. unsigned int neighborhood_edge_count = 0; if(neighbors.size() > 0) { NeighborSetType::iterator iter; for(iter = neighbors.begin(); iter != neighbors.end(); ++iter) { std::pair oe = out_edges(*iter, *(m_Network->GetBoostGraph()) ); for(; oe.first != oe.second; ++oe.first) { if(neighbors.find(target(*oe.first, *(m_Network->GetBoostGraph()) )) != neighbors.end()) { ++neighborhood_edge_count; } } } neighborhood_edge_count /= 2; } //Clustering Coefficienct C,E if(neighbors.size() > 1) { double num = neighborhood_edge_count; double denum = neighbors.size() * (neighbors.size()-1)/2; m_VectorOfClusteringCoefficientsC.push_back( num / denum); m_VectorOfClusteringCoefficientsE.push_back( num / denum); } else { m_VectorOfClusteringCoefficientsC.push_back(0.0); } //Clustering Coefficienct D if(neighbors.size() > 0) { double num = neighbors.size() + neighborhood_edge_count; double denum = ( (neighbors.size()+1) * neighbors.size()) / 2; m_VectorOfClusteringCoefficientsD.push_back( num / denum); } else { m_VectorOfClusteringCoefficientsD.push_back(0.0); } } // Average Clustering coefficienies: m_AverageClusteringCoefficientsC = std::accumulate(m_VectorOfClusteringCoefficientsC.begin(), m_VectorOfClusteringCoefficientsC.end(), 0.0) / m_NumberOfVertices; m_AverageClusteringCoefficientsD = std::accumulate(m_VectorOfClusteringCoefficientsD.begin(), m_VectorOfClusteringCoefficientsD.end(), 0.0) / m_NumberOfVertices; m_AverageClusteringCoefficientsE = std::accumulate(m_VectorOfClusteringCoefficientsE.begin(), m_VectorOfClusteringCoefficientsE.end(), 0.0) / m_VectorOfClusteringCoefficientsE.size(); } void mitk::ConnectomicsStatisticsCalculator::CalculateBetweennessCentrality() { // std::map used for convenient initialization EdgeIndexStdMapType stdEdgeIndex; // associative property map needed for iterator property map-wrapper EdgeIndexMapType edgeIndex(stdEdgeIndex); EdgeIteratorType iterator, end; // sets iterator to start end end to end boost::tie(iterator, end) = boost::edges( *(m_Network->GetBoostGraph()) ); int i(0); for ( ; iterator != end; ++iterator, ++i) { stdEdgeIndex.insert(std::pair< EdgeDescriptorType, int >( *iterator, i)); } // Define EdgeCentralityMap m_VectorOfEdgeBetweennessCentralities.resize( m_NumberOfEdges, 0.0); // Create the external property map m_PropertyMapOfEdgeBetweennessCentralities = EdgeIteratorPropertyMapType(m_VectorOfEdgeBetweennessCentralities.begin(), edgeIndex); // Define VertexCentralityMap VertexIndexMapType vertexIndex = get(boost::vertex_index, *(m_Network->GetBoostGraph()) ); m_VectorOfVertexBetweennessCentralities.resize( m_NumberOfVertices, 0.0); // Create the external property map m_PropertyMapOfVertexBetweennessCentralities = VertexIteratorPropertyMapType(m_VectorOfVertexBetweennessCentralities.begin(), vertexIndex); boost::brandes_betweenness_centrality( *(m_Network->GetBoostGraph()), m_PropertyMapOfVertexBetweennessCentralities, m_PropertyMapOfEdgeBetweennessCentralities ); m_AverageVertexBetweennessCentrality = std::accumulate(m_VectorOfVertexBetweennessCentralities.begin(), m_VectorOfVertexBetweennessCentralities.end(), 0.0) / (double) m_NumberOfVertices; m_AverageEdgeBetweennessCentrality = std::accumulate(m_VectorOfEdgeBetweennessCentralities.begin(), m_VectorOfEdgeBetweennessCentralities.end(), 0.0) / (double) m_NumberOfEdges; } void mitk::ConnectomicsStatisticsCalculator::CalculateIsolatedAndEndPoints() { m_NumberOfIsolatedPoints = 0; m_NumberOfEndPoints = 0; VertexIteratorType vi, vi_end; for( boost::tie(vi,vi_end) = boost::vertices( *(m_Network->GetBoostGraph()) ); vi!=vi_end; ++vi) { int degree = boost::out_degree(*vi, *(m_Network->GetBoostGraph()) ); if(degree == 0) { m_NumberOfIsolatedPoints++; } else if (degree == 1) { m_NumberOfEndPoints++; } } m_RatioOfEndPoints = (double) m_NumberOfEndPoints / (double) m_NumberOfVertices; m_RatioOfIsolatedPoints = (double) m_NumberOfIsolatedPoints / (double) m_NumberOfVertices; } /** * Calculates Shortest Path Related metrics of the graph. The * function runs a BFS from each node to find out the shortest * distances to other nodes in the graph. The maximum of this distance * is called the eccentricity of that node. The maximum eccentricity * in the graph is called diameter and the minimum eccentricity is * called the radius of the graph. Central points are those nodes * having eccentricity equals to radius. */ void mitk::ConnectomicsStatisticsCalculator::CalculateShortestPathMetrics() { //for all vertices: VertexIteratorType vi, vi_end; //store the eccentricities in a vector. m_VectorOfEccentrities.resize( m_NumberOfVertices ); m_VectorOfEccentrities90.resize( m_NumberOfVertices ); m_VectorOfAveragePathLengths.resize( m_NumberOfVertices ); //assign diameter and radius while iterating over the ecccencirities. m_Diameter = 0; m_Diameter90 = 0; m_Radius = std::numeric_limits::max(); m_Radius90 = std::numeric_limits::max(); m_AverageEccentricity = 0.0; m_AverageEccentricity90 = 0.0; m_AveragePathLength = 0.0; //The size of the giant connected component so far. unsigned int giant_component_size = 0; VertexDescriptorType radius_src; //Loop over the vertices for( boost::tie(vi, vi_end) = boost::vertices( *(m_Network->GetBoostGraph()) ); vi!=vi_end; ++vi) { //We are going to start a BFS, initialize the neccessary //structures for that. Store the distances of nodes from the //source in distance vector. The maximum distance is stored in //max. The BFS will start from the node that vi is pointing, that //is the src is *vi. We also init the distance of the src node to //itself to 0. size gives the number of nodes discovered during //this BFS. std::vector distances( m_NumberOfVertices ); int max_distance = 0; VertexDescriptorType src = *vi; distances[src] = 0; unsigned int size = 0; breadth_first_search(*(m_Network->GetBoostGraph()), src, visitor(all_pairs_shortest_recorder (&distances[0], max_distance, size))); // vertex vi has eccentricity equal to max_distance m_VectorOfEccentrities[src] = max_distance; //check whether there is any change in the diameter or the radius. //note that the diameter we are calculating here is also the //diameter of the giant connected component! if(m_VectorOfEccentrities[src] > m_Diameter) { m_Diameter = m_VectorOfEccentrities[src]; } //The radius should be calculated on the largest connected //component, otherwise it is very likely that radius will be 1. //We change the value of the radius only if this is the giant //connected component so far. After all the eccentricities are //found we should loop over this connected component and find the //minimum eccentricity which is the radius. So we keep the src //node, so that we can find the connected component later on. if(size > giant_component_size) { giant_component_size = size; radius_src = src; } //Calculate in how many hops we can reach 90 percent of the //nodes. We store the number of hops we can reach in h hops in the //bucket vector. That is bucket[h] gives the number of nodes //reachable in exactly h hops. sum of bucket[i bucket (max_distance+1); int counter = 0; for(unsigned int i=0; i0) { bucket[distances[i]]++; m_VectorOfAveragePathLengths[src] += distances[i]; counter ++; } } if(counter > 0) { m_VectorOfAveragePathLengths[src] = m_VectorOfAveragePathLengths[src] / counter; } int eccentricity90 = 0; while(reachable90 > 0) { eccentricity90 ++; reachable90 = reachable90 - bucket[eccentricity90]; } // vertex vi has eccentricity90 equal to eccentricity90 m_VectorOfEccentrities90[src] = eccentricity90; if(m_VectorOfEccentrities90[src] > m_Diameter90) { m_Diameter90 = m_VectorOfEccentrities90[src]; } } //We are going to calculate the radius now. We stored the src node //that when we start a BFS gives the giant connected component, and //we have the eccentricities calculated. Iterate over the nodes of //this giant component and find the minimum eccentricity. std::vector component( m_NumberOfVertices ); boost::connected_components( *(m_Network->GetBoostGraph()), &component[0]); for (unsigned int i=0; i m_VectorOfEccentrities[i]) { m_Radius = m_VectorOfEccentrities[i]; } if(m_Radius90 > m_VectorOfEccentrities90[i]) { m_Radius90 = m_VectorOfEccentrities90[i]; } } } m_AverageEccentricity = std::accumulate(m_VectorOfEccentrities.begin(), m_VectorOfEccentrities.end(), 0.0) / m_NumberOfVertices; m_AverageEccentricity90 = std::accumulate(m_VectorOfEccentrities90.begin(), m_VectorOfEccentrities90.end(), 0.0) / m_NumberOfVertices; m_AveragePathLength = std::accumulate(m_VectorOfAveragePathLengths.begin(), m_VectorOfAveragePathLengths.end(), 0.0) / m_NumberOfVertices; //calculate Number of Central Points, nodes having eccentricity = radius. m_NumberOfCentralPoints = 0; for (boost::tie(vi, vi_end) = boost::vertices( *(m_Network->GetBoostGraph()) ); vi != vi_end; ++vi) { if(m_VectorOfEccentrities[*vi] == m_Radius) { m_NumberOfCentralPoints++; } } m_RatioOfCentralPoints = (double)m_NumberOfCentralPoints / m_NumberOfVertices; } void mitk::ConnectomicsStatisticsCalculator::CalculateSpectralMetrics() { mitk::ConnectomicsNetworkConverter::Pointer converter = mitk::ConnectomicsNetworkConverter::New(); converter->SetNetwork( m_Network ); vnl_matrix adjacencyMatrix = converter->GetNetworkAsVNLAdjacencyMatrix(); vnl_symmetric_eigensystem eigenSystem(adjacencyMatrix); m_AdjacencyTrace = 0; m_AdjacencyEnergy = 0; m_VectorOfSortedEigenValues.clear(); - for(int i=0; i < m_NumberOfVertices; ++i) + for(unsigned int i=0; i < m_NumberOfVertices; ++i) { double value = std::fabs(eigenSystem.get_eigenvalue(i)); m_VectorOfSortedEigenValues.push_back(value); m_AdjacencyTrace += value; m_AdjacencyEnergy += value * value; } std::sort(m_VectorOfSortedEigenValues.begin(), m_VectorOfSortedEigenValues.end()); m_SpectralRadius = m_VectorOfSortedEigenValues[ m_NumberOfVertices - 1]; m_SecondLargestEigenValue = m_VectorOfSortedEigenValues[ m_NumberOfVertices - 2]; } void mitk::ConnectomicsStatisticsCalculator::CalculateLaplacianMetrics() { mitk::ConnectomicsNetworkConverter::Pointer converter = mitk::ConnectomicsNetworkConverter::New(); converter->SetNetwork( m_Network ); vnl_matrix adjacencyMatrix = converter->GetNetworkAsVNLAdjacencyMatrix(); vnl_matrix laplacianMatrix ( m_NumberOfVertices, m_NumberOfVertices, 0); vnl_matrix degreeMatrix = converter->GetNetworkAsVNLDegreeMatrix(); m_VectorOfSortedLaplacianEigenValues.clear(); laplacianMatrix = degreeMatrix - adjacencyMatrix; int numberOfConnectedComponents = 0; vnl_symmetric_eigensystem laplacianEigenSystem( laplacianMatrix ); m_LaplacianEnergy = 0; m_LaplacianTrace = 0; - for(int i(0); i < m_NumberOfVertices; ++i) + for(unsigned int i(0); i < m_NumberOfVertices; ++i) { double value = std::fabs( laplacianEigenSystem.get_eigenvalue(i) ); m_VectorOfSortedLaplacianEigenValues.push_back( value ); m_LaplacianTrace += value; m_LaplacianEnergy += value * value; if ( std::fabs( value ) < mitk::eps ) { numberOfConnectedComponents++; } } std::sort(m_VectorOfSortedLaplacianEigenValues.begin(), m_VectorOfSortedLaplacianEigenValues.end()); for(unsigned int i(0); i < m_VectorOfSortedLaplacianEigenValues.size(); ++i) { if(m_VectorOfSortedLaplacianEigenValues[i] > mitk::eps ) { m_LaplacianSpectralGap = m_VectorOfSortedLaplacianEigenValues[i]; break; } } } void mitk::ConnectomicsStatisticsCalculator::CalculateNormalizedLaplacianMetrics() { vnl_matrix normalizedLaplacianMatrix(m_NumberOfVertices, m_NumberOfVertices, 0); EdgeIteratorType ei, ei_end; VertexDescriptorType sourceVertex, destinationVertex; int sourceIndex, destinationIndex; VertexIndexMapType vertexIndexMap = boost::get(boost::vertex_index, *(m_Network->GetBoostGraph()) ); m_VectorOfSortedNormalizedLaplacianEigenValues.clear(); // Normalized laplacian matrix for( boost::tie(ei, ei_end) = boost::edges( *(m_Network->GetBoostGraph()) ); ei != ei_end; ++ei) { sourceVertex = boost::source(*ei, *(m_Network->GetBoostGraph()) ); sourceIndex = vertexIndexMap[sourceVertex]; destinationVertex = boost::target(*ei, *(m_Network->GetBoostGraph()) ); destinationIndex = vertexIndexMap[destinationVertex]; int sourceDegree = boost::out_degree(sourceVertex, *(m_Network->GetBoostGraph()) ); int destinationDegree = boost::out_degree(destinationVertex, *(m_Network->GetBoostGraph()) ); normalizedLaplacianMatrix.put( sourceIndex, destinationIndex, -1 / (sqrt(double(sourceDegree * destinationDegree)))); normalizedLaplacianMatrix.put( destinationIndex, sourceIndex, -1 / (sqrt(double(sourceDegree * destinationDegree)))); } VertexIteratorType vi, vi_end; for(boost::tie(vi, vi_end)=boost::vertices( *(m_Network->GetBoostGraph()) ); vi!=vi_end; ++vi) { if(boost::out_degree(*vi, *(m_Network->GetBoostGraph()) ) > 0) { normalizedLaplacianMatrix.put(vertexIndexMap[*vi], vertexIndexMap[*vi], 1); } } //End of normalized laplacian matrix definition vnl_symmetric_eigensystem normalizedLaplacianEigensystem(normalizedLaplacianMatrix); double N1=0, C1=0, D1=0, E1=0, F1=0, b1=0; double N2=0, C2=0, D2=0, E2=0, F2=0, b2=0; m_NormalizedLaplacianNumberOf2s = 0; m_NormalizedLaplacianNumberOf1s = 0; m_NormalizedLaplacianNumberOf0s = 0; m_NormalizedLaplacianTrace = 0; m_NormalizedLaplacianEnergy = 0; - for(int i(0); i< m_NumberOfVertices; ++i) + for(unsigned int i(0); i< m_NumberOfVertices; ++i) { double eigenValue = std::fabs(normalizedLaplacianEigensystem.get_eigenvalue(i)); m_VectorOfSortedNormalizedLaplacianEigenValues.push_back(eigenValue); m_NormalizedLaplacianTrace += eigenValue; m_NormalizedLaplacianEnergy += eigenValue * eigenValue; //0 if(eigenValue < mitk::eps) { m_NormalizedLaplacianNumberOf0s++; } //Between 0 and 1. else if(eigenValue > mitk::eps && eigenValue< 1 - mitk::eps) { C1 += i; D1 += eigenValue; E1 += i * eigenValue; F1 += i * i; N1 ++; } //1 else if(std::fabs( std::fabs(eigenValue) - 1) < mitk::eps) { m_NormalizedLaplacianNumberOf1s++; } //Between 1 and 2 else if(std::fabs(eigenValue) > 1+mitk::eps && std::fabs(eigenValue)< 2 - mitk::eps) { C2 += i; D2 += eigenValue; E2 += i * eigenValue; F2 += i * i; N2 ++; } //2 else if(std::fabs( std::fabs(eigenValue) - 2) < mitk::eps) { m_NormalizedLaplacianNumberOf2s++; } } b1 = (D1*F1 - C1*E1)/(F1*N1 - C1*C1); m_NormalizedLaplacianLowerSlope = (E1 - b1*C1)/F1; b2 = (D2*F2 - C2*E2)/(F2*N2 - C2*C2); m_NormalizedLaplacianUpperSlope = (E2 - b2*C2)/F2; } void mitk::ConnectomicsStatisticsCalculator::CalculateSmallWorldness() { double k( this->GetAverageDegree() ); double N( this->GetNumberOfVertices() ); // The clustering coefficient of an Erdos-Reny network is equivalent to // the likelihood two random nodes are connected double gamma = this->GetAverageClusteringCoefficientsC() / ( k / N ); //The mean path length of an Erdos-Reny network is approximately // ln( #vertices ) / ln( average degree ) double lambda = this->GetAveragePathLength() / ( std::log( N ) / std::log( k ) ); m_SmallWorldness = gamma / lambda; } diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsStatisticsCalculator.h b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsStatisticsCalculator.h index f914f6b44f..8c97aa3ce8 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsStatisticsCalculator.h +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsStatisticsCalculator.h @@ -1,242 +1,242 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkConnectomicsStatisticsCalculator_h #define mitkConnectomicsStatisticsCalculator_h #include #include #include #include "mitkCommon.h" #include "ConnectomicsExports.h" #include namespace mitk { /** * \brief A class giving functions for calculating a variety of network indices */ class Connectomics_EXPORT ConnectomicsStatisticsCalculator : public itk::Object { public: /** Standard class typedefs. */ /** Method for creation through the object factory. */ mitkClassMacro(ConnectomicsStatisticsCalculator, itk::Object); itkNewMacro(Self); // Typedefs typedef mitk::ConnectomicsNetwork::NetworkType NetworkType; typedef mitk::ConnectomicsNetwork::VertexDescriptorType VertexDescriptorType; typedef mitk::ConnectomicsNetwork::EdgeDescriptorType EdgeDescriptorType; typedef boost::graph_traits::vertex_iterator VertexIteratorType; typedef boost::graph_traits::edge_iterator EdgeIteratorType; typedef boost::graph_traits::adjacency_iterator AdjacencyIteratorType; typedef std::map EdgeIndexStdMapType; typedef boost::associative_property_map< EdgeIndexStdMapType > EdgeIndexMapType; typedef boost::iterator_property_map< std::vector< double >::iterator, EdgeIndexMapType > EdgeIteratorPropertyMapType; typedef boost::property_map< NetworkType, boost::vertex_index_t>::type VertexIndexMapType; typedef boost::iterator_property_map< std::vector< double >::iterator, VertexIndexMapType > VertexIteratorPropertyMapType; // Set/Get Macros itkSetObjectMacro( Network, mitk::ConnectomicsNetwork ); itkGetMacro( NumberOfVertices, unsigned int ); itkGetMacro( NumberOfEdges, unsigned int ); itkGetMacro( AverageDegree, double ); itkGetMacro( ConnectionDensity, double ); itkGetMacro( NumberOfConnectedComponents, unsigned int ); itkGetMacro( AverageComponentSize, double ); itkGetMacro( Components, std::vector< int > ); itkGetMacro( LargestComponentSize, unsigned int ); itkGetMacro( RatioOfNodesInLargestComponent, double ); itkGetMacro( HopPlotExponent, double ); itkGetMacro( EffectiveHopDiameter, double ); itkGetMacro( VectorOfClusteringCoefficientsC, std::vector< double > ); itkGetMacro( VectorOfClusteringCoefficientsD, std::vector< double > ); itkGetMacro( VectorOfClusteringCoefficientsE, std::vector< double > ); itkGetMacro( AverageClusteringCoefficientsC, double ); itkGetMacro( AverageClusteringCoefficientsD, double ); itkGetMacro( AverageClusteringCoefficientsE, double ); itkGetMacro( VectorOfVertexBetweennessCentralities, std::vector< double > ); itkGetMacro( PropertyMapOfVertexBetweennessCentralities, VertexIteratorPropertyMapType ); itkGetMacro( AverageVertexBetweennessCentrality, double ); itkGetMacro( VectorOfEdgeBetweennessCentralities, std::vector< double > ); itkGetMacro( PropertyMapOfEdgeBetweennessCentralities, EdgeIteratorPropertyMapType ); itkGetMacro( AverageEdgeBetweennessCentrality, double ); itkGetMacro( NumberOfIsolatedPoints, unsigned int ); itkGetMacro( RatioOfIsolatedPoints, double ); itkGetMacro( NumberOfEndPoints, unsigned int ); itkGetMacro( RatioOfEndPoints, double ); - itkGetMacro( VectorOfEccentrities, std::vector< int > ); - itkGetMacro( VectorOfEccentrities90, std::vector< int > ); + itkGetMacro( VectorOfEccentrities, std::vector< unsigned int > ); + itkGetMacro( VectorOfEccentrities90, std::vector< unsigned int > ); itkGetMacro( VectorOfAveragePathLengths, std::vector< double > ); itkGetMacro( Diameter, unsigned int ); itkGetMacro( Diameter90, unsigned int ); itkGetMacro( Radius, unsigned int ); itkGetMacro( Radius90, unsigned int ); itkGetMacro( AverageEccentricity, double ); itkGetMacro( AverageEccentricity90, double ); itkGetMacro( AveragePathLength, double ); itkGetMacro( NumberOfCentralPoints, unsigned int ); itkGetMacro( RatioOfCentralPoints, double ); itkGetMacro( VectorOfSortedEigenValues, std::vector< double > ); itkGetMacro( SpectralRadius, double ); itkGetMacro( SecondLargestEigenValue, double ); itkGetMacro( AdjacencyTrace, double ); itkGetMacro( AdjacencyEnergy, double ); itkGetMacro( VectorOfSortedLaplacianEigenValues, std::vector< double > ); itkGetMacro( LaplacianTrace, double ); itkGetMacro( LaplacianEnergy, double ); itkGetMacro( LaplacianSpectralGap, double ); itkGetMacro( VectorOfSortedNormalizedLaplacianEigenValues, std::vector< double > ); itkGetMacro( NormalizedLaplacianTrace, double ); itkGetMacro( NormalizedLaplacianEnergy, double ); itkGetMacro( NormalizedLaplacianNumberOf2s, unsigned int ); itkGetMacro( NormalizedLaplacianNumberOf1s, unsigned int ); itkGetMacro( NormalizedLaplacianNumberOf0s, unsigned int ); itkGetMacro( NormalizedLaplacianLowerSlope, double ); itkGetMacro( NormalizedLaplacianUpperSlope, double ); itkGetMacro( SmallWorldness, double ); void Update(); protected: //////////////////// Functions /////////////////////// ConnectomicsStatisticsCalculator(); ~ConnectomicsStatisticsCalculator(); void CalculateNumberOfVertices(); void CalculateNumberOfEdges(); void CalculateAverageDegree(); void CalculateConnectionDensity(); void CalculateNumberOfConnectedComponents(); void CalculateAverageComponentSize(); void CalculateLargestComponentSize(); void CalculateRatioOfNodesInLargestComponent(); void CalculateHopPlotValues(); /** * \brief Calculate the different clustering coefficients * * The clustering coefficient (cc) measures how strong the tendency to form cliques * is in the network. Groups of nodes, that are highly interconnected. * * CC C - Percentage of connections between nodes connected with the given node * CC D - Same as C, but including the connections with the given node * CC E - Same as C, but not counting isolated nodes when averaging */ void CalculateClusteringCoefficients(); void CalculateBetweennessCentrality(); void CalculateIsolatedAndEndPoints(); void CalculateShortestPathMetrics(); void CalculateSpectralMetrics(); void CalculateLaplacianMetrics(); void CalculateNormalizedLaplacianMetrics(); /** * \brief Calculate the small worldness of the network. * * This will compare the clustering coefficient and mean path length of the network * to an Erdos-Reny network of the same number of nodes and edges. */ void CalculateSmallWorldness(); /////////////////////// Variables //////////////////////// // The connectomics network, which is used for statistics calculation mitk::ConnectomicsNetwork::Pointer m_Network; // Statistics unsigned int m_NumberOfVertices; unsigned int m_NumberOfEdges; double m_AverageDegree; double m_ConnectionDensity; unsigned int m_NumberOfConnectedComponents; double m_AverageComponentSize; std::vector< int > m_Components; unsigned int m_LargestComponentSize; double m_RatioOfNodesInLargestComponent; double m_HopPlotExponent; double m_EffectiveHopDiameter; std::vector< double > m_VectorOfClusteringCoefficientsC; std::vector< double > m_VectorOfClusteringCoefficientsD; std::vector< double > m_VectorOfClusteringCoefficientsE; double m_AverageClusteringCoefficientsC; double m_AverageClusteringCoefficientsD; double m_AverageClusteringCoefficientsE; std::vector< double > m_VectorOfVertexBetweennessCentralities; VertexIteratorPropertyMapType m_PropertyMapOfVertexBetweennessCentralities; double m_AverageVertexBetweennessCentrality; std::vector< double > m_VectorOfEdgeBetweennessCentralities; EdgeIteratorPropertyMapType m_PropertyMapOfEdgeBetweennessCentralities; double m_AverageEdgeBetweennessCentrality; unsigned int m_NumberOfIsolatedPoints; double m_RatioOfIsolatedPoints; unsigned int m_NumberOfEndPoints; double m_RatioOfEndPoints; - std::vector< int > m_VectorOfEccentrities; - std::vector< int > m_VectorOfEccentrities90; + std::vector< unsigned int > m_VectorOfEccentrities; + std::vector< unsigned int > m_VectorOfEccentrities90; std::vector< double > m_VectorOfAveragePathLengths; unsigned int m_Diameter; unsigned int m_Diameter90; unsigned int m_Radius; unsigned int m_Radius90; double m_AverageEccentricity; double m_AverageEccentricity90; double m_AveragePathLength; unsigned int m_NumberOfCentralPoints; double m_RatioOfCentralPoints; std::vector m_VectorOfSortedEigenValues; double m_SpectralRadius; double m_SecondLargestEigenValue; double m_AdjacencyTrace; double m_AdjacencyEnergy; std::vector m_VectorOfSortedLaplacianEigenValues; double m_LaplacianTrace; double m_LaplacianEnergy; double m_LaplacianSpectralGap; std::vector m_VectorOfSortedNormalizedLaplacianEigenValues; double m_NormalizedLaplacianTrace; double m_NormalizedLaplacianEnergy; unsigned int m_NormalizedLaplacianNumberOf2s; unsigned int m_NormalizedLaplacianNumberOf1s; unsigned int m_NormalizedLaplacianNumberOf0s; double m_NormalizedLaplacianLowerSlope; double m_NormalizedLaplacianUpperSlope; double m_SmallWorldness; }; }// end namespace mitk #endif // mitkConnectomicsStatisticsCalculator_h diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSyntheticNetworkGenerator.cpp b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSyntheticNetworkGenerator.cpp index f0f8d58b84..d826667d56 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSyntheticNetworkGenerator.cpp +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSyntheticNetworkGenerator.cpp @@ -1,360 +1,351 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkConnectomicsSyntheticNetworkGenerator.h" #include #include #include "mitkConnectomicsConstantsManager.h" #include //for random number generation #include "vnl/vnl_random.h" #include "vnl/vnl_math.h" mitk::ConnectomicsSyntheticNetworkGenerator::ConnectomicsSyntheticNetworkGenerator() : m_LastGenerationWasSuccess( false ) { } mitk::ConnectomicsSyntheticNetworkGenerator::~ConnectomicsSyntheticNetworkGenerator() { } mitk::ConnectomicsNetwork::Pointer mitk::ConnectomicsSyntheticNetworkGenerator::CreateSyntheticNetwork(int networkTypeId, int paramterOne, double parameterTwo) { mitk::ConnectomicsNetwork::Pointer network = mitk::ConnectomicsNetwork::New(); m_LastGenerationWasSuccess = false; // give the network an artificial geometry network->SetGeometry( this->GenerateDefaultGeometry() ); switch (networkTypeId) { case 0: GenerateSyntheticCubeNetwork( network, paramterOne, parameterTwo ); break; case 1: GenerateSyntheticCenterToSurfaceNetwork( network, paramterOne, parameterTwo ); break; case 2: GenerateSyntheticRandomNetwork( network, paramterOne, parameterTwo ); break; case 3: //GenerateSyntheticScaleFreeNetwork( network, 1000 ); break; case 4: //GenerateSyntheticSmallWorldNetwork( network, 1000 ); break; default: MBI_ERROR << "Unrecognized Network ID"; } network->UpdateBounds(); return network; } mitk::Geometry3D::Pointer mitk::ConnectomicsSyntheticNetworkGenerator::GenerateDefaultGeometry() { mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); double zero( 0.0 ); double one( 1.0 ); // origin = {0,0,0} mitk::Point3D origin; origin[0] = zero; origin[1] = zero; origin[2] = zero; geometry->SetOrigin(origin); // spacing = {1,1,1} ScalarType spacing[3]; spacing[0] = one; spacing[1] = one; spacing[2] = one; geometry->SetSpacing(spacing); // transform vtkMatrix4x4* transformMatrix = vtkMatrix4x4::New(); transformMatrix->SetElement(0,0,one); transformMatrix->SetElement(1,0,zero); transformMatrix->SetElement(2,0,zero); transformMatrix->SetElement(0,1,zero); transformMatrix->SetElement(1,1,one); transformMatrix->SetElement(2,1,zero); transformMatrix->SetElement(0,2,zero); transformMatrix->SetElement(1,2,zero); transformMatrix->SetElement(2,2,one); transformMatrix->SetElement(0,3,origin[0]); transformMatrix->SetElement(1,3,origin[1]); transformMatrix->SetElement(2,3,origin[2]); transformMatrix->SetElement(3,3,1); geometry->SetIndexToWorldTransformByVtkMatrix( transformMatrix ); geometry->SetImageGeometry(true); return geometry; } void mitk::ConnectomicsSyntheticNetworkGenerator::GenerateSyntheticCubeNetwork( mitk::ConnectomicsNetwork::Pointer network, int cubeExtent, double distance ) { // map for storing the conversion from indices to vertex descriptor std::map< int, mitk::ConnectomicsNetwork::VertexDescriptorType > idToVertexMap; int vertexID(0); for( int loopX( 0 ); loopX < cubeExtent; loopX++ ) { for( int loopY( 0 ); loopY < cubeExtent; loopY++ ) { for( int loopZ( 0 ); loopZ < cubeExtent; loopZ++ ) { std::vector< float > position; std::string label; std::stringstream labelStream; labelStream << vertexID; label = labelStream.str(); position.push_back( loopX * distance ); position.push_back( loopY * distance ); position.push_back( loopZ * distance ); mitk::ConnectomicsNetwork::VertexDescriptorType newVertex = network->AddVertex( vertexID ); network->SetLabel( newVertex, label ); network->SetCoordinates( newVertex, position ); if ( idToVertexMap.count( vertexID ) > 0 ) { MITK_ERROR << "Aborting network creation, duplicate vertex ID generated."; m_LastGenerationWasSuccess = false; return; } idToVertexMap.insert( std::pair< int, mitk::ConnectomicsNetwork::VertexDescriptorType >( vertexID, newVertex) ); vertexID++; } } } int edgeID(0), edgeSourceID(0), edgeTargetID(0); // uniform weight of one int edgeWeight(1); mitk::ConnectomicsNetwork::VertexDescriptorType source; mitk::ConnectomicsNetwork::VertexDescriptorType target; for( int loopX( 0 ); loopX < cubeExtent; loopX++ ) { for( int loopY( 0 ); loopY < cubeExtent; loopY++ ) { for( int loopZ( 0 ); loopZ < cubeExtent; loopZ++ ) { // to avoid creating an edge twice (this being an undirected graph) we only generate // edges in three directions, the others will be supplied by the corresponding nodes if( loopX != 0 ) { edgeTargetID = edgeSourceID - cubeExtent * cubeExtent; source = idToVertexMap.find( edgeSourceID )->second; target = idToVertexMap.find( edgeTargetID )->second; network->AddEdge( source, target, edgeSourceID, edgeTargetID, edgeWeight); edgeID++; } if( loopY != 0 ) { edgeTargetID = edgeSourceID - cubeExtent; source = idToVertexMap.find( edgeSourceID )->second; target = idToVertexMap.find( edgeTargetID )->second; network->AddEdge( source, target, edgeSourceID, edgeTargetID, edgeWeight); edgeID++; } if( loopZ != 0 ) { edgeTargetID = edgeSourceID - 1; source = idToVertexMap.find( edgeSourceID )->second; target = idToVertexMap.find( edgeTargetID )->second; network->AddEdge( source, target, edgeSourceID, edgeTargetID, edgeWeight); edgeID++; } edgeSourceID++; } // end for( int loopZ( 0 ); loopZ < cubeExtent; loopZ++ ) } // end for( int loopY( 0 ); loopY < cubeExtent; loopY++ ) } // end for( int loopX( 0 ); loopX < cubeExtent; loopX++ ) m_LastGenerationWasSuccess = true; } void mitk::ConnectomicsSyntheticNetworkGenerator::GenerateSyntheticCenterToSurfaceNetwork( mitk::ConnectomicsNetwork::Pointer network, int numberOfPoints, double radius ) { - //the random number generators - unsigned int randomOne = (unsigned int) rand(); - unsigned int randomTwo = (unsigned int) rand(); vnl_random rng( (unsigned int) rand() ); - vnl_random rng2( (unsigned int) rand() ); mitk::ConnectomicsNetwork::VertexDescriptorType centerVertex; int vertexID(0); { //add center vertex std::vector< float > position; std::string label; std::stringstream labelStream; labelStream << vertexID; label = labelStream.str(); position.push_back( 0 ); position.push_back( 0 ); position.push_back( 0 ); centerVertex = network->AddVertex( vertexID ); network->SetLabel( centerVertex, label ); network->SetCoordinates( centerVertex, position ); }//end add center vertex // uniform weight of one int edgeWeight(1); //add vertices on sphere surface for( int loopID( 1 ); loopID < numberOfPoints; loopID++ ) { std::vector< float > position; std::string label; std::stringstream labelStream; labelStream << loopID; label = labelStream.str(); //generate random, uniformly distributed points on a sphere surface const double uVariable = rng.drand64( 0.0 , 1.0); const double vVariable = rng.drand64( 0.0 , 1.0); const double phi = 2 * vnl_math::pi * uVariable; const double theta = std::acos( 2 * vVariable - 1 ); double xpos = radius * std::cos( phi ) * std::sin( theta ); double ypos = radius * std::sin( phi ) * std::sin( theta ); double zpos = radius * std::cos( theta ); position.push_back( xpos ); position.push_back( ypos ); position.push_back( zpos ); mitk::ConnectomicsNetwork::VertexDescriptorType newVertex = network->AddVertex( loopID ); network->SetLabel( newVertex, label ); network->SetCoordinates( newVertex, position ); network->AddEdge( newVertex, centerVertex, loopID, 0, edgeWeight); } m_LastGenerationWasSuccess = true; } void mitk::ConnectomicsSyntheticNetworkGenerator::GenerateSyntheticRandomNetwork( mitk::ConnectomicsNetwork::Pointer network, int numberOfPoints, double threshold ) { // as the surface is proportional to the square of the radius the density stays the same double radius = 5 * std::sqrt( (float) numberOfPoints ); - //the random number generators - unsigned int randomOne = (unsigned int) rand(); - unsigned int randomTwo = (unsigned int) rand(); - vnl_random rng( (unsigned int) rand() ); - vnl_random rng2( (unsigned int) rand() ); // map for storing the conversion from indices to vertex descriptor std::map< int, mitk::ConnectomicsNetwork::VertexDescriptorType > idToVertexMap; //add vertices on sphere surface for( int loopID( 0 ); loopID < numberOfPoints; loopID++ ) { std::vector< float > position; std::string label; std::stringstream labelStream; labelStream << loopID; label = labelStream.str(); //generate random, uniformly distributed points on a sphere surface const double uVariable = rng.drand64( 0.0 , 1.0); const double vVariable = rng.drand64( 0.0 , 1.0); const double phi = 2 * vnl_math::pi * uVariable; const double theta = std::acos( 2 * vVariable - 1 ); double xpos = radius * std::cos( phi ) * std::sin( theta ); double ypos = radius * std::sin( phi ) * std::sin( theta ); double zpos = radius * std::cos( theta ); position.push_back( xpos ); position.push_back( ypos ); position.push_back( zpos ); mitk::ConnectomicsNetwork::VertexDescriptorType newVertex = network->AddVertex( loopID ); network->SetLabel( newVertex, label ); network->SetCoordinates( newVertex, position ); if ( idToVertexMap.count( loopID ) > 0 ) { MITK_ERROR << "Aborting network creation, duplicate vertex ID generated."; m_LastGenerationWasSuccess = false; return; } idToVertexMap.insert( std::pair< int, mitk::ConnectomicsNetwork::VertexDescriptorType >( loopID, newVertex) ); } int edgeID(0); // uniform weight of one int edgeWeight(1); mitk::ConnectomicsNetwork::VertexDescriptorType source; mitk::ConnectomicsNetwork::VertexDescriptorType target; for( int loopID( 0 ); loopID < numberOfPoints; loopID++ ) { // to avoid creating an edge twice (this being an undirected graph) we only // potentially generate edges with all nodes with a bigger ID for( int innerLoopID( loopID ); innerLoopID < numberOfPoints; innerLoopID++ ) { if( rng.drand64( 0.0 , 1.0) > threshold) { // do nothing } else { source = idToVertexMap.find( loopID )->second; target = idToVertexMap.find( innerLoopID )->second; network->AddEdge( source, target, loopID, innerLoopID, edgeWeight); edgeID++; } } // end for( int innerLoopID( loopID ); innerLoopID < numberOfPoints; innerLoopID++ ) } // end for( int loopID( 0 ); loopID < numberOfPoints; loopID++ ) m_LastGenerationWasSuccess = true; } bool mitk::ConnectomicsSyntheticNetworkGenerator::WasGenerationSuccessfull() { return m_LastGenerationWasSuccess; } diff --git a/Modules/DiffusionImaging/Connectomics/CMakeLists.txt b/Modules/DiffusionImaging/Connectomics/CMakeLists.txt index 4094285b4a..cbba888b80 100644 --- a/Modules/DiffusionImaging/Connectomics/CMakeLists.txt +++ b/Modules/DiffusionImaging/Connectomics/CMakeLists.txt @@ -1,7 +1,8 @@ MITK_CREATE_MODULE( Connectomics SUBPROJECTS MITK-DTI INCLUDE_DIRS Algorithms IODataStructures Rendering ${CMAKE_CURRENT_BINARY_DIR} DEPENDS DiffusionCore FiberTracking QmitkExt + WARNINGS_AS_ERRORS ) add_subdirectory(Testing) diff --git a/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetwork.cpp b/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetwork.cpp index 5988d67e6f..b4f2505958 100644 --- a/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetwork.cpp +++ b/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetwork.cpp @@ -1,766 +1,766 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkConnectomicsNetwork.h" #include #include #include /* Constructor and Destructor */ mitk::ConnectomicsNetwork::ConnectomicsNetwork() : m_IsModified( false ) { } mitk::ConnectomicsNetwork::~ConnectomicsNetwork() { } /* Wrapper methods */ bool mitk::ConnectomicsNetwork::EdgeExists( mitk::ConnectomicsNetwork::VertexDescriptorType vertexA, mitk::ConnectomicsNetwork::VertexDescriptorType vertexB ) const { return boost::edge(vertexA, vertexB, m_Network ).second; } void mitk::ConnectomicsNetwork::IncreaseEdgeWeight( mitk::ConnectomicsNetwork::VertexDescriptorType vertexA, mitk::ConnectomicsNetwork::VertexDescriptorType vertexB ) { m_Network[ boost::edge(vertexA, vertexB, m_Network ).first ].weight++; SetIsModified( true ); } void mitk::ConnectomicsNetwork::AddEdge( mitk::ConnectomicsNetwork::VertexDescriptorType vertexA, mitk::ConnectomicsNetwork::VertexDescriptorType vertexB ) { AddEdge(vertexA, vertexB, m_Network[ vertexA ].id, m_Network[ vertexB ].id ); } void mitk::ConnectomicsNetwork::AddEdge( mitk::ConnectomicsNetwork::VertexDescriptorType vertexA, mitk::ConnectomicsNetwork::VertexDescriptorType vertexB, int sourceID, int targetID, int weight ) { boost::add_edge( vertexA, vertexB, m_Network ); m_Network[ boost::edge(vertexA, vertexB, m_Network ).first ].sourceId = sourceID; m_Network[ boost::edge(vertexA, vertexB, m_Network ).first ].targetId = targetID; m_Network[ boost::edge(vertexA, vertexB, m_Network ).first ].weight = weight; m_Network[ boost::edge(vertexA, vertexB, m_Network ).first ].edge_weight = 1.0; SetIsModified( true ); } mitk::ConnectomicsNetwork::VertexDescriptorType mitk::ConnectomicsNetwork::AddVertex( int id ) { VertexDescriptorType vertex = boost::add_vertex( m_Network ); m_Network[vertex].id = id; SetIsModified( true ); return vertex; } void mitk::ConnectomicsNetwork::SetLabel( mitk::ConnectomicsNetwork::VertexDescriptorType vertex, std::string inLabel ) { m_Network[vertex].label = inLabel; SetIsModified( true ); } void mitk::ConnectomicsNetwork::SetCoordinates( mitk::ConnectomicsNetwork::VertexDescriptorType vertex, std::vector< float > inCoordinates ) { m_Network[vertex].coordinates = inCoordinates; SetIsModified( true ); } void mitk::ConnectomicsNetwork::clear() { m_Network.clear(); SetIsModified( true ); } /* Superclass methods, that need to be implemented */ void mitk::ConnectomicsNetwork::UpdateOutputInformation() { } void mitk::ConnectomicsNetwork::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::ConnectomicsNetwork::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::ConnectomicsNetwork::VerifyRequestedRegion() { return true; } -void mitk::ConnectomicsNetwork::SetRequestedRegion(const itk::DataObject *data ) +void mitk::ConnectomicsNetwork::SetRequestedRegion(const itk::DataObject * /*data*/ ) { } std::vector< mitk::ConnectomicsNetwork::NetworkNode > mitk::ConnectomicsNetwork::GetVectorOfAllNodes() const { boost::graph_traits::vertex_iterator iterator, end; // sets iterator to start end end to end boost::tie(iterator, end) = boost::vertices( m_Network ); std::vector< NetworkNode > vectorOfNodes; for ( ; iterator != end; ++iterator) { NetworkNode tempNode; // the value of an iterator is a descriptor tempNode = m_Network[ *iterator ]; vectorOfNodes.push_back( tempNode ); } return vectorOfNodes; } std::vector< mitk::ConnectomicsNetwork::VertexDescriptorType > mitk::ConnectomicsNetwork::GetVectorOfAllVertexDescriptors() const { boost::graph_traits::vertex_iterator iterator, end; // sets iterator to start end end to end boost::tie(iterator, end) = boost::vertices( m_Network ); std::vector< VertexDescriptorType > vectorOfDescriptors; for ( ; iterator != end; ++iterator) { vectorOfDescriptors.push_back( *iterator ); } return vectorOfDescriptors; } std::vector< std::pair< std::pair< mitk::ConnectomicsNetwork::NetworkNode, mitk::ConnectomicsNetwork::NetworkNode > , mitk::ConnectomicsNetwork::NetworkEdge > > mitk::ConnectomicsNetwork::GetVectorOfAllEdges() const { boost::graph_traits::edge_iterator iterator, end; // sets iterator to start end end to end boost::tie(iterator, end) = boost::edges( m_Network ); std::vector< std::pair< std::pair< NetworkNode, NetworkNode > , NetworkEdge > > vectorOfEdges; for ( ; iterator != end; ++iterator) { NetworkNode sourceNode, targetNode; NetworkEdge tempEdge; // the value of an iterator is a descriptor tempEdge = m_Network[ *iterator ]; sourceNode = m_Network[ boost::source( *iterator, m_Network ) ]; targetNode = m_Network[ boost::target( *iterator, m_Network ) ]; std::pair< NetworkNode, NetworkNode > nodePair( sourceNode, targetNode ); std::pair< std::pair< NetworkNode, NetworkNode > , NetworkEdge > edgePair( nodePair, tempEdge); vectorOfEdges.push_back( edgePair ); } return vectorOfEdges; } int mitk::ConnectomicsNetwork::GetNumberOfVertices() const { return boost::num_vertices( m_Network ); } int mitk::ConnectomicsNetwork::GetNumberOfEdges() const { return boost::num_edges( m_Network ); } int mitk::ConnectomicsNetwork::GetMaximumWeight() const { int maxWeight( 0 ); boost::graph_traits::edge_iterator iterator, end; // sets iterator to start end end to end boost::tie(iterator, end) = boost::edges( m_Network ); for ( ; iterator != end; ++iterator) { int tempWeight; // the value of an iterator is a descriptor tempWeight = m_Network[ *iterator ].weight; if( tempWeight > maxWeight ) { maxWeight = tempWeight; } } return maxWeight; } int mitk::ConnectomicsNetwork::GetNumberOfSelfLoops() { int noOfSelfLoops( 0 ); std::vector< std::pair< std::pair< NetworkNode, NetworkNode > , NetworkEdge > > edgeVector = GetVectorOfAllEdges(); - for( int index = 0; index < edgeVector.size() ; index++ ) + for( unsigned int index = 0; index < edgeVector.size() ; index++ ) { double sourceX, sourceY, sourceZ, targetX, targetY, targetZ; sourceX = edgeVector[ index ].first.first.coordinates[0] ; sourceY = edgeVector[ index ].first.first.coordinates[1] ; sourceZ = edgeVector[ index ].first.first.coordinates[2] ; targetX = edgeVector[ index ].first.second.coordinates[0] ; targetY = edgeVector[ index ].first.second.coordinates[1] ; targetZ = edgeVector[ index ].first.second.coordinates[2] ; // if the coordinates are the same if( sourceX > ( targetX - 0.01 ) && sourceX < ( targetX + 0.01 ) && sourceY > ( targetY - 0.01 ) && sourceY < ( targetY + 0.01 ) && sourceZ > ( targetZ - 0.01 ) && sourceZ < ( targetZ + 0.01 ) ) { noOfSelfLoops++; } } return noOfSelfLoops; } double mitk::ConnectomicsNetwork::GetAverageDegree() { double vertices = (double) GetNumberOfVertices(); double edges = (double) GetNumberOfEdges(); return ( ( edges * 2.0 ) / vertices ); } double mitk::ConnectomicsNetwork::GetConnectionDensity() { double vertices = (double) GetNumberOfVertices(); double edges = (double) GetNumberOfEdges(); double numberOfPossibleEdges = vertices * ( vertices - 1 ) / 2 ; return ( edges / numberOfPossibleEdges ); } std::vector< int > mitk::ConnectomicsNetwork::GetDegreeOfNodes( ) const { std::vector< int > vectorOfDegree; boost::graph_traits::vertex_iterator iterator, end; // sets iterator to start end end to end boost::tie( iterator, end ) = boost::vertices( m_Network ); vectorOfDegree.resize( this->GetNumberOfVertices() ); for ( ; iterator != end; ++iterator) { // the value of an iterator is a descriptor vectorOfDegree[ m_Network[ *iterator ].id ] = GetVectorOfAdjacentNodes( *iterator ).size(); } return vectorOfDegree; } std::vector< mitk::ConnectomicsNetwork::VertexDescriptorType > mitk::ConnectomicsNetwork::GetVectorOfAdjacentNodes( mitk::ConnectomicsNetwork::VertexDescriptorType vertex ) const { std::vector< mitk::ConnectomicsNetwork::VertexDescriptorType > vectorOfAdjacentNodes; boost::graph_traits::adjacency_iterator adjIter, adjEnd; boost::tie( adjIter, adjEnd ) = boost::adjacent_vertices( vertex, m_Network); for ( ; adjIter != adjEnd; ++adjIter) { vectorOfAdjacentNodes.push_back( *adjIter ); } return vectorOfAdjacentNodes; } int mitk::ConnectomicsNetwork::GetMaximumDegree() const { int maximumDegree( 0 ); std::vector< int > vectorOfDegree = GetDegreeOfNodes(); - for( int index( 0 ); index < vectorOfDegree.size(); ++index ) + for( unsigned int index( 0 ); index < vectorOfDegree.size(); ++index ) { if( maximumDegree < vectorOfDegree[ index ] ) { maximumDegree = vectorOfDegree[ index ]; } } return maximumDegree; } std::vector< double > mitk::ConnectomicsNetwork::GetLocalClusteringCoefficients( ) const { std::vector< double > vectorOfClusteringCoefficients; typedef boost::graph_traits::vertex_iterator vertexIter; vectorOfClusteringCoefficients.resize( this->GetNumberOfVertices() ); std::pair vertexPair; //for every vertex calculate the clustering coefficient int size = vectorOfClusteringCoefficients.size(); for (vertexPair = vertices(m_Network); vertexPair.first != vertexPair.second; ++vertexPair.first) { int index = m_Network[ *vertexPair.first ].id; if( index > size ) { MITK_ERROR << "Trying to access out of bounds clustering coefficient"; continue; } vectorOfClusteringCoefficients[ index ] = boost::clustering_coefficient(m_Network,*vertexPair.first) ; } return vectorOfClusteringCoefficients; } std::vector< double > mitk::ConnectomicsNetwork::GetClusteringCoefficientsByDegree( ) { std::vector< double > vectorOfClusteringCoefficients = GetLocalClusteringCoefficients(); std::vector< int > vectorOfDegree = GetDegreeOfNodes(); std::vector< double > vectorOfClusteringCoefficientsByDegree; vectorOfClusteringCoefficientsByDegree.resize( GetMaximumDegree() + 1, 0 ); // c_{mean}(k) = frac{1}_{N_{k}} sum_{i in Y(k)} c_{i} // where N_{k} is the number of vertices of degree k // Y(k) is the set of vertices of degree k // c_{i} is the local clustering coefficient of vertex i - for( int degree( 0 ); degree < vectorOfClusteringCoefficientsByDegree.size(); ++degree ) + for( unsigned int degree( 0 ); degree < vectorOfClusteringCoefficientsByDegree.size(); ++degree ) { vectorOfClusteringCoefficientsByDegree[ degree ] = 0; int n_k( 0 ); - for( int index( 0 ); index < vectorOfDegree.size(); ++index ) + for( unsigned int index( 0 ); index < vectorOfDegree.size(); ++index ) { - if( degree == vectorOfDegree[ index ] ) + if( degree == (unsigned int)vectorOfDegree[ index ] ) {// if in Y( degree ) vectorOfClusteringCoefficientsByDegree[ degree ] += vectorOfClusteringCoefficients[ index ]; n_k++; } } if( n_k != 0 ) { vectorOfClusteringCoefficientsByDegree[ degree ] = vectorOfClusteringCoefficientsByDegree[ degree ] / n_k; } } return vectorOfClusteringCoefficientsByDegree; } double mitk::ConnectomicsNetwork::GetGlobalClusteringCoefficient( ) { double globalClusteringCoefficient( 0.0 ); std::vector< double > vectorOfClusteringCoefficientsByDegree = GetClusteringCoefficientsByDegree(); std::vector< int > vectorOfDegree = GetDegreeOfNodes(); std::vector< int > degreeDistribution; degreeDistribution.resize( vectorOfClusteringCoefficientsByDegree.size(), 0 ); int normalizationParameter( 0 ); - for( int index( 0 ); index < vectorOfDegree.size(); ++index ) + for( unsigned int index( 0 ); index < vectorOfDegree.size(); ++index ) { degreeDistribution[ vectorOfDegree[ index ] ]++; normalizationParameter++; } // c_{mean} = sum_{k} P_{k} c_{mean}(k) // where P_{k} is the degree distribution // k is the degree - for( int degree( 0 ); degree < degreeDistribution.size(); ++degree ) + for( unsigned int degree( 0 ); degree < degreeDistribution.size(); ++degree ) { globalClusteringCoefficient += degreeDistribution[ degree ] / ( (double) normalizationParameter) * vectorOfClusteringCoefficientsByDegree[ degree ]; } return globalClusteringCoefficient; } mitk::ConnectomicsNetwork::NetworkType* mitk::ConnectomicsNetwork::GetBoostGraph() { return &m_Network; } void mitk::ConnectomicsNetwork::SetBoostGraph( NetworkType* newGraph ) { this->clear(); m_Network = *newGraph; this->SetIsModified( true ); } void mitk::ConnectomicsNetwork::ImportNetwort( mitk::ConnectomicsNetwork::Pointer source ) { typedef std::vector< std::pair< std::pair< NetworkNode, NetworkNode >, NetworkEdge > > EdgeVectorType; typedef std::vector< NetworkNode > VertexVectorType; this->clear(); this->SetGeometry( source->GetGeometry()); VertexVectorType vertexVector = source->GetVectorOfAllNodes(); EdgeVectorType edgeVector = source->GetVectorOfAllEdges(); std::map< int, VertexDescriptorType > idToVertexMap; - for( int loop(0); loop < vertexVector.size(); loop++ ) + for( unsigned int loop(0); loop < vertexVector.size(); loop++ ) { VertexDescriptorType newVertex = this->AddVertex( vertexVector[ loop ].id ); this->SetLabel( newVertex, vertexVector[ loop ].label ); this->SetCoordinates( newVertex, vertexVector[ loop ].coordinates ); if ( idToVertexMap.count( vertexVector[ loop ].id ) > 0 ) { MITK_ERROR << "Aborting network import, duplicate vertex ID discovered."; return; } idToVertexMap.insert( std::pair< int, VertexDescriptorType >( vertexVector[ loop ].id, newVertex) ); } - for( int loop(0); loop < edgeVector.size(); loop++ ) + for( unsigned int loop(0); loop < edgeVector.size(); loop++ ) { VertexDescriptorType source = idToVertexMap.find( edgeVector[ loop ].second.sourceId )->second; VertexDescriptorType target = idToVertexMap.find( edgeVector[ loop ].second.targetId )->second; this->AddEdge( source, target, edgeVector[ loop ].second.sourceId, edgeVector[ loop ].second.targetId, edgeVector[ loop ].second.weight); } this->SetIsModified( true ); } bool mitk::ConnectomicsNetwork::GetIsModified() const { return m_IsModified; } void mitk::ConnectomicsNetwork::SetIsModified( bool value) { m_IsModified = value; } mitk::ConnectomicsNetwork::NetworkNode mitk::ConnectomicsNetwork::GetNode( VertexDescriptorType vertex ) const { return m_Network[ vertex ]; } mitk::ConnectomicsNetwork::NetworkEdge mitk::ConnectomicsNetwork::GetEdge( VertexDescriptorType vertexA, VertexDescriptorType vertexB ) const { return m_Network[ boost::edge(vertexA, vertexB, m_Network ).first ]; } void mitk::ConnectomicsNetwork::UpdateBounds( ) { float min = itk::NumericTraits::min(); float max = itk::NumericTraits::max(); float bounds[] = {max, min, max, min, max, min}; std::vector< mitk::ConnectomicsNetwork::NetworkNode > nodeVector = this->GetVectorOfAllNodes(); if( nodeVector.size() == 0 ) { bounds[0] = 0; bounds[1] = 1; bounds[2] = 0; bounds[3] = 1; bounds[4] = 0; bounds[5] = 1; } // for each direction, make certain the point is in between for( int index(0), end(nodeVector.size()) ; index < end; index++ ) { - for( int direction(0); direction < nodeVector.at( index ).coordinates.size(); direction++ ) + for( unsigned int direction(0); direction < nodeVector.at( index ).coordinates.size(); direction++ ) { if( nodeVector.at( index ).coordinates.at(direction) < bounds[ 2 * direction ] ) { bounds[ 2 * direction ] = nodeVector.at( index ).coordinates.at(direction); } if( nodeVector.at( index ).coordinates.at(direction) > bounds[ 2 * direction + 1] ) { bounds[ 2 * direction + 1] = nodeVector.at( index ).coordinates.at(direction); } } } // provide some border margin for(int i=0; i<=4; i+=2) { bounds[i] -=10; } for(int i=1; i<=5; i+=2) { bounds[i] +=10; } this->GetGeometry()->SetFloatBounds(bounds); this->GetTimeGeometry()->Update(); } void mitk::ConnectomicsNetwork::PruneUnconnectedSingleNodes() { boost::graph_traits::vertex_iterator iterator, end; // set to true if iterators are invalidated by deleting a vertex bool vertexHasBeenRemoved( true ); // if no vertex has been removed in the last loop, we are done while( vertexHasBeenRemoved ) { vertexHasBeenRemoved = false; // sets iterator to start and end to end boost::tie(iterator, end) = boost::vertices( m_Network ); for ( ; iterator != end && !vertexHasBeenRemoved; ++iterator) { // If the node has no adjacent vertices it should be deleted if( GetVectorOfAdjacentNodes( *iterator ).size() == 0 ) { vertexHasBeenRemoved = true; // this invalidates all iterators boost::remove_vertex( *iterator, m_Network ); } } } UpdateIDs(); } void mitk::ConnectomicsNetwork::UpdateIDs() { boost::graph_traits::vertex_iterator v_i, v_end; boost::graph_traits::edge_iterator e_i, e_end; // update node ids boost::tie( v_i, v_end ) = boost::vertices( m_Network ); for ( ; v_i != v_end; ++v_i) { m_Network[*v_i].id = *v_i; } // update edge information boost::tie(e_i, e_end) = boost::edges( m_Network ); for ( ; e_i != e_end; ++e_i) { m_Network[ *e_i ].sourceId = m_Network[ boost::source( *e_i, m_Network ) ].id; m_Network[ *e_i ].targetId = m_Network[ boost::target( *e_i, m_Network ) ].id; } this->SetIsModified( true ); } std::vector< double > mitk::ConnectomicsNetwork::GetNodeBetweennessVector() const { std::vector< double > betweennessVector; betweennessVector.clear(); betweennessVector.resize( this->GetNumberOfVertices() ); boost::brandes_betweenness_centrality( m_Network, boost::centrality_map( boost::make_iterator_property_map( betweennessVector.begin(), boost::get( &NetworkNode::id, m_Network ), double() ) ).vertex_index_map( boost::get( &NetworkNode::id, m_Network ) ) ); return betweennessVector; } std::vector< double > mitk::ConnectomicsNetwork::GetEdgeBetweennessVector() const { // std::map used for convenient initialization typedef std::map EdgeIndexStdMap; EdgeIndexStdMap stdEdgeIndex; // associative property map needed for iterator property map-wrapper typedef boost::associative_property_map< EdgeIndexStdMap > EdgeIndexMap; EdgeIndexMap edgeIndex(stdEdgeIndex); boost::graph_traits::edge_iterator iterator, end; // sets iterator to start end end to end boost::tie(iterator, end) = boost::edges( m_Network ); int i(0); for ( ; iterator != end; ++iterator, ++i) { stdEdgeIndex.insert(std::pair< EdgeDescriptorType, int >( *iterator, i)); } // Define EdgeCentralityMap std::vector< double > edgeBetweennessVector(boost::num_edges( m_Network ), 0.0); // Create the external property map boost::iterator_property_map< std::vector< double >::iterator, EdgeIndexMap > e_centrality_map(edgeBetweennessVector.begin(), edgeIndex); // Define VertexCentralityMap typedef boost::property_map< NetworkType, boost::vertex_index_t>::type VertexIndexMap; VertexIndexMap vertexIndex = get(boost::vertex_index, m_Network ); std::vector< double > betweennessVector(boost::num_vertices( m_Network ), 0.0); // Create the external property map boost::iterator_property_map< std::vector< double >::iterator, VertexIndexMap > v_centrality_map(betweennessVector.begin(), vertexIndex); boost::brandes_betweenness_centrality( m_Network, v_centrality_map, e_centrality_map ); return edgeBetweennessVector; } std::vector< double > mitk::ConnectomicsNetwork::GetShortestDistanceVectorFromLabel( std::string targetLabel ) const { std::vector< VertexDescriptorType > predecessorMap( boost::num_vertices( m_Network ) ); int numberOfNodes( boost::num_vertices( m_Network ) ); std::vector< double > distanceMatrix; distanceMatrix.resize( numberOfNodes ); boost::graph_traits::vertex_iterator iterator, end; boost::tie(iterator, end) = boost::vertices( m_Network ); while( (iterator != end) && (m_Network[ *iterator ].label != targetLabel) ) { ++iterator; } if( iterator == end ) { MITK_WARN << "Label not found"; return distanceMatrix; } boost::dijkstra_shortest_paths(m_Network, *iterator, boost::predecessor_map(&predecessorMap[ 0 ]).distance_map(&distanceMatrix[ 0 ]).weight_map( boost::get( &NetworkEdge::edge_weight ,m_Network ) ) ) ; return distanceMatrix; } bool mitk::ConnectomicsNetwork::CheckForLabel( std::string targetLabel ) const { boost::graph_traits::vertex_iterator iterator, end; boost::tie(iterator, end) = boost::vertices( m_Network ); while( (iterator != end) && (m_Network[ *iterator ].label != targetLabel) ) { ++iterator; } if( iterator == end ) { return false; } return true; } bool mitk::Equal( mitk::ConnectomicsNetwork* leftHandSide, mitk::ConnectomicsNetwork* rightHandSide, mitk::ScalarType eps, bool verbose ) { bool noDifferenceFound = true; if( rightHandSide == NULL ) { if(verbose) { MITK_INFO << "[Equal( ConnectomicsNetwork*, ConnectomicsNetwork* )] rightHandSide NULL."; } return false; } if( leftHandSide == NULL ) { if(verbose) { MITK_INFO << "[Equal( ConnectomicsNetwork*, ConnectomicsNetwork* )] leftHandSide NULL."; } return false; } mitk::ConnectomicsStatisticsCalculator::Pointer calculatorLeft = mitk::ConnectomicsStatisticsCalculator::New(); mitk::ConnectomicsStatisticsCalculator::Pointer calculatorRight = mitk::ConnectomicsStatisticsCalculator::New(); calculatorLeft->SetNetwork( leftHandSide ); calculatorRight->SetNetwork( rightHandSide ); calculatorLeft->Update(); calculatorRight->Update(); if( ! mitk::Equal( calculatorLeft->GetNumberOfVertices(), calculatorRight->GetNumberOfVertices(), eps ) ) { if(verbose) MITK_INFO << "[Equal( ConnectomicsNetwork*, ConnectomicsNetwork* )] Number of vertices not equal. " << calculatorLeft->GetNumberOfVertices() << " vs " << calculatorRight->GetNumberOfVertices(); noDifferenceFound = false; } if( ! mitk::Equal( calculatorLeft->GetNumberOfEdges(), calculatorRight->GetNumberOfEdges(), eps ) ) { if(verbose) MITK_INFO << "[Equal( ConnectomicsNetwork*, ConnectomicsNetwork* )] Number of edges not equal. " << calculatorLeft->GetNumberOfEdges() << " vs " << calculatorRight->GetNumberOfEdges(); noDifferenceFound = false; } if( ! mitk::Equal( calculatorLeft->GetSmallWorldness(), calculatorRight->GetSmallWorldness(), eps ) ) { if(verbose) MITK_INFO << "[Equal( ConnectomicsNetwork*, ConnectomicsNetwork* )] Small worldness not equal. " << calculatorLeft->GetSmallWorldness() << " vs " << calculatorRight->GetSmallWorldness(); noDifferenceFound = false; } return noDifferenceFound; } diff --git a/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetwork.h b/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetwork.h index 6ee578d0ea..af16f89058 100644 --- a/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetwork.h +++ b/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetwork.h @@ -1,235 +1,235 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_ConnectomicsNetwork_H #define _MITK_ConnectomicsNetwork_H #include "ConnectomicsExports.h" #include "mitkBaseData.h" #include namespace mitk { /** * \brief Connectomics Network Class * * This class is designed to represent a connectomics network (brain network). It encapsulates a * boost adjacency list and provides additional capabilities. The information contained in the nodes and edges is: * * Network Node: *
    *
  • int ID - The id of the node *
  • string label - The label of the node, this can be any string, such as an anatomical label *
  • vector coordinates - The coordinates the node should be displayed at *
* * Network Edge: *
    *
  • int sourceId - The Id of the source node *
  • int targetId - The Id of the target node *
  • int weight - Weight of the edge as int (used for counting fibers) *
  • double edge_weight - Used for boost and algorithms, should be between 0 and 1 *
*/ class Connectomics_EXPORT ConnectomicsNetwork : public BaseData { public: /** Structs for the graph */ /** The Node */ struct NetworkNode { int id; std::string label; std::vector< float > coordinates; }; /** The Edge */ struct NetworkEdge { int sourceId; int targetId; int weight; // For now the number of times it was present double edge_weight; // For boost, currently set to 1 by default for unweighted calculations }; /** Typedefs **/ //typedef boost::adjacency_list< boost::listS, boost::listS, boost::undirectedS, NetworkNode, NetworkEdge > NetworkType; typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS, NetworkNode, NetworkEdge > NetworkType; typedef boost::graph_traits::vertex_descriptor VertexDescriptorType; typedef boost::graph_traits::edge_descriptor EdgeDescriptorType; // virtual methods that need to be implemented virtual void UpdateOutputInformation(); virtual void SetRequestedRegionToLargestPossibleRegion(); virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); virtual bool VerifyRequestedRegion(); - virtual void SetRequestedRegion(const itk::DataObject *data ); + virtual void SetRequestedRegion(const itk::DataObject * ); // Macros mitkClassMacro( ConnectomicsNetwork, BaseData ); itkNewMacro( Self ); ////////////////// Interface /////////////////// /** return whether an edge exists between the two given vertices */ bool EdgeExists( VertexDescriptorType vertexA, VertexDescriptorType vertexB ) const; /** increase the weight of an edge between the two given vertices */ void IncreaseEdgeWeight( VertexDescriptorType vertexA, VertexDescriptorType vertexB ); /** add an edge between two given vertices */ void AddEdge( VertexDescriptorType vertexA, VertexDescriptorType vertexB); /** add an edge between two given vertices ( with a specific weight ) */ void AddEdge( VertexDescriptorType vertexA, VertexDescriptorType vertexB, int sourceID, int targetID, int weight = 1 ); /** add a vertex with a specified id */ VertexDescriptorType AddVertex( int id); /** set the label of a vertex */ void SetLabel( VertexDescriptorType vertex, std::string inLabel ); /** set the coordinates of a vertex */ void SetCoordinates( VertexDescriptorType vertex, std::vector< float > inCoordinates ); /** clear the graph */ void clear(); /** return the node struct for a given node descriptor */ NetworkNode GetNode( VertexDescriptorType vertex ) const; /** return the edge struct for two given node descriptors */ NetworkEdge GetEdge( VertexDescriptorType vertexA, VertexDescriptorType vertexB ) const; /** get vector containing all the nodes of the network */ std::vector< NetworkNode > GetVectorOfAllNodes() const; /** get vector containing all the vertex descriptors of the network */ std::vector< VertexDescriptorType > GetVectorOfAllVertexDescriptors() const; /** get vector containing the descriptors of nodes adjacent to the vertex denoted by the given descriptor */ std::vector< VertexDescriptorType > GetVectorOfAdjacentNodes( VertexDescriptorType vertex ) const; /** get vector containing all the edges of the network and the connected nodes */ std::vector< std::pair< std::pair< NetworkNode, NetworkNode > , NetworkEdge > > GetVectorOfAllEdges() const; /** get overall number of vertices in the network */ int GetNumberOfVertices() const; /** get overall number of edges in the network */ int GetNumberOfEdges() const; /** get number of vertices, that are connected to themselves */ int GetNumberOfSelfLoops(); /** get number of vertices, that are connected to themselves */ double GetAverageDegree(); /** get number of edges divided by number of possible edges */ double GetConnectionDensity(); /** Get the maximum weight of all edges */ int GetMaximumWeight() const; /** Get a vector in the format vector[ vertexID ] = degree */ std::vector< int > GetDegreeOfNodes( ) const; /** Get the maximum degree of all nodes */ int GetMaximumDegree() const; /** Get a vector in the format vector[ vertexID ] = clustering coefficient */ std::vector< double > GetLocalClusteringCoefficients( ) const; /** Get a vector in the format vector[ degree ] = average clustering coefficient */ std::vector< double > GetClusteringCoefficientsByDegree( ); /** Get the global clustering coefficient */ double GetGlobalClusteringCoefficient( ); /** Get the betweenness centrality for each vertex in form of a vector of length (number vertices)*/ std::vector< double > GetNodeBetweennessVector() const; /** Get the betweenness centrality for each edge in form of a vector of length (number edges)*/ std::vector< double > GetEdgeBetweennessVector() const; /** Check whether a vertex with the specified label exists*/ bool CheckForLabel( std::string targetLabel ) const; /** Get the shortest distance from a specified vertex to all other vertices in form of a vector of length (number vertices)*/ std::vector< double > GetShortestDistanceVectorFromLabel( std::string targetLabel ) const; /** Access boost graph directly */ NetworkType* GetBoostGraph(); /** Set the boost graph directly */ void SetBoostGraph( NetworkType* newGraph ); void ImportNetwort( mitk::ConnectomicsNetwork::Pointer source ); /** Get the modified flag */ bool GetIsModified() const; /** Set the modified flag */ void SetIsModified( bool ); /** Update the bounds of the geometry to fit the network */ void UpdateBounds( ); /** Remove nodes not connected to any other node */ void PruneUnconnectedSingleNodes(); /** This function will relabel all vertices and edges in a continuous manner * * Mainly important after removing vertices, to make sure that the ids run continuously from * 0 to number of vertices - 1 and edge target and source ids match the corresponding node. */ void UpdateIDs(); protected: ConnectomicsNetwork(); virtual ~ConnectomicsNetwork(); NetworkType m_Network; /// Flag which indicates whether the network has been modified since the last check /// /// mainly for rendering purposes bool m_IsModified; private: }; /** * \brief Returns true if the networks are considered equal. * * For now two networks are considered equal if they have the following properties are equal: * - Number of nodes * - Number of edges * - Smallworldness */ Connectomics_EXPORT bool Equal( mitk::ConnectomicsNetwork* leftHandSide, mitk::ConnectomicsNetwork* rightHandSide, mitk::ScalarType eps, bool verbose); } // namespace mitk #endif /* _MITK_ConnectomicsNetwork_H */ diff --git a/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetworkReader.cpp b/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetworkReader.cpp index 9c88b40362..568a9415f0 100644 --- a/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetworkReader.cpp +++ b/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetworkReader.cpp @@ -1,275 +1,275 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkConnectomicsNetworkReader.h" #include "mitkConnectomicsNetworkDefinitions.h" #include #include "itksys/SystemTools.hxx" #include void mitk::ConnectomicsNetworkReader::GenerateData() { MITK_INFO << "Reading connectomics network"; if ( ( ! m_OutputCache ) ) { Superclass::SetNumberOfRequiredOutputs(0); this->GenerateOutputInformation(); } if (!m_OutputCache) { itkWarningMacro("Tree cache is empty!"); } Superclass::SetNumberOfRequiredOutputs(1); Superclass::SetNthOutput(0, m_OutputCache.GetPointer()); } void mitk::ConnectomicsNetworkReader::GenerateOutputInformation() { m_OutputCache = OutputType::New(); std::string ext = itksys::SystemTools::GetFilenameLastExtension(m_FileName); ext = itksys::SystemTools::LowerCase(ext); if ( m_FileName == "") { MITK_ERROR << "No file name specified."; } else if (ext == ".cnf") { try { TiXmlDocument doc( m_FileName ); bool loadOkay = doc.LoadFile(); if(!loadOkay) { mitkThrow() << "Could not open file " << m_FileName << " for reading."; } TiXmlHandle hDoc(&doc); TiXmlElement* pElem; TiXmlHandle hRoot(0); pElem = hDoc.FirstChildElement().Element(); // save this for later hRoot = TiXmlHandle(pElem); pElem = hRoot.FirstChildElement(mitk::ConnectomicsNetworkDefinitions::XML_GEOMETRY).Element(); // read geometry mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); // read origin mitk::Point3D origin; double temp = 0; pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_ORIGIN_X, &temp); origin[0] = temp; pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_ORIGIN_Y, &temp); origin[1] = temp; pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_ORIGIN_Z, &temp); origin[2] = temp; geometry->SetOrigin(origin); // read spacing ScalarType spacing[3]; pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_SPACING_X, &temp); spacing[0] = temp; pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_SPACING_Y, &temp); spacing[1] = temp; pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_SPACING_Z, &temp); spacing[2] = temp; geometry->SetSpacing(spacing); // read transform vtkMatrix4x4* m = vtkMatrix4x4::New(); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_XX, &temp); m->SetElement(0,0,temp); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_XY, &temp); m->SetElement(1,0,temp); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_XZ, &temp); m->SetElement(2,0,temp); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_YX, &temp); m->SetElement(0,1,temp); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_YY, &temp); m->SetElement(1,1,temp); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_YZ, &temp); m->SetElement(2,1,temp); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_ZX, &temp); m->SetElement(0,2,temp); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_ZY, &temp); m->SetElement(1,2,temp); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_ZZ, &temp); m->SetElement(2,2,temp); m->SetElement(0,3,origin[0]); m->SetElement(1,3,origin[1]); m->SetElement(2,3,origin[2]); m->SetElement(3,3,1); geometry->SetIndexToWorldTransformByVtkMatrix(m); geometry->SetImageGeometry(true); m_OutputCache->SetGeometry(geometry); // read network std::map< int, mitk::ConnectomicsNetwork::VertexDescriptorType > idToVertexMap; // read vertices pElem = hRoot.FirstChildElement(mitk::ConnectomicsNetworkDefinitions::XML_VERTICES).Element(); { // walk through the vertices TiXmlElement* vertexElement = pElem->FirstChildElement(); - for( vertexElement; vertexElement; vertexElement=vertexElement->NextSiblingElement()) + for( ; vertexElement; vertexElement=vertexElement->NextSiblingElement()) { std::vector< float > pos; std::string label; int vertexID(0); vertexElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_X, &temp); pos.push_back(temp); vertexElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_Y, &temp); pos.push_back(temp); vertexElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_Z, &temp); pos.push_back(temp); vertexElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_ID, &vertexID); vertexElement->QueryStringAttribute(mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_LABEL, &label); mitk::ConnectomicsNetwork::VertexDescriptorType newVertex = m_OutputCache->AddVertex( vertexID ); m_OutputCache->SetLabel( newVertex, label ); m_OutputCache->SetCoordinates( newVertex, pos ); if ( idToVertexMap.count( vertexID ) > 0 ) { MITK_ERROR << "Aborting network creation, duplicate vertex ID in file."; return; } idToVertexMap.insert( std::pair< int, mitk::ConnectomicsNetwork::VertexDescriptorType >( vertexID, newVertex) ); } } // read edges pElem = hRoot.FirstChildElement(mitk::ConnectomicsNetworkDefinitions::XML_EDGES).Element(); { // walk through the edges TiXmlElement* edgeElement = pElem->FirstChildElement(); - for( edgeElement; edgeElement; edgeElement=edgeElement->NextSiblingElement()) + for( ; edgeElement; edgeElement=edgeElement->NextSiblingElement()) { int edgeID(0), edgeSourceID(0), edgeTargetID(0), edgeWeight(0); edgeElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_EDGE_ID, &edgeID); edgeElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_EDGE_SOURCE_ID, &edgeSourceID); edgeElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_EDGE_TARGET_ID, &edgeTargetID); edgeElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_EDGE_WEIGHT_ID, &edgeWeight); mitk::ConnectomicsNetwork::VertexDescriptorType source = idToVertexMap.find( edgeSourceID )->second; mitk::ConnectomicsNetwork::VertexDescriptorType target = idToVertexMap.find( edgeTargetID )->second; m_OutputCache->AddEdge( source, target, edgeSourceID, edgeTargetID, edgeWeight); } } m_OutputCache->UpdateBounds(); MITK_INFO << "Network read"; } catch (mitk::Exception e) { MITK_ERROR << e.GetDescription(); } catch(...) { MITK_ERROR << "Unknown error occured while trying to read file."; } } } void mitk::ConnectomicsNetworkReader::Update() { this->GenerateData(); } const char* mitk::ConnectomicsNetworkReader::GetFileName() const { return m_FileName.c_str(); } void mitk::ConnectomicsNetworkReader::SetFileName(const char* aFileName) { m_FileName = aFileName; } const char* mitk::ConnectomicsNetworkReader::GetFilePrefix() const { return m_FilePrefix.c_str(); } void mitk::ConnectomicsNetworkReader::SetFilePrefix(const char* aFilePrefix) { m_FilePrefix = aFilePrefix; } const char* mitk::ConnectomicsNetworkReader::GetFilePattern() const { return m_FilePattern.c_str(); } void mitk::ConnectomicsNetworkReader::SetFilePattern(const char* aFilePattern) { m_FilePattern = aFilePattern; } bool mitk::ConnectomicsNetworkReader::CanReadFile( const std::string filename, const std::string /*filePrefix*/, const std::string /*filePattern*/) { // First check the extension if( filename == "" ) { return false; } std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename); ext = itksys::SystemTools::LowerCase(ext); if (ext == ".cnf") { return true; } return false; } mitk::BaseDataSource::DataObjectPointer mitk::ConnectomicsNetworkReader::MakeOutput(const DataObjectIdentifierType &name) { itkDebugMacro("MakeOutput(" << name << ")"); if( this->IsIndexedOutputName(name) ) { return this->MakeOutput( this->MakeIndexFromOutputName(name) ); } return static_cast(OutputType::New().GetPointer()); } mitk::BaseDataSource::DataObjectPointer mitk::ConnectomicsNetworkReader::MakeOutput(DataObjectPointerArraySizeType /*idx*/) { return OutputType::New().GetPointer(); } diff --git a/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetworkWriter.cpp b/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetworkWriter.cpp index 213c18b482..b880c28151 100644 --- a/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetworkWriter.cpp +++ b/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetworkWriter.cpp @@ -1,157 +1,157 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkConnectomicsNetworkWriter.h" #include "mitkConnectomicsNetworkDefinitions.h" #include #include "itksys/SystemTools.hxx" mitk::ConnectomicsNetworkWriter::ConnectomicsNetworkWriter() : m_FileName(""), m_FilePrefix(""), m_FilePattern(""), m_Success(false) { this->SetNumberOfRequiredInputs( 1 ); } mitk::ConnectomicsNetworkWriter::~ConnectomicsNetworkWriter() {} void mitk::ConnectomicsNetworkWriter::GenerateData() { MITK_INFO << "Writing connectomics network"; m_Success = false; InputType* input = this->GetInput(); if (input == NULL) { itkWarningMacro(<<"Sorry, input to ConnectomicsNetworkWriter is NULL!"); return; } if ( m_FileName == "" ) { itkWarningMacro( << "Sorry, filename has not been set!" ); return ; } std::string ext = itksys::SystemTools::GetFilenameLastExtension(m_FileName); ext = itksys::SystemTools::LowerCase(ext); if (ext == ".cnf") { // Get geometry of the network mitk::Geometry3D* geometry = input->GetGeometry(); // Create XML document TiXmlDocument documentXML; { // begin document TiXmlDeclaration* declXML = new TiXmlDeclaration( "1.0", "", "" ); // TODO what to write here? encoding? etc.... documentXML.LinkEndChild( declXML ); TiXmlElement* mainXML = new TiXmlElement(mitk::ConnectomicsNetworkDefinitions::XML_CONNECTOMICS_FILE); mainXML->SetAttribute(mitk::ConnectomicsNetworkDefinitions::XML_FILE_VERSION, mitk::ConnectomicsNetworkDefinitions::VERSION_STRING); documentXML.LinkEndChild(mainXML); TiXmlElement* geometryXML = new TiXmlElement(mitk::ConnectomicsNetworkDefinitions::XML_GEOMETRY); { // begin geometry geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_XX, geometry->GetMatrixColumn(0)[0]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_XY, geometry->GetMatrixColumn(0)[1]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_XZ, geometry->GetMatrixColumn(0)[2]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_YX, geometry->GetMatrixColumn(1)[0]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_YY, geometry->GetMatrixColumn(1)[1]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_YZ, geometry->GetMatrixColumn(1)[2]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_ZX, geometry->GetMatrixColumn(2)[0]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_ZY, geometry->GetMatrixColumn(2)[1]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_ZZ, geometry->GetMatrixColumn(2)[2]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_ORIGIN_X, geometry->GetOrigin()[0]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_ORIGIN_Y, geometry->GetOrigin()[1]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_ORIGIN_Z, geometry->GetOrigin()[2]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_SPACING_X, geometry->GetSpacing()[0]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_SPACING_Y, geometry->GetSpacing()[1]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_SPACING_Z, geometry->GetSpacing()[2]); } // end geometry mainXML->LinkEndChild(geometryXML); TiXmlElement* verticesXML = new TiXmlElement(mitk::ConnectomicsNetworkDefinitions::XML_VERTICES); { // begin vertices section VertexVectorType vertexVector = this->GetInput()->GetVectorOfAllNodes(); - for( int index = 0; index < vertexVector.size(); index++ ) + for( unsigned int index = 0; index < vertexVector.size(); index++ ) { // not localized as of yet TODO TiXmlElement* vertexXML = new TiXmlElement(mitk::ConnectomicsNetworkDefinitions::XML_VERTEX ); vertexXML->SetAttribute( mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_ID , vertexVector[ index ].id ); vertexXML->SetAttribute( mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_LABEL , vertexVector[ index ].label ); vertexXML->SetDoubleAttribute( mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_X , vertexVector[ index ].coordinates[0] ); vertexXML->SetDoubleAttribute( mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_Y , vertexVector[ index ].coordinates[1] ); vertexXML->SetDoubleAttribute( mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_Z , vertexVector[ index ].coordinates[2] ); verticesXML->LinkEndChild(vertexXML); } } // end vertices section mainXML->LinkEndChild(verticesXML); TiXmlElement* edgesXML = new TiXmlElement(mitk::ConnectomicsNetworkDefinitions::XML_EDGES); { // begin edges section EdgeVectorType edgeVector = this->GetInput()->GetVectorOfAllEdges(); - for( int index = 0; index < edgeVector.size(); index++ ) + for(unsigned int index = 0; index < edgeVector.size(); index++ ) { TiXmlElement* edgeXML = new TiXmlElement(mitk::ConnectomicsNetworkDefinitions::XML_EDGE ); edgeXML->SetAttribute( mitk::ConnectomicsNetworkDefinitions::XML_EDGE_ID , index ); edgeXML->SetAttribute( mitk::ConnectomicsNetworkDefinitions::XML_EDGE_SOURCE_ID , edgeVector[ index ].second.sourceId ); edgeXML->SetAttribute( mitk::ConnectomicsNetworkDefinitions::XML_EDGE_TARGET_ID , edgeVector[ index ].second.targetId ); edgeXML->SetAttribute( mitk::ConnectomicsNetworkDefinitions::XML_EDGE_WEIGHT_ID , edgeVector[ index ].second.weight ); edgesXML->LinkEndChild(edgeXML); } } // end edges section mainXML->LinkEndChild(edgesXML); } // end document documentXML.SaveFile( m_FileName ); m_Success = true; MITK_INFO << "Connectomics network written"; } } void mitk::ConnectomicsNetworkWriter::SetInputConnectomicsNetwork( InputType* conNetwork ) { this->ProcessObject::SetNthInput( 0, conNetwork ); } mitk::ConnectomicsNetwork* mitk::ConnectomicsNetworkWriter::GetInput() { if ( this->GetNumberOfInputs() < 1 ) { return NULL; } else { return dynamic_cast ( this->ProcessObject::GetInput( 0 ) ); } } std::vector mitk::ConnectomicsNetworkWriter::GetPossibleFileExtensions() { std::vector possibleFileExtensions; possibleFileExtensions.push_back(".cnf"); return possibleFileExtensions; } diff --git a/Modules/DiffusionImaging/Connectomics/Rendering/mitkConnectomicsNetworkMapper3D.cpp b/Modules/DiffusionImaging/Connectomics/Rendering/mitkConnectomicsNetworkMapper3D.cpp index 0d54c1bebb..585d22003c 100644 --- a/Modules/DiffusionImaging/Connectomics/Rendering/mitkConnectomicsNetworkMapper3D.cpp +++ b/Modules/DiffusionImaging/Connectomics/Rendering/mitkConnectomicsNetworkMapper3D.cpp @@ -1,757 +1,749 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkConnectomicsNetworkMapper3D.h" #include #include "vtkGraphLayout.h" #include #include "vtkGraphToPolyData.h" #include #include "vtkGlyph3D.h" #include "vtkGlyphSource2D.h" #include "mitkConnectomicsRenderingProperties.h" #include "mitkConnectomicsRenderingSchemeProperty.h" #include "mitkConnectomicsRenderingEdgeFilteringProperty.h" #include "mitkConnectomicsRenderingNodeFilteringProperty.h" #include "mitkConnectomicsRenderingNodeColorParameterProperty.h" #include "mitkConnectomicsRenderingNodeRadiusParameterProperty.h" #include "mitkConnectomicsRenderingEdgeColorParameterProperty.h" #include "mitkConnectomicsRenderingEdgeRadiusParameterProperty.h" #include "mitkConnectomicsRenderingNodeThresholdParameterProperty.h" #include "mitkConnectomicsRenderingEdgeThresholdParameterProperty.h" #include mitk::ConnectomicsNetworkMapper3D::ConnectomicsNetworkMapper3D() { m_NetworkAssembly = vtkPropAssembly::New(); } mitk::ConnectomicsNetworkMapper3D:: ~ConnectomicsNetworkMapper3D() { m_NetworkAssembly->Delete(); } void mitk::ConnectomicsNetworkMapper3D::GenerateDataForRenderer(mitk::BaseRenderer* renderer) { if( this->GetInput() == NULL ) { return; } bool propertiesHaveChanged = this->PropertiesChanged(); if( this->GetInput()->GetIsModified( ) || propertiesHaveChanged ) { m_NetworkAssembly->Delete(); m_NetworkAssembly = vtkPropAssembly::New(); // Here is the part where a graph is given and converted to points and connections between points... std::vector< mitk::ConnectomicsNetwork::NetworkNode > vectorOfNodes = this->GetInput()->GetVectorOfAllNodes(); std::vector< std::pair< std::pair< mitk::ConnectomicsNetwork::NetworkNode, mitk::ConnectomicsNetwork::NetworkNode > , mitk::ConnectomicsNetwork::NetworkEdge > > vectorOfEdges = this->GetInput()->GetVectorOfAllEdges(); // Decide on the style of rendering due to property if( m_ChosenRenderingScheme == connectomicsRenderingMITKScheme ) { mitk::Point3D tempWorldPoint, tempCNFGeometryPoint; //////////////////////Prepare coloring and radius//////////// std::vector< double > vectorOfNodeRadiusParameterValues; vectorOfNodeRadiusParameterValues.resize( vectorOfNodes.size() ); double maxNodeRadiusParameterValue( FillNodeParameterVector( &vectorOfNodeRadiusParameterValues, m_NodeRadiusParameter ) ); std::vector< double > vectorOfNodeColorParameterValues; vectorOfNodeColorParameterValues.resize( vectorOfNodes.size() ); double maxNodeColorParameterValue( FillNodeParameterVector( &vectorOfNodeColorParameterValues, m_NodeColorParameter ) ); std::vector< double > vectorOfEdgeRadiusParameterValues; vectorOfEdgeRadiusParameterValues.resize( vectorOfEdges.size() ); double maxEdgeRadiusParameterValue( FillEdgeParameterVector( &vectorOfEdgeRadiusParameterValues, m_EdgeRadiusParameter ) ); std::vector< double > vectorOfEdgeColorParameterValues; vectorOfEdgeColorParameterValues.resize( vectorOfEdges.size() ); double maxEdgeColorParameterValue( FillEdgeParameterVector( &vectorOfEdgeColorParameterValues, m_EdgeColorParameter ) ); //////////////////////Prepare Filtering////////////////////// // true will be rendered std::vector< bool > vectorOfNodeFilterBools( vectorOfNodes.size(), true ); if( m_ChosenNodeFilter == connectomicsRenderingNodeThresholdingFilter ) { FillNodeFilterBoolVector( &vectorOfNodeFilterBools, m_NodeThresholdParameter ); } std::vector< bool > vectorOfEdgeFilterBools( vectorOfEdges.size(), true ); if( m_ChosenEdgeFilter == connectomicsRenderingEdgeThresholdFilter ) { FillEdgeFilterBoolVector( &vectorOfEdgeFilterBools, m_EdgeThresholdParameter ); } //////////////////////Create Spheres///////////////////////// for(unsigned int i = 0; i < vectorOfNodes.size(); i++) { vtkSmartPointer sphereSource = vtkSmartPointer::New(); for(unsigned int dimension = 0; dimension < 3; dimension++) { tempCNFGeometryPoint.SetElement( dimension , vectorOfNodes[i].coordinates[dimension] ); } GetDataNode()->GetData()->GetGeometry()->IndexToWorld( tempCNFGeometryPoint, tempWorldPoint ); sphereSource->SetCenter( tempWorldPoint[0] , tempWorldPoint[1], tempWorldPoint[2] ); // determine radius double radiusFactor = vectorOfNodeRadiusParameterValues[i] / maxNodeRadiusParameterValue; double radius = m_NodeRadiusStart + ( m_NodeRadiusEnd - m_NodeRadiusStart) * radiusFactor; sphereSource->SetRadius( radius ); vtkSmartPointer mapper = vtkSmartPointer::New(); mapper->SetInputConnection(sphereSource->GetOutputPort()); vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); // determine color double colorFactor = vectorOfNodeColorParameterValues[i] / maxNodeColorParameterValue; double redStart = m_NodeColorStart.GetElement( 0 ); double greenStart = m_NodeColorStart.GetElement( 1 ); double blueStart = m_NodeColorStart.GetElement( 2 ); double redEnd = m_NodeColorEnd.GetElement( 0 ); double greenEnd = m_NodeColorEnd.GetElement( 1 ); double blueEnd = m_NodeColorEnd.GetElement( 2 ); double red = redStart + ( redEnd - redStart ) * colorFactor; double green = greenStart + ( greenEnd - greenStart ) * colorFactor; double blue = blueStart + ( blueEnd - blueStart ) * colorFactor; actor->GetProperty()->SetColor( red, green, blue); if( vectorOfNodeFilterBools[i] ) { m_NetworkAssembly->AddPart(actor); } } //////////////////////Create Tubes///////////////////////// - double maxWeight = (double) this->GetInput()->GetMaximumWeight(); - for(unsigned int i = 0; i < vectorOfEdges.size(); i++) { vtkSmartPointer lineSource = vtkSmartPointer::New(); for(unsigned int dimension = 0; dimension < 3; dimension++) { tempCNFGeometryPoint[ dimension ] = vectorOfEdges[i].first.first.coordinates[dimension]; } GetDataNode()->GetData()->GetGeometry()->IndexToWorld( tempCNFGeometryPoint, tempWorldPoint ); lineSource->SetPoint1(tempWorldPoint[0], tempWorldPoint[1],tempWorldPoint[2] ); for(unsigned int dimension = 0; dimension < 3; dimension++) { tempCNFGeometryPoint[ dimension ] = vectorOfEdges[i].first.second.coordinates[dimension]; } GetDataNode()->GetData()->GetGeometry()->IndexToWorld( tempCNFGeometryPoint, tempWorldPoint ); lineSource->SetPoint2(tempWorldPoint[0], tempWorldPoint[1], tempWorldPoint[2] ); vtkSmartPointer tubes = vtkSmartPointer::New(); tubes->SetInputConnection( lineSource->GetOutputPort() ); tubes->SetNumberOfSides( 12 ); // determine radius double radiusFactor = vectorOfEdgeRadiusParameterValues[i] / maxEdgeRadiusParameterValue; double radius = m_EdgeRadiusStart + ( m_EdgeRadiusEnd - m_EdgeRadiusStart) * radiusFactor; tubes->SetRadius( radius ); // originally we used a logarithmic scaling, // double radiusFactor = 1.0 + ((double) vectorOfEdges[i].second.weight) / 10.0 ; // tubes->SetRadius( std::log10( radiusFactor ) ); vtkSmartPointer mapper2 = vtkSmartPointer::New(); mapper2->SetInputConnection( tubes->GetOutputPort() ); vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper2); // determine color double colorFactor = vectorOfEdgeColorParameterValues[i] / maxEdgeColorParameterValue; double redStart = m_EdgeColorStart.GetElement( 0 ); double greenStart = m_EdgeColorStart.GetElement( 1 ); double blueStart = m_EdgeColorStart.GetElement( 2 ); double redEnd = m_EdgeColorEnd.GetElement( 0 ); double greenEnd = m_EdgeColorEnd.GetElement( 1 ); double blueEnd = m_EdgeColorEnd.GetElement( 2 ); double red = redStart + ( redEnd - redStart ) * colorFactor; double green = greenStart + ( greenEnd - greenStart ) * colorFactor; double blue = blueStart + ( blueEnd - blueStart ) * colorFactor; actor->GetProperty()->SetColor( red, green, blue); if( vectorOfEdgeFilterBools[i] ) { m_NetworkAssembly->AddPart(actor); } } } else if( m_ChosenRenderingScheme == connectomicsRenderingVTKScheme ) { vtkSmartPointer graph = vtkSmartPointer::New(); std::vector< vtkIdType > networkToVTKvector; networkToVTKvector.resize(vectorOfNodes.size()); for(unsigned int i = 0; i < vectorOfNodes.size(); i++) { networkToVTKvector[vectorOfNodes[i].id] = graph->AddVertex(); } for(unsigned int i = 0; i < vectorOfEdges.size(); i++) { graph->AddEdge(networkToVTKvector[vectorOfEdges[i].first.first.id], networkToVTKvector[vectorOfEdges[i].first.second.id]); } vtkSmartPointer points = vtkSmartPointer::New(); for(unsigned int i = 0; i < vectorOfNodes.size(); i++) { double x = vectorOfNodes[i].coordinates[0]; double y = vectorOfNodes[i].coordinates[1]; double z = vectorOfNodes[i].coordinates[2]; points->InsertNextPoint( x, y, z); } graph->SetPoints(points); vtkGraphLayout* layout = vtkGraphLayout::New(); layout->SetInputData(graph); vtkPassThroughLayoutStrategy* ptls = vtkPassThroughLayoutStrategy::New(); layout->SetLayoutStrategy( ptls ); vtkGraphToPolyData* graphToPoly = vtkGraphToPolyData::New(); graphToPoly->SetInputConnection(layout->GetOutputPort()); // Create the standard VTK polydata mapper and actor // for the connections (edges) in the tree. vtkPolyDataMapper* edgeMapper = vtkPolyDataMapper::New(); edgeMapper->SetInputConnection(graphToPoly->GetOutputPort()); vtkActor* edgeActor = vtkActor::New(); edgeActor->SetMapper(edgeMapper); edgeActor->GetProperty()->SetColor(0.0, 0.5, 1.0); // Glyph the points of the tree polydata to create // VTK_VERTEX cells at each vertex in the tree. vtkGlyph3D* vertGlyph = vtkGlyph3D::New(); vertGlyph->SetInputConnection(0, graphToPoly->GetOutputPort()); vtkGlyphSource2D* glyphSource = vtkGlyphSource2D::New(); glyphSource->SetGlyphTypeToVertex(); vertGlyph->SetInputConnection(1, glyphSource->GetOutputPort()); // Create a mapper for the vertices, and tell the mapper // to use the specified color array. vtkPolyDataMapper* vertMapper = vtkPolyDataMapper::New(); vertMapper->SetInputConnection(vertGlyph->GetOutputPort()); /*if (colorArray) { vertMapper->SetScalarModeToUsePointFieldData(); vertMapper->SelectColorArray(colorArray); vertMapper->SetScalarRange(colorRange); }*/ // Create an actor for the vertices. Move the actor forward // in the z direction so it is drawn on top of the edge actor. vtkActor* vertActor = vtkActor::New(); vertActor->SetMapper(vertMapper); vertActor->GetProperty()->SetPointSize(5); vertActor->SetPosition(0, 0, 0.001); m_NetworkAssembly->AddPart(edgeActor); m_NetworkAssembly->AddPart(vertActor); } (static_cast ( GetDataNode()->GetData() ) )->SetIsModified( false ); } } const mitk::ConnectomicsNetwork* mitk::ConnectomicsNetworkMapper3D::GetInput() { return static_cast ( GetDataNode()->GetData() ); } void mitk::ConnectomicsNetworkMapper3D::SetDefaultProperties(DataNode* node, BaseRenderer* renderer , bool overwrite) { // Initialize enumeration properties mitk::ConnectomicsRenderingSchemeProperty::Pointer connectomicsRenderingScheme = mitk::ConnectomicsRenderingSchemeProperty::New(); mitk::ConnectomicsRenderingEdgeFilteringProperty::Pointer connectomicsRenderingEdgeFiltering = mitk::ConnectomicsRenderingEdgeFilteringProperty::New(); mitk::ConnectomicsRenderingNodeFilteringProperty::Pointer connectomicsRenderingNodeFiltering = mitk::ConnectomicsRenderingNodeFilteringProperty::New(); mitk::ConnectomicsRenderingNodeColorParameterProperty::Pointer connectomicsRenderingNodeGradientColorParameter = mitk::ConnectomicsRenderingNodeColorParameterProperty::New(); mitk::ConnectomicsRenderingNodeRadiusParameterProperty::Pointer connectomicsRenderingNodeRadiusParameter = mitk::ConnectomicsRenderingNodeRadiusParameterProperty::New(); mitk::ConnectomicsRenderingEdgeColorParameterProperty::Pointer connectomicsRenderingEdgeGradientColorParameter = mitk::ConnectomicsRenderingEdgeColorParameterProperty::New(); mitk::ConnectomicsRenderingEdgeRadiusParameterProperty::Pointer connectomicsRenderingEdgeRadiusParameter = mitk::ConnectomicsRenderingEdgeRadiusParameterProperty::New(); mitk::ConnectomicsRenderingNodeThresholdParameterProperty::Pointer connectomicsRenderingNodeThresholdParameter = mitk::ConnectomicsRenderingNodeThresholdParameterProperty::New(); mitk::ConnectomicsRenderingEdgeThresholdParameterProperty::Pointer connectomicsRenderingEdgeThresholdParameter = mitk::ConnectomicsRenderingEdgeThresholdParameterProperty::New(); // set the properties node->AddProperty( connectomicsRenderingSchemePropertyName.c_str(), connectomicsRenderingScheme, renderer, overwrite ); node->AddProperty( connectomicsRenderingEdgeFilteringPropertyName.c_str(), connectomicsRenderingEdgeFiltering, renderer, overwrite ); node->AddProperty( connectomicsRenderingEdgeThresholdFilterParameterName.c_str(), connectomicsRenderingEdgeThresholdParameter, renderer, overwrite ); node->AddProperty( connectomicsRenderingEdgeThresholdFilterThresholdName.c_str(), connectomicsRenderingEdgeThresholdFilterThresholdDefault, renderer, overwrite ); node->AddProperty( connectomicsRenderingNodeFilteringPropertyName.c_str(), connectomicsRenderingNodeFiltering, renderer, overwrite ); node->AddProperty( connectomicsRenderingNodeThresholdFilterParameterName.c_str(), connectomicsRenderingNodeThresholdParameter, renderer, overwrite ); node->AddProperty( connectomicsRenderingNodeThresholdFilterThresholdName.c_str(), connectomicsRenderingNodeThresholdFilterThresholdDefault, renderer, overwrite ); node->AddProperty( connectomicsRenderingNodeGradientStartColorName.c_str(), connectomicsRenderingNodeGradientStartColorDefault, renderer, overwrite ); node->AddProperty( connectomicsRenderingNodeGradientEndColorName.c_str(), connectomicsRenderingNodeGradientEndColorDefault, renderer, overwrite ); node->AddProperty( connectomicsRenderingNodeGradientColorParameterName.c_str(), connectomicsRenderingNodeGradientColorParameter, renderer, overwrite ); node->AddProperty( connectomicsRenderingNodeRadiusStartName.c_str(), connectomicsRenderingNodeRadiusStartDefault, renderer, overwrite ); node->AddProperty( connectomicsRenderingNodeRadiusEndName.c_str(), connectomicsRenderingNodeRadiusEndDefault, renderer, overwrite ); node->AddProperty( connectomicsRenderingNodeRadiusParameterName.c_str(), connectomicsRenderingNodeRadiusParameter, renderer, overwrite ); node->AddProperty( connectomicsRenderingNodeChosenNodeName.c_str(), connectomicsRenderingNodeChosenNodeDefault, renderer, overwrite ); node->AddProperty( connectomicsRenderingEdgeGradientStartColorName.c_str(), connectomicsRenderingEdgeGradientStartColorDefault, renderer, overwrite ); node->AddProperty( connectomicsRenderingEdgeGradientEndColorName.c_str(), connectomicsRenderingEdgeGradientEndColorDefault, renderer, overwrite ); node->AddProperty( connectomicsRenderingEdgeGradientColorParameterName.c_str(), connectomicsRenderingEdgeGradientColorParameter, renderer, overwrite ); node->AddProperty( connectomicsRenderingEdgeRadiusStartName.c_str(), connectomicsRenderingEdgeRadiusStartDefault, renderer, overwrite ); node->AddProperty( connectomicsRenderingEdgeRadiusEndName.c_str(), connectomicsRenderingEdgeRadiusEndDefault, renderer, overwrite ); node->AddProperty( connectomicsRenderingEdgeRadiusParameterName.c_str(), connectomicsRenderingEdgeRadiusParameter, renderer, overwrite ); Superclass::SetDefaultProperties(node, renderer, overwrite); } -void mitk::ConnectomicsNetworkMapper3D::ApplyProperties(mitk::BaseRenderer* renderer) -{ - //TODO: implement - -} - void mitk::ConnectomicsNetworkMapper3D::SetVtkMapperImmediateModeRendering(vtkMapper *mapper) { //TODO: implement } void mitk::ConnectomicsNetworkMapper3D::UpdateVtkObjects() { //TODO: implement } vtkProp* mitk::ConnectomicsNetworkMapper3D::GetVtkProp(mitk::BaseRenderer *renderer) { return m_NetworkAssembly; } bool mitk::ConnectomicsNetworkMapper3D::PropertiesChanged() { mitk::ConnectomicsRenderingSchemeProperty * renderingScheme = static_cast< mitk::ConnectomicsRenderingSchemeProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingSchemePropertyName.c_str() ) ); mitk::ConnectomicsRenderingEdgeFilteringProperty * edgeFilter = static_cast< mitk::ConnectomicsRenderingEdgeFilteringProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingEdgeFilteringPropertyName.c_str() ) ); mitk::FloatProperty * edgeThreshold = static_cast< mitk::FloatProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingEdgeThresholdFilterThresholdName.c_str() ) ); mitk::ConnectomicsRenderingNodeFilteringProperty * nodeFilter = static_cast< mitk::ConnectomicsRenderingNodeFilteringProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingNodeFilteringPropertyName.c_str() ) ); mitk::ConnectomicsRenderingNodeThresholdParameterProperty * nodeThresholdParameter = static_cast< mitk::ConnectomicsRenderingNodeThresholdParameterProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingNodeThresholdFilterParameterName.c_str() ) ); mitk::ConnectomicsRenderingEdgeThresholdParameterProperty * edgeThresholdParameter = static_cast< mitk::ConnectomicsRenderingEdgeThresholdParameterProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingEdgeThresholdFilterParameterName.c_str() ) ); mitk::FloatProperty * nodeThreshold = static_cast< mitk::FloatProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingNodeThresholdFilterThresholdName.c_str() ) ); mitk::ColorProperty * nodeColorStart = static_cast< mitk::ColorProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingNodeGradientStartColorName.c_str() ) ); mitk::ColorProperty * nodeColorEnd = static_cast< mitk::ColorProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingNodeGradientEndColorName.c_str() ) ); mitk::FloatProperty * nodeRadiusStart = static_cast< mitk::FloatProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingNodeRadiusStartName.c_str() ) ); mitk::FloatProperty * nodeRadiusEnd = static_cast< mitk::FloatProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingNodeRadiusEndName.c_str() ) ); mitk::StringProperty * chosenNode = static_cast< mitk::StringProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingNodeChosenNodeName.c_str() ) ); mitk::ColorProperty * edgeColorStart = static_cast< mitk::ColorProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingEdgeGradientStartColorName.c_str() ) ); mitk::ColorProperty * edgeColorEnd = static_cast< mitk::ColorProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingEdgeGradientEndColorName.c_str() ) ); mitk::FloatProperty * edgeRadiusStart = static_cast< mitk::FloatProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingEdgeRadiusStartName.c_str() ) ); mitk::FloatProperty * edgeRadiusEnd = static_cast< mitk::FloatProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingEdgeRadiusEndName.c_str() ) ); mitk::ConnectomicsRenderingNodeColorParameterProperty * nodeColorParameter = static_cast< mitk::ConnectomicsRenderingNodeColorParameterProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingNodeGradientColorParameterName.c_str() ) ); mitk::ConnectomicsRenderingNodeRadiusParameterProperty * nodeRadiusParameter = static_cast< mitk::ConnectomicsRenderingNodeRadiusParameterProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingNodeRadiusParameterName.c_str() ) ); mitk::ConnectomicsRenderingEdgeColorParameterProperty * edgeColorParameter = static_cast< mitk::ConnectomicsRenderingEdgeColorParameterProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingEdgeGradientColorParameterName.c_str() ) ); mitk::ConnectomicsRenderingEdgeRadiusParameterProperty * edgeRadiusParameter = static_cast< mitk::ConnectomicsRenderingEdgeRadiusParameterProperty * > ( this->GetDataNode()->GetProperty( connectomicsRenderingEdgeRadiusParameterName.c_str() ) ); if( m_ChosenRenderingScheme != renderingScheme->GetValueAsString() || m_ChosenEdgeFilter != edgeFilter->GetValueAsString() || m_EdgeThreshold != edgeThreshold->GetValue() || m_EdgeThresholdParameter != edgeThresholdParameter->GetValueAsString() || m_ChosenNodeFilter != nodeFilter->GetValueAsString() || m_NodeThreshold != nodeThreshold->GetValue() || m_NodeThresholdParameter != nodeThresholdParameter->GetValueAsString() || m_NodeColorStart != nodeColorStart->GetValue() || m_NodeColorEnd != nodeColorEnd->GetValue() || m_NodeRadiusStart != nodeRadiusStart->GetValue() || m_NodeRadiusEnd != nodeRadiusEnd->GetValue() || m_ChosenNodeLabel != chosenNode->GetValueAsString() || m_EdgeColorStart != edgeColorStart->GetValue() || m_EdgeColorEnd != edgeColorEnd->GetValue() || m_EdgeRadiusStart != edgeRadiusStart->GetValue() || m_EdgeRadiusEnd != edgeRadiusEnd->GetValue() || m_NodeColorParameter != nodeColorParameter->GetValueAsString() || m_NodeRadiusParameter != nodeRadiusParameter->GetValueAsString() || m_EdgeColorParameter != edgeColorParameter->GetValueAsString() || m_EdgeRadiusParameter != edgeRadiusParameter->GetValueAsString() ) { m_ChosenRenderingScheme = renderingScheme->GetValueAsString(); m_ChosenEdgeFilter = edgeFilter->GetValueAsString(); m_EdgeThreshold = edgeThreshold->GetValue(); m_EdgeThresholdParameter = edgeThresholdParameter->GetValueAsString(); m_ChosenNodeFilter = nodeFilter->GetValueAsString(); m_NodeThreshold = nodeThreshold->GetValue(); m_NodeThresholdParameter = nodeThresholdParameter->GetValueAsString(); m_NodeColorStart = nodeColorStart->GetValue(); m_NodeColorEnd = nodeColorEnd->GetValue(); m_NodeRadiusStart = nodeRadiusStart->GetValue(); m_NodeRadiusEnd = nodeRadiusEnd->GetValue(); m_ChosenNodeLabel = chosenNode->GetValueAsString(); m_EdgeColorStart = edgeColorStart->GetValue(); m_EdgeColorEnd = edgeColorEnd->GetValue(); m_EdgeRadiusStart = edgeRadiusStart->GetValue(); m_EdgeRadiusEnd = edgeRadiusEnd->GetValue(); m_NodeColorParameter = nodeColorParameter->GetValueAsString(); m_NodeRadiusParameter = nodeRadiusParameter->GetValueAsString(); m_EdgeColorParameter = edgeColorParameter->GetValueAsString(); m_EdgeRadiusParameter = edgeRadiusParameter->GetValueAsString(); return true; } return false; } double mitk::ConnectomicsNetworkMapper3D::FillNodeParameterVector( std::vector< double > * parameterVector, std::string parameterName ) { int end( parameterVector->size() ); // constant parameter - uniform style if( parameterName == connectomicsRenderingNodeParameterConstant ) { for(int index(0); index < end; index++) { parameterVector->at( index ) = 1.0; } return 1.0; } double maximum( 0.0 ); // using the degree as parameter if( parameterName == connectomicsRenderingNodeParameterDegree ) { std::vector< int > vectorOfDegree = this->GetInput()->GetDegreeOfNodes(); for(int index(0); index < end; index++) { parameterVector->at( index ) = vectorOfDegree[ index ]; } maximum = *std::max_element( parameterVector->begin(), parameterVector->end() ); } // using betweenness centrality as parameter if( parameterName == connectomicsRenderingNodeParameterBetweenness ) { std::vector< double > vectorOfBetweenness = this->GetInput()->GetNodeBetweennessVector(); for(int index(0); index < end; index++) { parameterVector->at( index ) = vectorOfBetweenness[index]; } maximum = *std::max_element( parameterVector->begin(), parameterVector->end() ); } // using clustering coefficient as parameter if( parameterName == connectomicsRenderingNodeParameterClustering ) { const std::vector< double > vectorOfClustering = this->GetInput()->GetLocalClusteringCoefficients(); for(int index(0); index < end; index++) { parameterVector->at( index ) = vectorOfClustering[index]; } maximum = *std::max_element( parameterVector->begin(), parameterVector->end() ); } // using distance to a specific node as parameter if( parameterName == connectomicsRenderingNodeParameterColoringShortestPath ) { bool labelFound( this->GetInput()->CheckForLabel( m_ChosenNodeLabel ) ); // check whether the chosen node is valid if( !labelFound ) { MITK_WARN << "Node chosen for rendering is not valid."; for(int index(0); index < end; index++) { parameterVector->at( index ) = 1.0; } return 1.0; } else { const std::vector< double > distanceVector = this->GetInput()->GetShortestDistanceVectorFromLabel( m_ChosenNodeLabel ); for(int index(0); index < end; index++) { parameterVector->at( index ) = distanceVector[index]; } maximum = *std::max_element( parameterVector->begin(), parameterVector->end() ); } } // if the maximum is nearly zero if( std::abs( maximum ) < mitk::eps ) { maximum = 1.0; } return maximum; } double mitk::ConnectomicsNetworkMapper3D::FillEdgeParameterVector( std::vector< double > * parameterVector, std::string parameterName ) { int end( parameterVector->size() ); // constant parameter - uniform style if( parameterName == connectomicsRenderingEdgeParameterConstant ) { for(int index(0); index < end; index++) { parameterVector->at( index ) = 1.0; } return 1.0; } double maximum( 0.0 ); // using the weight as parameter if( parameterName == connectomicsRenderingEdgeParameterWeight ) { std::vector< std::pair< std::pair< mitk::ConnectomicsNetwork::NetworkNode, mitk::ConnectomicsNetwork::NetworkNode > , mitk::ConnectomicsNetwork::NetworkEdge > > vectorOfEdges = this->GetInput()->GetVectorOfAllEdges(); for(int index(0); index < end; index++) { parameterVector->at( index ) = vectorOfEdges[ index ].second.weight; } maximum = *std::max_element( parameterVector->begin(), parameterVector->end() ); } // using the edge centrality as parameter if( parameterName == connectomicsRenderingEdgeParameterCentrality ) { const std::vector< double > vectorOfCentrality = this->GetInput()->GetEdgeBetweennessVector(); for(int index(0); index < end; index++) { parameterVector->at( index ) = vectorOfCentrality[index]; } maximum = *std::max_element( parameterVector->begin(), parameterVector->end() ); } // if the maximum is nearly zero if( std::abs( maximum ) < mitk::eps ) { maximum = 1.0; } return maximum; } void mitk::ConnectomicsNetworkMapper3D::FillNodeFilterBoolVector( std::vector< bool > * boolVector, std::string parameterName ) { std::vector< double > parameterVector; parameterVector.resize( boolVector->size() ); int end( parameterVector.size() ); // using the degree as parameter if( parameterName == connectomicsRenderingNodeParameterDegree ) { std::vector< int > vectorOfDegree = this->GetInput()->GetDegreeOfNodes(); for(int index(0); index < end; index++) { parameterVector.at( index ) = vectorOfDegree[ index ]; } } // using betweenness centrality as parameter if( parameterName == connectomicsRenderingNodeParameterBetweenness ) { std::vector< double > vectorOfBetweenness = this->GetInput()->GetNodeBetweennessVector(); for(int index(0); index < end; index++) { parameterVector.at( index ) = vectorOfBetweenness[index]; } } // using clustering coefficient as parameter if( parameterName == connectomicsRenderingNodeParameterClustering ) { const std::vector< double > vectorOfClustering = this->GetInput()->GetLocalClusteringCoefficients(); for(int index(0); index < end; index++) { parameterVector.at( index ) = vectorOfClustering[index]; } } for( int index( 0 ), end( boolVector->size() ); index < end; index++ ) { if( parameterVector.at( index ) >= m_NodeThreshold ) { boolVector->at( index ) = true; } else { boolVector->at( index ) = false; } } return; } void mitk::ConnectomicsNetworkMapper3D::FillEdgeFilterBoolVector( std::vector< bool > * boolVector, std::string parameterName ) { std::vector< double > parameterVector; parameterVector.resize( boolVector->size() ); int end( parameterVector.size() ); // using the weight as parameter if( parameterName == connectomicsRenderingEdgeParameterWeight ) { std::vector< std::pair< std::pair< mitk::ConnectomicsNetwork::NetworkNode, mitk::ConnectomicsNetwork::NetworkNode > , mitk::ConnectomicsNetwork::NetworkEdge > > vectorOfEdges = this->GetInput()->GetVectorOfAllEdges(); for(int index(0); index < end; index++) { parameterVector.at( index ) = vectorOfEdges[ index ].second.weight; } } // using the edge centrality as parameter if( parameterName == connectomicsRenderingEdgeParameterCentrality ) { const std::vector< double > vectorOfCentrality = this->GetInput()->GetEdgeBetweennessVector(); for(int index(0); index < end; index++) { parameterVector.at( index ) = vectorOfCentrality[index]; } } for( int index( 0 ), end( boolVector->size() ); index < end; index++ ) { if( parameterVector.at( index ) >= m_EdgeThreshold ) { boolVector->at( index ) = true; } else { boolVector->at( index ) = false; } } return; } diff --git a/Modules/DiffusionImaging/Connectomics/Rendering/mitkConnectomicsNetworkMapper3D.h b/Modules/DiffusionImaging/Connectomics/Rendering/mitkConnectomicsNetworkMapper3D.h index 391c32906d..10ae4a856a 100644 --- a/Modules/DiffusionImaging/Connectomics/Rendering/mitkConnectomicsNetworkMapper3D.h +++ b/Modules/DiffusionImaging/Connectomics/Rendering/mitkConnectomicsNetworkMapper3D.h @@ -1,135 +1,134 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef ConnectomicsNetworkMapper3D_H_HEADER_INCLUDED #define ConnectomicsNetworkMapper3D_H_HEADER_INCLUDED // VTK includes #include #include "vtkPropAssembly.h" // MITK includes // base class #include "mitkVtkMapper.h" // data type #include "mitkConnectomicsNetwork.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ConnectomicsExports.h" namespace mitk { /** * \brief Mapper for Networks * \ingroup Mapper */ class Connectomics_EXPORT ConnectomicsNetworkMapper3D : public VtkMapper { public: mitkClassMacro(ConnectomicsNetworkMapper3D, VtkMapper); itkNewMacro(Self); virtual vtkProp *GetVtkProp(mitk::BaseRenderer *renderer); //looks like deprecated.. should be replaced bz GetViewProp() static void SetDefaultProperties(DataNode* node, BaseRenderer* renderer = NULL, bool overwrite = false ); - virtual void ApplyProperties(mitk::BaseRenderer* renderer); static void SetVtkMapperImmediateModeRendering(vtkMapper *mapper); virtual void GenerateDataForRenderer(mitk::BaseRenderer* renderer); virtual const mitk::ConnectomicsNetwork* GetInput(); protected: ConnectomicsNetworkMapper3D(); virtual ~ConnectomicsNetworkMapper3D(); void UpdateVtkObjects(); vtkPropAssembly *m_NetworkAssembly; /** * \brief Returns true if the properties have changed since the last data generation */ bool PropertiesChanged(); // Create vectors for customizing color and radius and return maximum double FillNodeParameterVector( std::vector< double > * parameterVector, std::string parameterName ); double FillEdgeParameterVector( std::vector< double > * parameterVector, std::string parameterName ); void FillNodeFilterBoolVector( std::vector< bool > * boolVector, std::string parameterName ); void FillEdgeFilterBoolVector( std::vector< bool > * boolVector, std::string parameterName ); // Property storing members std::string m_ChosenRenderingScheme; std::string m_ChosenEdgeFilter; std::string m_EdgeThresholdParameter; double m_EdgeThreshold; std::string m_ChosenNodeFilter; std::string m_NodeThresholdParameter; double m_NodeThreshold; mitk::Color m_NodeColorStart; mitk::Color m_NodeColorEnd; double m_NodeRadiusStart; double m_NodeRadiusEnd; std::string m_ChosenNodeLabel; mitk::Color m_EdgeColorStart; mitk::Color m_EdgeColorEnd; double m_EdgeRadiusStart; double m_EdgeRadiusEnd; std::string m_NodeRadiusParameter; std::string m_NodeColorParameter; std::string m_EdgeRadiusParameter; std::string m_EdgeColorParameter; }; } // namespace mitk #endif /* ConnectomicsNetworkMapper3D_H_HEADER_INCLUDED */ diff --git a/Modules/DiffusionImaging/Connectomics/Testing/mitkConnectomicsNetworkTest.cpp b/Modules/DiffusionImaging/Connectomics/Testing/mitkConnectomicsNetworkTest.cpp index 7aaa3eb247..598e284214 100644 --- a/Modules/DiffusionImaging/Connectomics/Testing/mitkConnectomicsNetworkTest.cpp +++ b/Modules/DiffusionImaging/Connectomics/Testing/mitkConnectomicsNetworkTest.cpp @@ -1,526 +1,526 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTestingMacros.h" #include #include "mitkConnectomicsNetwork.h" #include "mitkConnectomicsSyntheticNetworkGenerator.h" #include "mitkConnectomicsSimulatedAnnealingManager.h" #include "mitkConnectomicsSimulatedAnnealingPermutationModularity.h" #include "mitkConnectomicsSimulatedAnnealingCostFunctionModularity.h" #include #include #include /**Documentation * Test for synthetic connectomics generation and connectomics network functionality */ int mitkConnectomicsNetworkTest(int argc, char* argv[]) { // Test begins MITK_TEST_BEGIN("mitkConnectomicsNetworkTest"); // Typedefs typedef mitk::ConnectomicsNetwork::VertexDescriptorType VertexType; typedef mitk::ConnectomicsNetwork::EdgeDescriptorType EdgeType; typedef mitk::ConnectomicsNetwork::NetworkNode NodeType; // The test network std::vector< NodeType > inNodes; NodeType node; node.id = 0; node.label = "1-1"; node.coordinates.clear(); node.coordinates.push_back( 0 ); node.coordinates.push_back( 0 ); node.coordinates.push_back( 0 ); inNodes.push_back(node); node.id = 1; node.label = "2-1"; node.coordinates.clear(); node.coordinates.push_back( 10 ); node.coordinates.push_back( 0 ); node.coordinates.push_back( 0 ); inNodes.push_back(node); node.id = 2; node.label = "3-1"; node.coordinates.clear(); node.coordinates.push_back( 20 ); node.coordinates.push_back( 10 ); node.coordinates.push_back( 0 ); inNodes.push_back(node); node.id = 3; node.label = "4-1"; node.coordinates.clear(); node.coordinates.push_back( 30 ); node.coordinates.push_back( 20 ); node.coordinates.push_back( 0 ); inNodes.push_back(node); node.id = 4; node.label = "5-1"; node.coordinates.clear(); node.coordinates.push_back( 40 ); node.coordinates.push_back( 50 ); node.coordinates.push_back( 0 ); inNodes.push_back(node); node.id = 5; node.label = "6-2"; node.coordinates.clear(); node.coordinates.push_back( 0 ); node.coordinates.push_back( 0 ); node.coordinates.push_back( 10 ); inNodes.push_back(node); node.id = 6; node.label = "7-2"; node.coordinates.clear(); node.coordinates.push_back( 0 ); node.coordinates.push_back( 10 ); node.coordinates.push_back( 20 ); inNodes.push_back(node); node.id = 7; node.label = "8-2"; node.coordinates.clear(); node.coordinates.push_back( 0 ); node.coordinates.push_back( 20 ); node.coordinates.push_back( 30 ); inNodes.push_back(node); node.id = 8; node.label = "9-2"; node.coordinates.clear(); node.coordinates.push_back( 0 ); node.coordinates.push_back( 30 ); node.coordinates.push_back( 40 ); inNodes.push_back(node); node.id = 9; node.label = "10-3"; node.coordinates.clear(); node.coordinates.push_back( 20 ); node.coordinates.push_back( 0 ); node.coordinates.push_back( 10 ); inNodes.push_back(node); node.id = 10; node.label = "11-3"; node.coordinates.clear(); node.coordinates.push_back( 30 ); node.coordinates.push_back( 0 ); node.coordinates.push_back( 20 ); inNodes.push_back(node); node.id = 11; node.label = "12-3"; node.coordinates.clear(); node.coordinates.push_back( 40 ); node.coordinates.push_back( 0 ); node.coordinates.push_back( 30 ); inNodes.push_back(node); std::vector< mitk::ConnectomicsNetwork::NetworkEdge > inEdges; mitk::ConnectomicsNetwork::NetworkEdge edge; edge.sourceId = 0; edge.targetId = 1; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 0; edge.targetId = 2; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 0; edge.targetId = 4; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 1; edge.targetId = 4; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 1; edge.targetId = 3; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 2; edge.targetId = 3; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 3; edge.targetId = 4; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 4; edge.targetId = 5; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 5; edge.targetId = 6; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 5; edge.targetId = 7; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 5; edge.targetId = 8; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 7; edge.targetId = 8; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 6; edge.targetId = 8; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 6; edge.targetId = 9; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 3; edge.targetId = 10; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 9; edge.targetId = 10; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 10; edge.targetId = 11; edge.weight = 2; inEdges.push_back( edge ); edge.sourceId = 9; edge.targetId = 11; edge.weight = 2; inEdges.push_back( edge ); // further variables double eps(0.001); try { // Testing synthetic network generation mitk::ConnectomicsSyntheticNetworkGenerator::Pointer generator = mitk::ConnectomicsSyntheticNetworkGenerator::New(); MITK_TEST_CONDITION_REQUIRED(generator.IsNotNull(),"Synthetic network generator has been instantiated") // first and second parameter std::vector< std::pair > parameterVector; // name and isRandom std::vector< std::pair > messageVector; // order of results is # vertices, # edges, # self loops, average degree, connection density // global clustering coefficient std::vector< std::vector< double > > resultVector; int numberOfOptions = 3; parameterVector.resize(numberOfOptions); messageVector.resize(numberOfOptions); resultVector.resize(numberOfOptions); // Create regular lattice network in the form of a cube with sidelength 5 and distance 10 between nodes parameterVector[0] = std::pair< int, double>(5, 10); messageVector[0] = std::pair("Regular Lattice Network", false); resultVector[0].push_back( 5 * 5 * 5 ); resultVector[0].push_back( 300 ); resultVector[0].push_back( 0 ); resultVector[0].push_back( 4.8 ); resultVector[0].push_back(0.0387); resultVector[0].push_back(0); // Create a heterogeneous sphere network with 1 central node and 49 nodes on the surface and radius 10 parameterVector[1] = std::pair< int, double>(50, 10); messageVector[1] = std::pair("Heterogeneous Sphere Network", false); resultVector[1].push_back( 50 ); resultVector[1].push_back( 49 ); resultVector[1].push_back( 0 ); resultVector[1].push_back( 1.96 ); resultVector[1].push_back(0.0400); resultVector[1].push_back(0); // Create random network with 50 nodes and edges between them generated with a 0.1 likelihood parameterVector[2] = std::pair< int, double>(50, 0.1); messageVector[2] = std::pair("Random Network", true); resultVector[2].push_back( 50 ); for(int loop(0); loop < numberOfOptions; loop++) { mitk::ConnectomicsNetwork::Pointer network = generator->CreateSyntheticNetwork(loop, parameterVector[loop].first, parameterVector[loop].second); bool generationWorked = generator->WasGenerationSuccessfull() && network.IsNotNull(); std::string message = messageVector[loop].first + " has been instantiated"; MITK_TEST_CONDITION_REQUIRED(generationWorked,message) bool verticesCloseEnough( std::abs(resultVector[loop][0] - network->GetNumberOfVertices()) < eps); MITK_TEST_CONDITION_REQUIRED( verticesCloseEnough, "Expected number of vertices") if(!messageVector[loop].second) { bool edgesCloseEnough( std::abs(resultVector[loop][1] - network->GetNumberOfEdges()) < eps); MITK_TEST_CONDITION_REQUIRED( edgesCloseEnough, "Expected number of edges") bool selfLoopsCloseEnough( std::abs(resultVector[loop][2] - network->GetNumberOfSelfLoops()) < eps); MITK_TEST_CONDITION_REQUIRED( selfLoopsCloseEnough, "Expected number of self loops") bool avDegCloseEnough( std::abs(resultVector[loop][3] - network->GetAverageDegree()) < eps); MITK_TEST_CONDITION_REQUIRED( avDegCloseEnough, "Expected average degree") bool conDensCloseEnough( std::abs(resultVector[loop][4] - network->GetConnectionDensity()) < eps); MITK_TEST_CONDITION_REQUIRED( conDensCloseEnough, "Expected connection density") bool clustCoeffCloseEnough( std::abs(resultVector[loop][5] - network->GetGlobalClusteringCoefficient()) < eps); MITK_TEST_CONDITION_REQUIRED( clustCoeffCloseEnough, "Expected global clustering coefficient") } } } catch (...) { MITK_ERROR << "Unhandled exception caught while testing synthetic network generation [FAILED]" ; return EXIT_FAILURE; } try { // Testing network interface // Create network mitk::ConnectomicsNetwork::Pointer network = mitk::ConnectomicsNetwork::New(); std::vector< VertexType > vertexVector; vertexVector.resize( inNodes.size() ); - for(int loop(0); loop < inNodes.size(); loop++) + for(unsigned int loop(0); loop < inNodes.size(); loop++) { VertexType newVertex = network->AddVertex( inNodes[loop].id ); vertexVector[ inNodes[loop].id ] = newVertex; network->SetLabel( newVertex, inNodes[loop].label ); network->SetCoordinates( newVertex, inNodes[loop].coordinates ); } - for(int loop(0); loop < inEdges.size(); loop++) + for(unsigned int loop(0); loop < inEdges.size(); loop++) { int sourceId = inEdges[loop].sourceId; int targetId = inEdges[loop].targetId; VertexType sourceVertex = vertexVector[ sourceId ]; VertexType targetVertex = vertexVector[ targetId ]; // there are two methods to add nodes if( loop % 2 == 0 ) { network->AddEdge(sourceVertex, targetVertex); for( int remaining( inEdges[loop].weight ); remaining > 1; remaining-- ) { network->IncreaseEdgeWeight( sourceVertex, targetVertex ); } } else { network->AddEdge(sourceVertex, targetVertex, sourceId, targetId, inEdges[loop].weight ); } } // Test whether network parameters are as expected - MITK_TEST_CONDITION_REQUIRED( inNodes.size() == network->GetNumberOfVertices(), "Expected number of vertices") + MITK_TEST_CONDITION_REQUIRED( inNodes.size() == (unsigned int)network->GetNumberOfVertices(), "Expected number of vertices") - MITK_TEST_CONDITION_REQUIRED( inEdges.size() == network->GetNumberOfEdges(), "Expected number of edges") + MITK_TEST_CONDITION_REQUIRED( inEdges.size() == (unsigned int)network->GetNumberOfEdges(), "Expected number of edges") MITK_TEST_CONDITION_REQUIRED( 0 == network->GetNumberOfSelfLoops(), "Expected number of self loops") bool avDegCloseEnough( std::abs(3 - network->GetAverageDegree()) < eps); MITK_TEST_CONDITION_REQUIRED( avDegCloseEnough, "Expected average degree") bool conDensCloseEnough( std::abs(0.2727 - network->GetConnectionDensity()) < eps); MITK_TEST_CONDITION_REQUIRED( conDensCloseEnough, "Expected connection density") bool clustCoeffCloseEnough( std::abs(0.4583 - network->GetGlobalClusteringCoefficient()) < eps); MITK_TEST_CONDITION_REQUIRED( clustCoeffCloseEnough, "Expected global clustering coefficient") MITK_TEST_CONDITION_REQUIRED( network->GetMaximumWeight() == 2, "Expected maximum weight") MITK_TEST_CONDITION_REQUIRED( network->GetVectorOfAllVertexDescriptors().size() == vertexVector.size(), "Expected number of vertex descriptors") } catch (...) { MITK_ERROR << "Unhandled exception caught while testing network interface [FAILED]" ; return EXIT_FAILURE; } try { // Testing modularity calculation typedef std::map< VertexType, int > ToModuleMapType; // Create network mitk::ConnectomicsNetwork::Pointer network = mitk::ConnectomicsNetwork::New(); std::vector< VertexType > vertexVector; vertexVector.resize( inNodes.size() ); - for(int loop(0); loop < inNodes.size(); loop++) + for(unsigned int loop(0); loop < inNodes.size(); loop++) { VertexType newVertex = network->AddVertex( inNodes[loop].id ); vertexVector[ inNodes[loop].id ] = newVertex; network->SetLabel( newVertex, inNodes[loop].label ); network->SetCoordinates( newVertex, inNodes[loop].coordinates ); } - for(int loop(0); loop < inEdges.size(); loop++) + for(unsigned int loop(0); loop < inEdges.size(); loop++) { int sourceId = inEdges[loop].sourceId; int targetId = inEdges[loop].targetId; VertexType sourceVertex = vertexVector[ sourceId ]; VertexType targetVertex = vertexVector[ targetId ]; // there are two methods to add nodes if( loop % 2 == 0 ) { network->AddEdge(sourceVertex, targetVertex); for( int remaining( inEdges[loop].weight ); remaining > 1; remaining-- ) { network->IncreaseEdgeWeight( sourceVertex, targetVertex ); } } else { network->AddEdge(sourceVertex, targetVertex, sourceId, targetId, inEdges[loop].weight ); } } // Simulated annealing classes mitk::ConnectomicsSimulatedAnnealingManager::Pointer manager = mitk::ConnectomicsSimulatedAnnealingManager::New(); mitk::ConnectomicsSimulatedAnnealingPermutationModularity::Pointer permutation = mitk::ConnectomicsSimulatedAnnealingPermutationModularity::New(); mitk::ConnectomicsSimulatedAnnealingCostFunctionModularity::Pointer costFunction = mitk::ConnectomicsSimulatedAnnealingCostFunctionModularity::New(); // Test whether modularity calculation behaves as expected ToModuleMapType threeModuleSolution; std::vector< VertexType > vertexInVector = network->GetVectorOfAllVertexDescriptors(); threeModuleSolution.insert( std::pair( vertexInVector[ 0 ], 0 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 1 ], 0 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 2 ], 0 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 3 ], 0 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 4 ], 0 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 5 ], 1 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 6 ], 1 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 7 ], 1 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 8 ], 1 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 9 ], 2 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 10 ], 2 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 11 ], 2 ) ); bool threeModuleModularity( std::abs(0.4753 - costFunction->CalculateModularity( network, &threeModuleSolution )) < eps); MITK_TEST_CONDITION_REQUIRED( threeModuleModularity, "Expected three module modularity") bool correctNumberOfModules( permutation->getNumberOfModules( &threeModuleSolution ) == 3 ); MITK_TEST_CONDITION_REQUIRED( correctNumberOfModules, "Expected number of modules") bool correctNumberOfVertices( permutation->getNumberOfVerticesInModule( &threeModuleSolution, 0 ) == 5 && permutation->getNumberOfVerticesInModule( &threeModuleSolution, 1 ) == 4 && permutation->getNumberOfVerticesInModule( &threeModuleSolution, 2 ) == 3 ); MITK_TEST_CONDITION_REQUIRED( correctNumberOfVertices, "Expected number of vertices per module") ToModuleMapType oneModuleSolution; oneModuleSolution.insert( std::pair( vertexInVector[ 0 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 1 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 2 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 3 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 4 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 5 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 6 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 7 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 8 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 9 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 10 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 11 ], 0 ) ); bool oneModuleModularity( std::abs(0.0 - costFunction->CalculateModularity( network, &oneModuleSolution )) < eps); MITK_TEST_CONDITION_REQUIRED( oneModuleModularity, "Expected one module modularity") ToModuleMapType badTwoModuleSolution; badTwoModuleSolution.insert( std::pair( vertexInVector[ 0 ], 0 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 1 ], 0 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 2 ], 0 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 3 ], 0 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 4 ], 0 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 5 ], 1 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 6 ], 1 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 7 ], 1 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 8 ], 0 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 9 ], 1 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 10 ], 1 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 11 ], 0 ) ); bool badTwoModuleModularity( std::abs(0.097222 - costFunction->CalculateModularity( network, &badTwoModuleSolution )) < eps); MITK_TEST_CONDITION_REQUIRED( badTwoModuleModularity, "Expected bad two module modularity") ToModuleMapType noInternalLinksThreeModuleSolution; noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 0 ], 0 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 1 ], 2 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 2 ], 1 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 3 ], 0 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 4 ], 1 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 5 ], 2 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 6 ], 0 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 7 ], 0 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 8 ], 1 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 9 ], 2 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 10 ], 1 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 11 ], 0 ) ); bool noInternalThreeModuleModularity( std::abs(-0.3395 - costFunction->CalculateModularity( network, &noInternalLinksThreeModuleSolution )) < eps); MITK_TEST_CONDITION_REQUIRED( noInternalThreeModuleModularity, "Expected three module modularity containing no internal links") } catch (...) { MITK_ERROR << "Unhandled exception caught while testing modularity calculation [FAILED]" ; return EXIT_FAILURE; } // Test ends MITK_TEST_END(); } diff --git a/Modules/DiffusionImaging/Connectomics/Testing/mitkConnectomicsStatisticsCalculatorTest.cpp b/Modules/DiffusionImaging/Connectomics/Testing/mitkConnectomicsStatisticsCalculatorTest.cpp index a33b970652..64edddd2fb 100644 --- a/Modules/DiffusionImaging/Connectomics/Testing/mitkConnectomicsStatisticsCalculatorTest.cpp +++ b/Modules/DiffusionImaging/Connectomics/Testing/mitkConnectomicsStatisticsCalculatorTest.cpp @@ -1,248 +1,248 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // macros #include "mitkTestingMacros.h" // std includes #include #include // MITK includes #include #include #include -static void CalculateStatistics(std::string networkName, std::string outName, std::vector< std::vector< std::string > > vectorOfLabelVectors ) +static void CalculateStatistics(std::string networkName, std::string outName, std::vector< std::vector< std::string > > /*vectorOfLabelVectors*/ ) { const std::string s1="", s2=""; RegisterConnectomicsObjectFactory(); // load network std::vector networkFile = mitk::BaseDataIO::LoadBaseDataFromFile( networkName, s1, s2, false ); if( networkFile.empty() ) { std::string errorMessage = "File at " + networkName + " could not be read. Aborting."; MITK_TEST_CONDITION_REQUIRED( !networkFile.empty(), errorMessage); return; } mitk::BaseData* networkBaseData = networkFile.at(0); mitk::ConnectomicsNetwork* network = dynamic_cast( networkBaseData ); if( !network ) { std::string errorMessage = "Read file at " + networkName + " could not be recognized as network. Aborting."; MITK_TEST_CONDITION_REQUIRED( network, errorMessage); return; } mitk::ConnectomicsStatisticsCalculator::Pointer statisticsCalculator = mitk::ConnectomicsStatisticsCalculator::New(); statisticsCalculator->SetNetwork( network ); statisticsCalculator->Update(); std::stringstream headerStream; if( outName == "") { // test mode double eps( 0.0001 ); MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetNumberOfVertices(), 4 , eps, true ), "GetNumberOfVertices" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetNumberOfEdges(), 5 , eps, true ), "GetNumberOfEdges" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetAverageDegree(), 2.5 , eps, true ), "GetAverageDegree" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetConnectionDensity(), 0.833333 , eps, true ), "GetConnectionDensity" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetNumberOfConnectedComponents(), 1 , eps, true ), "GetNumberOfConnectedComponents" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetAverageComponentSize(), 4 , eps, true ), "GetAverageComponentSize" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetLargestComponentSize(), 4 , eps, true ), "GetLargestComponentSize" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetRatioOfNodesInLargestComponent(), 1 , eps, true ), "GetRatioOfNodesInLargestComponent" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetHopPlotExponent(), 0.192645 , eps, true ), "GetHopPlotExponent" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetEffectiveHopDiameter(), 1 , eps, true ), "GetEffectiveHopDiameter" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetAverageClusteringCoefficientsC(), 0.833333 , eps, true ), "GetAverageClusteringCoefficientsC" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetAverageClusteringCoefficientsD(), 0.916667 , eps, true ), "GetAverageClusteringCoefficientsD" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetAverageClusteringCoefficientsE(), 0.833333 , eps, true ), "GetAverageClusteringCoefficientsE" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetAverageVertexBetweennessCentrality(), 0.25 , eps, true ), "GetAverageVertexBetweennessCentrality" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetAverageEdgeBetweennessCentrality(), 1.4 , eps, true ), "GetAverageEdgeBetweennessCentrality" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetNumberOfIsolatedPoints(), 0 , eps, true ), "GetNumberOfIsolatedPoints" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetRatioOfIsolatedPoints(), 0 , eps, true ), "GetRatioOfIsolatedPoints" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetNumberOfEndPoints(), 0 , eps, true ), "GetNumberOfEndPoints" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetRatioOfEndPoints(), 0 , eps, true ), "GetRatioOfEndPoints" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetDiameter(), 2 , eps, true ), "GetDiameter" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetDiameter90(), 2 , eps, true ), "GetDiameter90" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetRadius(), 1 , eps, true ), "GetRadius" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetRadius90(), 1 , eps, true ), "GetRadius90" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetAverageEccentricity(), 1.5 , eps, true ), "GetAverageEccentricity" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetAverageEccentricity90(), 1.5 , eps, true ), "GetAverageEccentricity90" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetAveragePathLength(), 1.16667 , eps, true ), "GetAveragePathLength" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetNumberOfCentralPoints(), 2 , eps, true ), "GetNumberOfCentralPoints" ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetRatioOfCentralPoints(), 0.5 , eps, true ), "GetRatioOfCentralPoints" ) // MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetSpectralRadius(), , eps, true ), " " ) // MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetSecondLargestEigenValue(), , eps, true ), " " ) // MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetAdjacencyTrace(), , eps, true ), " " ) // MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetAdjacencyEnergy(), , eps, true ), " " ) // MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetLaplacianTrace(), , eps, true ), " " ) // MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetLaplacianEnergy(), , eps, true ), " " ) // MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetLaplacianSpectralGap(), , eps, true ), " " ) // MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetNormalizedLaplacianTrace(), , eps, true ), " " ) // MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetNormalizedLaplacianEnergy(), , eps, true ), " " ) // MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetNormalizedLaplacianNumberOf2s(), , eps, true ), " " ) // MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetNormalizedLaplacianNumberOf1s(), , eps, true ), " " ) // MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetNormalizedLaplacianNumberOf0s(), , eps, true ), " " ) // MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetNormalizedLaplacianLowerSlope(), , eps, true ), " " ) // MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetNormalizedLaplacianUpperSlope(), , eps, true ), " " ) MITK_TEST_CONDITION_REQUIRED( mitk::Equal( statisticsCalculator->GetSmallWorldness(), 1.72908 , eps, true ), "GetSmallWorldness" ) } else { // batch mode headerStream << "NumberOfVertices " << "NumberOfEdges " << "AverageDegree " << "ConnectionDensity " << "NumberOfConnectedComponents " << "AverageComponentSize " << "LargestComponentSize " << "RatioOfNodesInLargestComponent " << "HopPlotExponent " << "EffectiveHopDiameter " << "AverageClusteringCoefficientsC " << "AverageClusteringCoefficientsD " << "AverageClusteringCoefficientsE " << "AverageVertexBetweennessCentrality " << "AverageEdgeBetweennessCentrality " << "NumberOfIsolatedPoints " << "RatioOfIsolatedPoints " << "NumberOfEndPoints " << "RatioOfEndPoints " << "Diameter " << "Diameter90 " << "Radius " << "Radius90 " << "AverageEccentricity " << "AverageEccentricity90 " << "AveragePathLength " << "NumberOfCentralPoints " << "RatioOfCentralPoints " << "SpectralRadius " << "SecondLargestEigenValue " << "AdjacencyTrace " << "AdjacencyEnergy " << "LaplacianTrace " << "LaplacianEnergy " << "LaplacianSpectralGap " << "NormalizedLaplacianTrace " << "NormalizedLaplacianEnergy " << "NormalizedLaplacianNumberOf2s " << "NormalizedLaplacianNumberOf1s " << "NormalizedLaplacianNumberOf0s " << "NormalizedLaplacianLowerSlope " << "NormalizedLaplacianUpperSlope" << "SmallWorldness" << std::endl; std::stringstream dataStream; dataStream << statisticsCalculator->GetNumberOfVertices() << " " << statisticsCalculator->GetNumberOfEdges() << " " << statisticsCalculator->GetAverageDegree() << " " << statisticsCalculator->GetConnectionDensity() << " " << statisticsCalculator->GetNumberOfConnectedComponents() << " " << statisticsCalculator->GetAverageComponentSize() << " " << statisticsCalculator->GetLargestComponentSize() << " " << statisticsCalculator->GetRatioOfNodesInLargestComponent() << " " << statisticsCalculator->GetHopPlotExponent() << " " << statisticsCalculator->GetEffectiveHopDiameter() << " " << statisticsCalculator->GetAverageClusteringCoefficientsC() << " " << statisticsCalculator->GetAverageClusteringCoefficientsD() << " " << statisticsCalculator->GetAverageClusteringCoefficientsE() << " " << statisticsCalculator->GetAverageVertexBetweennessCentrality() << " " << statisticsCalculator->GetAverageEdgeBetweennessCentrality() << " " << statisticsCalculator->GetNumberOfIsolatedPoints() << " " << statisticsCalculator->GetRatioOfIsolatedPoints() << " " << statisticsCalculator->GetNumberOfEndPoints() << " " << statisticsCalculator->GetRatioOfEndPoints() << " " << statisticsCalculator->GetDiameter() << " " << statisticsCalculator->GetDiameter90() << " " << statisticsCalculator->GetRadius() << " " << statisticsCalculator->GetRadius90() << " " << statisticsCalculator->GetAverageEccentricity() << " " << statisticsCalculator->GetAverageEccentricity90() << " " << statisticsCalculator->GetAveragePathLength() << " " << statisticsCalculator->GetNumberOfCentralPoints() << " " << statisticsCalculator->GetRatioOfCentralPoints() << " " << statisticsCalculator->GetSpectralRadius() << " " << statisticsCalculator->GetSecondLargestEigenValue() << " " << statisticsCalculator->GetAdjacencyTrace() << " " << statisticsCalculator->GetAdjacencyEnergy() << " " << statisticsCalculator->GetLaplacianTrace() << " " << statisticsCalculator->GetLaplacianEnergy() << " " << statisticsCalculator->GetLaplacianSpectralGap() << " " << statisticsCalculator->GetNormalizedLaplacianTrace() << " " << statisticsCalculator->GetNormalizedLaplacianEnergy() << " " << statisticsCalculator->GetNormalizedLaplacianNumberOf2s() << " " << statisticsCalculator->GetNormalizedLaplacianNumberOf1s() << " " << statisticsCalculator->GetNormalizedLaplacianNumberOf0s() << " " << statisticsCalculator->GetNormalizedLaplacianLowerSlope() << " " << statisticsCalculator->GetNormalizedLaplacianUpperSlope() << " " << statisticsCalculator->GetSmallWorldness() << std::endl; ofstream outFile( outName.c_str(), ios::out ); if( ! outFile.is_open() ) { std::string errorMessage = "Could not open " + outName + " for writing."; MITK_TEST_CONDITION_REQUIRED( outFile.is_open(), errorMessage); return; } outFile << headerStream.str() << dataStream.str(); outFile.close(); } } /** * @brief mitkConnectomicsStatisticsCalculatorTest A test of a number of network statistics */ int mitkConnectomicsStatisticsCalculatorTest(int argc, char* argv[]) { MITK_TEST_BEGIN(mitkConnectomicsStatisticsCalculatorTest); bool invalidNumberOfArguments( argc == 1 ); if( invalidNumberOfArguments ) { std::string errorMessage = "Wrong number of arguments.\nUsage: [list of local labels]"; MITK_TEST_CONDITION_REQUIRED( invalidNumberOfArguments, errorMessage); return 0; } std::string networkName = argv[1]; std::string outName = ""; std::vector< std::vector< std::string > > vectorOfLabelVectors; if( argc > 2 ) { outName = argv[2]; for(int loop(3); loop < argc; loop++ ) { vectorOfLabelVectors.at(0).push_back( argv[loop] ); } } CalculateStatistics( networkName, outName, vectorOfLabelVectors ); MITK_TEST_END(); } diff --git a/Modules/DiffusionImaging/DiffusionCore/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.cpp b/Modules/DiffusionImaging/DiffusionCore/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.cpp index d92204518a..4136c35c9b 100644 --- a/Modules/DiffusionImaging/DiffusionCore/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.cpp @@ -1,522 +1,522 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkFiniteDiffOdfMaximaExtractionFilter_cpp #define __itkFiniteDiffOdfMaximaExtractionFilter_cpp #include "itkFiniteDiffOdfMaximaExtractionFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace boost::math; namespace itk { static bool CompareVectors(const vnl_vector_fixed< double, 3 >& v1, const vnl_vector_fixed< double, 3 >& v2) { return (v1.magnitude()>v2.magnitude()); } template< class PixelType, int ShOrder, int NrOdfDirections > FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::FiniteDiffOdfMaximaExtractionFilter() - : m_Toolkit(FSL) + : m_NormalizationMethod(MAX_VEC_NORM) , m_MaxNumPeaks(2) , m_PeakThreshold(0.4) + , m_AbsolutePeakThreshold(0) , m_ClusteringThreshold(0.9) , m_AngularThreshold(0.7) , m_NumCoeffs((ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder) - , m_NormalizationMethod(MAX_VEC_NORM) - , m_AbsolutePeakThreshold(0) + , m_Toolkit(FSL) { this->SetNumberOfRequiredInputs(1); } template< class PixelType, int ShOrder, int NrOdfDirections > void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::FindCandidatePeaks(OdfType& odf, double thr, std::vector< DirectionType >& container) { double gfa = odf.GetGeneralizedFractionalAnisotropy(); //Find the peaks using a finite difference method bool flag = true; vnl_vector_fixed< bool, NrOdfDirections > used; used.fill(false); //Find the peaks for (int i=0; ithr && val*gfa>m_AbsolutePeakThreshold) // limit to one hemisphere ??? { flag = true; std::vector< int > neighbours = odf.GetNeighbors(i); - for (int j=0; j std::vector< vnl_vector_fixed< double, 3 > > FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections>::MeanShiftClustering(std::vector< vnl_vector_fixed< double, 3 > >& inDirs) { std::vector< DirectionType > outDirs; if (inDirs.empty()) return inDirs; DirectionType oldMean, currentMean, workingMean; std::vector< int > touched; // initialize touched.resize(inDirs.size(), 0); bool free = true; currentMean = inDirs[0]; // initialize first seed while (free) { oldMean.fill(0.0); // start mean-shift clustering float angle = 0.0; int counter = 0; while ((currentMean-oldMean).magnitude()>0.0001) { counter = 0; oldMean = currentMean; workingMean = oldMean; workingMean.normalize(); currentMean.fill(0.0); - for (int i=0; i=m_ClusteringThreshold) { currentMean += inDirs[i]; touched[i] = 1; counter++; } else if (-angle>=m_ClusteringThreshold) { currentMean -= inDirs[i]; touched[i] = 1; counter++; } } } // found stable mean if (counter>0) { float mag = currentMean.magnitude(); if (mag>0) { currentMean /= mag; outDirs.push_back(currentMean); } } // find next unused seed free = false; - for (int i=0; i void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::BeforeThreadedGenerateData() { typename CoefficientImageType::Pointer ShCoeffImage = static_cast< CoefficientImageType* >( this->ProcessObject::GetInput(0) ); itk::Vector spacing = ShCoeffImage->GetSpacing(); double minSpacing = spacing[0]; if (spacing[1]GetOrigin(); itk::Matrix direction = ShCoeffImage->GetDirection(); ImageRegion<3> imageRegion = ShCoeffImage->GetLargestPossibleRegion(); if (m_MaskImage.IsNotNull()) { origin = m_MaskImage->GetOrigin(); direction = m_MaskImage->GetDirection(); imageRegion = m_MaskImage->GetLargestPossibleRegion(); } m_DirectionImageContainer = ItkDirectionImageContainer::New(); - for (int i=0; i nullVec; nullVec.Fill(0.0); ItkDirectionImage::Pointer img = ItkDirectionImage::New(); img->SetSpacing( spacing ); img->SetOrigin( origin ); img->SetDirection( direction ); img->SetRegions( imageRegion ); img->Allocate(); img->FillBuffer(nullVec); m_DirectionImageContainer->InsertElement(m_DirectionImageContainer->Size(), img); } if (m_MaskImage.IsNull()) { m_MaskImage = ItkUcharImgType::New(); m_MaskImage->SetSpacing( spacing ); m_MaskImage->SetOrigin( origin ); m_MaskImage->SetDirection( direction ); m_MaskImage->SetRegions( imageRegion ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } m_NumDirectionsImage = ItkUcharImgType::New(); m_NumDirectionsImage->SetSpacing( spacing ); m_NumDirectionsImage->SetOrigin( origin ); m_NumDirectionsImage->SetDirection( direction ); m_NumDirectionsImage->SetRegions( imageRegion ); m_NumDirectionsImage->Allocate(); m_NumDirectionsImage->FillBuffer(0); - this->SetNumberOfOutputs(m_MaxNumPeaks); + this->SetNumberOfIndexedOutputs(m_MaxNumPeaks); // calculate SH basis OdfType odf; vnl_matrix_fixed* directions = odf.GetDirections(); vnl_matrix< double > sphCoords; std::vector< DirectionType > dirs; for (int i=0; iget_column(i)); Cart2Sph(dirs, sphCoords); // convert candidate peaks to spherical angles m_ShBasis = CalcShBasis(sphCoords); // evaluate spherical harmonics at each peak MITK_INFO << "Starting finite differences maximum extraction"; MITK_INFO << "ODF sampling points: " << NrOdfDirections; MITK_INFO << "SH order: " << ShOrder; MITK_INFO << "Maximum peaks: " << m_MaxNumPeaks; MITK_INFO << "Relative threshold: " << m_PeakThreshold; MITK_INFO << "Absolute threshold: " << m_AbsolutePeakThreshold; MITK_INFO << "Clustering threshold: " << m_ClusteringThreshold; MITK_INFO << "Angular threshold: " << m_AngularThreshold; } template< class PixelType, int ShOrder, int NrOdfDirections > void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::AfterThreadedGenerateData() { MITK_INFO << "Generating vector field"; vtkSmartPointer m_VtkCellArray = vtkSmartPointer::New(); vtkSmartPointer m_VtkPoints = vtkSmartPointer::New(); typename CoefficientImageType::Pointer ShCoeffImage = static_cast< CoefficientImageType* >( this->ProcessObject::GetInput(0) ); ImageRegionConstIterator< CoefficientImageType > cit(ShCoeffImage, ShCoeffImage->GetLargestPossibleRegion() ); mitk::Vector3D spacing = ShCoeffImage->GetSpacing(); double minSpacing = spacing[0]; if (spacing[1]GetLargestPossibleRegion().GetSize()[0]*ShCoeffImage->GetLargestPossibleRegion().GetSize()[1]*ShCoeffImage->GetLargestPossibleRegion().GetSize()[2]; boost::progress_display disp(maxProgress); while( !cit.IsAtEnd() ) { ++disp; typename CoefficientImageType::IndexType index = cit.GetIndex(); if (m_MaskImage->GetPixel(index)==0) { ++cit; continue; } - for (int i=0; iSize(); i++) + for (unsigned int i=0; iSize(); i++) { ItkDirectionImage::Pointer img = m_DirectionImageContainer->GetElement(i); itk::Vector< float, 3 > pixel = img->GetPixel(index); DirectionType dir; dir[0] = pixel[0]; dir[1] = pixel[1]; dir[2] = pixel[2]; vtkSmartPointer container = vtkSmartPointer::New(); itk::ContinuousIndex center; center[0] = index[0]; center[1] = index[1]; center[2] = index[2]; itk::Point worldCenter; m_MaskImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter ); itk::Point worldStart; worldStart[0] = worldCenter[0]-dir[0]/2 * minSpacing; worldStart[1] = worldCenter[1]-dir[1]/2 * minSpacing; worldStart[2] = worldCenter[2]-dir[2]/2 * minSpacing; vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer()); container->GetPointIds()->InsertNextId(id); itk::Point worldEnd; worldEnd[0] = worldCenter[0]+dir[0]/2 * minSpacing; worldEnd[1] = worldCenter[1]+dir[1]/2 * minSpacing; worldEnd[2] = worldCenter[2]+dir[2]/2 * minSpacing; id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer()); container->GetPointIds()->InsertNextId(id); m_VtkCellArray->InsertNextCell(container); } ++cit; } vtkSmartPointer directionsPolyData = vtkSmartPointer::New(); directionsPolyData->SetPoints(m_VtkPoints); directionsPolyData->SetLines(m_VtkCellArray); m_OutputFiberBundle = mitk::FiberBundleX::New(directionsPolyData); - for (int i=0; iSize(); i++) + for (unsigned int i=0; iSize(); i++) { ItkDirectionImage::Pointer img = m_DirectionImageContainer->GetElement(i); this->SetNthOutput(i, img); } } template< class PixelType, int ShOrder, int NrOdfDirections > void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::ThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, ThreadIdType threadID ) { typename CoefficientImageType::Pointer ShCoeffImage = static_cast< CoefficientImageType* >( this->ProcessObject::GetInput(0) ); ImageRegionConstIterator< CoefficientImageType > cit(ShCoeffImage, outputRegionForThread ); OdfType odf; while( !cit.IsAtEnd() ) { typename CoefficientImageType::IndexType index = cit.GetIndex(); if (m_MaskImage->GetPixel(index)==0) { ++cit; continue; } CoefficientPixelType c = cit.Get(); // calculate ODF double max = 0; odf.Fill(0.0); for (int i=0; imax) max = odf[i]; } if (max<0.0001) { ++cit; continue; } std::vector< DirectionType > candidates, peaks, temp; peaks.clear(); max *= m_PeakThreshold; // relative threshold FindCandidatePeaks(odf, max, candidates); // find all local maxima candidates = MeanShiftClustering(candidates); // cluster maxima vnl_matrix< double > shBasis, sphCoords; Cart2Sph(candidates, sphCoords); // convert candidate peaks to spherical angles shBasis = CalcShBasis(sphCoords); // evaluate spherical harmonics at each peak max = 0.0; - for (int i=0; imax) max = val; peaks.push_back(candidates[i]*val); } std::sort( peaks.begin(), peaks.end(), CompareVectors ); // sort peaks // kick out directions to close to a larger direction (too far away to cluster but too close to keep) - int m = peaks.size(); + unsigned int m = peaks.size(); if ( m>m_DirectionImageContainer->Size() ) m = m_DirectionImageContainer->Size(); - for (int i=0; im_AngularThreshold && valm_DirectionImageContainer->Size() ) num = m_DirectionImageContainer->Size(); - for (int i=0; i dir = peaks.at(i); ItkDirectionImage::Pointer img = m_DirectionImageContainer->GetElement(i); switch (m_NormalizationMethod) { case NO_NORM: break; case SINGLE_VEC_NORM: dir.normalize(); break; case MAX_VEC_NORM: dir /= max; break; } // dir[0] = -dir[0]; // dir[2] = -dir[2]; dir = m_MaskImage->GetDirection()*dir; itk::Vector< float, 3 > pixel; pixel.SetElement(0, dir[0]); pixel.SetElement(1, dir[1]); pixel.SetElement(2, dir[2]); img->SetPixel(index, pixel); } m_NumDirectionsImage->SetPixel(index, num); ++cit; } MITK_INFO << "Thread " << threadID << " finished extraction"; } // convert cartesian to spherical coordinates template< class PixelType, int ShOrder, int NrOdfDirections > void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::Cart2Sph(const std::vector< DirectionType >& dir, vnl_matrix& sphCoords) { sphCoords.set_size(dir.size(), 2); - for (int i=0; i vnl_matrix FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::CalcShBasis(vnl_matrix& sphCoords) { int M = sphCoords.rows(); int j, m; double mag, plm; vnl_matrix shBasis; shBasis.set_size(M, m_NumCoeffs); for (int p=0; p(l,abs(m),cos(sphCoords(p,0))); mag = sqrt((double)(2*l+1)/(4.0*M_PI)*factorial(l-abs(m))/factorial(l+abs(m)))*plm; if (m<0) shBasis(p,j) = sqrt(2.0)*mag*cos(fabs((double)m)*sphCoords(p,1)); else if (m==0) shBasis(p,j) = mag; else shBasis(p,j) = pow(-1.0, m)*sqrt(2.0)*mag*sin(m*sphCoords(p,1)); break; case MRTRIX: plm = legendre_p(l,abs(m),-cos(sphCoords(p,0))); mag = sqrt((double)(2*l+1)/(4.0*M_PI)*factorial(l-abs(m))/factorial(l+abs(m)))*plm; if (m>0) shBasis(p,j) = mag*cos(m*sphCoords(p,1)); else if (m==0) shBasis(p,j) = mag; else shBasis(p,j) = mag*sin(-m*sphCoords(p,1)); break; } j++; } } return shBasis; } } #endif // __itkFiniteDiffOdfMaximaExtractionFilter_cpp diff --git a/Modules/DiffusionImaging/DiffusionCore/Algorithms/itkProjectionFilter.txx b/Modules/DiffusionImaging/DiffusionCore/Algorithms/itkProjectionFilter.txx index 39228e4f76..989637d358 100644 --- a/Modules/DiffusionImaging/DiffusionCore/Algorithms/itkProjectionFilter.txx +++ b/Modules/DiffusionImaging/DiffusionCore/Algorithms/itkProjectionFilter.txx @@ -1,202 +1,194 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _itkProjectionFilter_txx #define _itkProjectionFilter_txx #include "itkProjectionFilter.h" #include "mitkProgressBar.h" //#include #define SEARCHSIGMA 10 /* length in linear voxel dimensions */ #define MAXSEARCHLENGTH (3*SEARCHSIGMA) namespace itk { ProjectionFilter::ProjectionFilter() { } ProjectionFilter::~ProjectionFilter() { } void ProjectionFilter::Project() { // Contains only code for the projection of FA data. The original FSL code contains some extra lines // For projection of other measurements than FA mitk::ProgressBar::GetInstance()->AddStepsToDo( 3 ); Float4DImageType::Pointer data_4d_projected = Float4DImageType::New(); data_4d_projected->SetRegions(m_AllFA->GetRequestedRegion()); data_4d_projected->SetDirection(m_AllFA->GetDirection()); data_4d_projected->SetSpacing(m_AllFA->GetSpacing()); data_4d_projected->SetOrigin(m_AllFA->GetOrigin()); data_4d_projected->Allocate(); data_4d_projected->FillBuffer(0.0); Float4DImageType::SizeType size = m_AllFA->GetRequestedRegion().GetSize(); - for(int t=0; tGetPixel(ix) != 0) { VectorImageType::PixelType dir = m_Directions->GetPixel(ix); - short maxvalX=0, maxvalY=0, maxvalZ=0; Float4DImageType::IndexType ix4d; ix4d[0]=x; ix4d[1]=y; ix4d[2]=z; ix4d[3]=t; float maxval = m_AllFA->GetPixel(ix4d); float maxval_weighted = maxval; float exponentfactor = -0.5 * (dir[0]*dir[0]+dir[1]*dir[1]+dir[2]*dir[2]) / (float)(SEARCHSIGMA*SEARCHSIGMA); // No tubular structure here if(m_Tube->GetPixel(ix) == 0) { for(int iters=0;iters<2;iters++) { float distance=0; - for(int d=1;d=size[0] && dy<=size[1] && dz<=size[2]) + if(dx>=size[0] && dy<=size[1] && dz<=size[2]) { d=MAXSEARCHLENGTH; } else if(m_DistanceMap->GetPixel(ix3d)>=distance) { float distanceweight = exp(d * d * exponentfactor); distance = m_DistanceMap->GetPixel(ix3d); ix4d[0]=x+dir[0]*D; ix4d[1]=y+dir[1]*D; ix4d[2]=z+dir[2]*D; ix4d[3]=t; if(distanceweight*m_AllFA->GetPixel(ix4d)>maxval_weighted) { maxval = m_AllFA->GetPixel(ix4d); maxval_weighted = maxval*distanceweight; - maxvalX = dir[0]*D; - maxvalY = dir[1]*D; - maxvalZ = dir[2]*D; } } else{ d=MAXSEARCHLENGTH; } } } } // Tubular structure else { for(int dy=-MAXSEARCHLENGTH; dy<=MAXSEARCHLENGTH;dy++) { for(int dx=-MAXSEARCHLENGTH; dx<=MAXSEARCHLENGTH; dx++) { float distanceweight = exp(-0.5 * (dx*dx+dy*dy) / (float)(SEARCHSIGMA*SEARCHSIGMA) ); float r=sqrt((float)(dx*dx+dy*dy)); if (r>0) { int allok=1; for(float rr=1; rr<=r+0.1; rr++) /* search outwards from centre to current voxel - test that distancemap always increasing */ { int dx1=round(rr*dx/r); int dy1=round(rr*dy/r); int dx2=round((rr+1)*dx/r); int dy2=round((rr+1)*dy/r); RealImageType::IndexType ix1, ix2; ix1[0]=x+dx1; ix1[1]=y+dy1; ix1[2]=z; ix2[0]=x+dx2; ix2[1]=y+dy2; ix2[2]=z; if(m_DistanceMap->GetPixel(ix1) > m_DistanceMap->GetPixel(ix2) ) { allok=0; } } ix4d[0]=x+dx; ix4d[1]=y+dy, ix4d[2]=z; ix4d[3]=t; if( allok && (distanceweight * m_AllFA->GetPixel(ix4d) > maxval_weighted) ) { maxval = m_AllFA->GetPixel(ix4d); maxval_weighted = maxval * distanceweight; - maxvalX=dx; - maxvalY=dy; - maxvalZ=0; } } } } } ix4d[0]=x; ix4d[1]=y; ix4d[2]=z; ix4d[3]=t; data_4d_projected->SetPixel(ix4d, maxval); } } } } } m_Projections = data_4d_projected; } } #endif // _itkProjectionFilter_txx diff --git a/Modules/DiffusionImaging/DiffusionCore/Rendering/mitkOdfVtkMapper2D.txx b/Modules/DiffusionImaging/DiffusionCore/Rendering/mitkOdfVtkMapper2D.txx index a15655f52b..39cc17361c 100644 --- a/Modules/DiffusionImaging/DiffusionCore/Rendering/mitkOdfVtkMapper2D.txx +++ b/Modules/DiffusionImaging/DiffusionCore/Rendering/mitkOdfVtkMapper2D.txx @@ -1,884 +1,884 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkOdfVtkMapper2D_txx__ #define __mitkOdfVtkMapper2D_txx__ #include "mitkOdfVtkMapper2D.h" #include "mitkDataNode.h" #include "mitkBaseRenderer.h" #include "mitkMatrixConvert.h" #include "mitkGeometry3D.h" #include "mitkTimeGeometry.h" #include "mitkOdfNormalizationMethodProperty.h" #include "mitkOdfScaleByProperty.h" #include "mitkProperties.h" #include "mitkTensorImage.h" #include "vtkSphereSource.h" #include "vtkPropCollection.h" #include "vtkMaskedGlyph3D.h" #include "vtkGlyph2D.h" #include "vtkGlyph3D.h" #include "vtkMaskedProgrammableGlyphFilter.h" #include "vtkImageData.h" #include "vtkLinearTransform.h" #include "vtkCamera.h" #include "vtkPointData.h" #include "vtkTransformPolyDataFilter.h" #include "vtkTransform.h" #include "vtkOdfSource.h" #include "vtkDoubleArray.h" #include "vtkLookupTable.h" #include "vtkProperty.h" #include "vtkPolyDataNormals.h" #include "vtkLight.h" #include "vtkLightCollection.h" #include "vtkMath.h" #include "vtkFloatArray.h" #include "vtkDelaunay2D.h" #include "vtkMapper.h" #include "vtkRenderer.h" #include "itkOrientationDistributionFunction.h" #include "itkFixedArray.h" #include #include "vtkOpenGLRenderer.h" #define _USE_MATH_DEFINES #include template vtkSmartPointer mitk::OdfVtkMapper2D::m_OdfTransform = vtkSmartPointer::New(); template vtkSmartPointer mitk::OdfVtkMapper2D::m_OdfSource = vtkSmartPointer::New(); template float mitk::OdfVtkMapper2D::m_Scaling; template int mitk::OdfVtkMapper2D::m_Normalization; template int mitk::OdfVtkMapper2D::m_ScaleBy; template float mitk::OdfVtkMapper2D::m_IndexParam1; template float mitk::OdfVtkMapper2D::m_IndexParam2; #define ODF_MAPPER_PI M_PI template mitk::OdfVtkMapper2D::LocalStorage::LocalStorage() { m_PropAssemblies.push_back(vtkPropAssembly::New()); m_PropAssemblies.push_back(vtkPropAssembly::New()); m_PropAssemblies.push_back(vtkPropAssembly::New()); m_OdfsPlanes.push_back(vtkAppendPolyData::New()); m_OdfsPlanes.push_back(vtkAppendPolyData::New()); m_OdfsPlanes.push_back(vtkAppendPolyData::New()); m_OdfsPlanes[0]->AddInputData(vtkPolyData::New()); m_OdfsPlanes[1]->AddInputData(vtkPolyData::New()); m_OdfsPlanes[2]->AddInputData(vtkPolyData::New()); m_OdfsActors.push_back(vtkActor::New()); m_OdfsActors.push_back(vtkActor::New()); m_OdfsActors.push_back(vtkActor::New()); m_OdfsActors[0]->GetProperty()->SetInterpolationToGouraud(); m_OdfsActors[1]->GetProperty()->SetInterpolationToGouraud(); m_OdfsActors[2]->GetProperty()->SetInterpolationToGouraud(); m_OdfsMappers.push_back(vtkPolyDataMapper::New()); m_OdfsMappers.push_back(vtkPolyDataMapper::New()); m_OdfsMappers.push_back(vtkPolyDataMapper::New()); vtkLookupTable *lut = vtkLookupTable::New(); m_OdfsMappers[0]->SetLookupTable(lut); m_OdfsMappers[1]->SetLookupTable(lut); m_OdfsMappers[2]->SetLookupTable(lut); m_OdfsActors[0]->SetMapper(m_OdfsMappers[0]); m_OdfsActors[1]->SetMapper(m_OdfsMappers[1]); m_OdfsActors[2]->SetMapper(m_OdfsMappers[2]); } template mitk::OdfVtkMapper2D ::OdfVtkMapper2D() { m_Planes.push_back(vtkPlane::New()); m_Planes.push_back(vtkPlane::New()); m_Planes.push_back(vtkPlane::New()); m_Cutters.push_back(vtkCutter::New()); m_Cutters.push_back(vtkCutter::New()); m_Cutters.push_back(vtkCutter::New()); m_Cutters[0]->SetCutFunction( m_Planes[0] ); m_Cutters[0]->GenerateValues( 1, 0, 1 ); m_Cutters[1]->SetCutFunction( m_Planes[1] ); m_Cutters[1]->GenerateValues( 1, 0, 1 ); m_Cutters[2]->SetCutFunction( m_Planes[2] ); m_Cutters[2]->GenerateValues( 1, 0, 1 ); // Windowing the cutted planes in direction 1 m_ThickPlanes1.push_back(vtkThickPlane::New()); m_ThickPlanes1.push_back(vtkThickPlane::New()); m_ThickPlanes1.push_back(vtkThickPlane::New()); m_Clippers1.push_back(vtkClipPolyData::New()); m_Clippers1.push_back(vtkClipPolyData::New()); m_Clippers1.push_back(vtkClipPolyData::New()); m_Clippers1[0]->SetClipFunction( m_ThickPlanes1[0] ); m_Clippers1[1]->SetClipFunction( m_ThickPlanes1[1] ); m_Clippers1[2]->SetClipFunction( m_ThickPlanes1[2] ); // Windowing the cutted planes in direction 2 m_ThickPlanes2.push_back(vtkThickPlane::New()); m_ThickPlanes2.push_back(vtkThickPlane::New()); m_ThickPlanes2.push_back(vtkThickPlane::New()); m_Clippers2.push_back(vtkClipPolyData::New()); m_Clippers2.push_back(vtkClipPolyData::New()); m_Clippers2.push_back(vtkClipPolyData::New()); m_Clippers2[0]->SetClipFunction( m_ThickPlanes2[0] ); m_Clippers2[1]->SetClipFunction( m_ThickPlanes2[1] ); m_Clippers2[2]->SetClipFunction( m_ThickPlanes2[2] ); m_ShowMaxNumber = 500; } template mitk::OdfVtkMapper2D ::~OdfVtkMapper2D() { } template mitk::Image* mitk::OdfVtkMapper2D ::GetInput() { return static_cast ( m_DataNode->GetData() ); } template vtkProp* mitk::OdfVtkMapper2D ::GetVtkProp(mitk::BaseRenderer* renderer) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); return localStorage->m_PropAssemblies[GetIndex(renderer)]; } template int mitk::OdfVtkMapper2D ::GetIndex(mitk::BaseRenderer* renderer) { if(!strcmp(renderer->GetName(),"stdmulti.widget1")) return 0; if(!strcmp(renderer->GetName(),"stdmulti.widget2")) return 1; if(!strcmp(renderer->GetName(),"stdmulti.widget3")) return 2; return 0; } template void mitk::OdfVtkMapper2D ::GlyphMethod(void *arg) { vtkMaskedProgrammableGlyphFilter* pfilter=(vtkMaskedProgrammableGlyphFilter*)arg; double point[3]; double debugpoint[3]; pfilter->GetPoint(point); pfilter->GetPoint(debugpoint); itk::Point p(point); Vector3D spacing = pfilter->GetGeometry()->GetSpacing(); p[0] /= spacing[0]; p[1] /= spacing[1]; p[2] /= spacing[2]; mitk::Point3D p2; pfilter->GetGeometry()->IndexToWorld( p, p2 ); point[0] = p2[0]; point[1] = p2[1]; point[2] = p2[2]; vtkPointData* data = pfilter->GetPointData(); vtkDataArray* odfvals = data->GetArray("vector"); vtkIdType id = pfilter->GetPointId(); m_OdfTransform->Identity(); m_OdfTransform->Translate(point[0],point[1],point[2]); typedef itk::OrientationDistributionFunction OdfType; OdfType odf; if(odfvals->GetNumberOfComponents()==6) { float tensorelems[6] = { (float)odfvals->GetComponent(id,0), (float)odfvals->GetComponent(id,1), (float)odfvals->GetComponent(id,2), (float)odfvals->GetComponent(id,3), (float)odfvals->GetComponent(id,4), (float)odfvals->GetComponent(id,5), }; itk::DiffusionTensor3D tensor(tensorelems); odf.InitFromTensor(tensor); } else { for(int i=0; iGetComponent(id,i); } switch(m_ScaleBy) { case ODFSB_NONE: m_OdfSource->SetScale(m_Scaling); break; case ODFSB_GFA: m_OdfSource->SetScale(m_Scaling*odf.GetGeneralizedGFA(m_IndexParam1, m_IndexParam2)); break; case ODFSB_PC: m_OdfSource->SetScale(m_Scaling*odf.GetPrincipleCurvature(m_IndexParam1, m_IndexParam2, 0)); break; } m_OdfSource->SetNormalization(m_Normalization); m_OdfSource->SetOdf(odf); m_OdfSource->Modified(); } template typename mitk::OdfVtkMapper2D::OdfDisplayGeometry mitk::OdfVtkMapper2D ::MeasureDisplayedGeometry(mitk::BaseRenderer* renderer) { Geometry2D::ConstPointer worldGeometry = renderer->GetCurrentWorldGeometry2D(); PlaneGeometry::ConstPointer worldPlaneGeometry = dynamic_cast( worldGeometry.GetPointer() ); // set up the cutter orientation according to the current geometry of // the renderers plane double vp[ 3 ], vnormal[ 3 ]; Point3D point = worldPlaneGeometry->GetOrigin(); Vector3D normal = worldPlaneGeometry->GetNormal(); normal.Normalize(); vnl2vtk( point.GetVnlVector(), vp ); vnl2vtk( normal.GetVnlVector(), vnormal ); mitk::DisplayGeometry::Pointer dispGeometry = renderer->GetDisplayGeometry(); mitk::Vector2D size = dispGeometry->GetSizeInMM(); mitk::Vector2D origin = dispGeometry->GetOriginInMM(); // // |------O------| // | d2 | // L d1 M | // | | // |-------------| // mitk::Vector2D M; mitk::Vector2D L; mitk::Vector2D O; M[0] = origin[0] + size[0]/2; M[1] = origin[1] + size[1]/2; L[0] = origin[0]; L[1] = origin[1] + size[1]/2; O[0] = origin[0] + size[0]/2; O[1] = origin[1] + size[1]; mitk::Point2D point1; point1[0] = M[0]; point1[1] = M[1]; mitk::Point3D M3D; dispGeometry->Map(point1, M3D); point1[0] = L[0]; point1[1] = L[1]; mitk::Point3D L3D; dispGeometry->Map(point1, L3D); point1[0] = O[0]; point1[1] = O[1]; mitk::Point3D O3D; dispGeometry->Map(point1, O3D); double d1 = sqrt((M3D[0]-L3D[0])*(M3D[0]-L3D[0]) + (M3D[1]-L3D[1])*(M3D[1]-L3D[1]) + (M3D[2]-L3D[2])*(M3D[2]-L3D[2])); double d2 = sqrt((M3D[0]-O3D[0])*(M3D[0]-O3D[0]) + (M3D[1]-O3D[1])*(M3D[1]-O3D[1]) + (M3D[2]-O3D[2])*(M3D[2]-O3D[2])); double d = d1>d2 ? d1 : d2; d = d2; OdfDisplayGeometry retval; retval.vp[0] = vp[0]; retval.vp[1] = vp[1]; retval.vp[2] = vp[2]; retval.vnormal[0] = vnormal[0]; retval.vnormal[1] = vnormal[1]; retval.vnormal[2] = vnormal[2]; retval.normal[0] = normal[0]; retval.normal[1] = normal[1]; retval.normal[2] = normal[2]; retval.d = d; retval.d1 = d1; retval.d2 = d2; retval.M3D[0] = M3D[0]; retval.M3D[1] = M3D[1]; retval.M3D[2] = M3D[2]; retval.L3D[0] = L3D[0]; retval.L3D[1] = L3D[1]; retval.L3D[2] = L3D[2]; retval.O3D[0] = O3D[0]; retval.O3D[1] = O3D[1]; retval.O3D[2] = O3D[2]; retval.vp_original[0] = vp[0]; retval.vp_original[1] = vp[1]; retval.vp_original[2] = vp[2]; retval.vnormal_original[0] = vnormal[0]; retval.vnormal_original[1] = vnormal[1]; retval.vnormal_original[2] = vnormal[2]; retval.size[0] = size[0]; retval.size[1] = size[1]; retval.origin[0] = origin[0]; retval.origin[1] = origin[1]; return retval; } template void mitk::OdfVtkMapper2D ::Slice(mitk::BaseRenderer* renderer, OdfDisplayGeometry dispGeo) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); vtkLinearTransform * vtktransform = this->GetDataNode()->GetVtkTransform(this->GetTimestep()); int index = GetIndex(renderer); vtkSmartPointer inversetransform = vtkSmartPointer::New(); inversetransform->Identity(); inversetransform->Concatenate(vtktransform->GetLinearInverse()); double myscale[3]; ((vtkTransform*)vtktransform)->GetScale(myscale); inversetransform->PostMultiply(); inversetransform->Scale(1*myscale[0],1*myscale[1],1*myscale[2]); inversetransform->TransformPoint( dispGeo.vp, dispGeo.vp ); inversetransform->TransformNormalAtPoint( dispGeo.vp, dispGeo.vnormal, dispGeo.vnormal ); // vtk works in axis align coords // thus the normal also must be axis align, since // we do not allow arbitrary cutting through volume // // vnormal should already be axis align, but in order // to get rid of precision effects, we set the two smaller // components to zero here int dims[3]; m_VtkImage->GetDimensions(dims); double spac[3]; m_VtkImage->GetSpacing(spac); if(fabs(dispGeo.vnormal[0]) > fabs(dispGeo.vnormal[1]) && fabs(dispGeo.vnormal[0]) > fabs(dispGeo.vnormal[2]) ) { if(fabs(dispGeo.vp[0]/spac[0]) < 0.4) dispGeo.vp[0] = 0.4*spac[0]; if(fabs(dispGeo.vp[0]/spac[0]) > (dims[0]-1)-0.4) dispGeo.vp[0] = ((dims[0]-1)-0.4)*spac[0]; dispGeo.vnormal[1] = 0; dispGeo.vnormal[2] = 0; } if(fabs(dispGeo.vnormal[1]) > fabs(dispGeo.vnormal[0]) && fabs(dispGeo.vnormal[1]) > fabs(dispGeo.vnormal[2]) ) { if(fabs(dispGeo.vp[1]/spac[1]) < 0.4) dispGeo.vp[1] = 0.4*spac[1]; if(fabs(dispGeo.vp[1]/spac[1]) > (dims[1]-1)-0.4) dispGeo.vp[1] = ((dims[1]-1)-0.4)*spac[1]; dispGeo.vnormal[0] = 0; dispGeo.vnormal[2] = 0; } if(fabs(dispGeo.vnormal[2]) > fabs(dispGeo.vnormal[1]) && fabs(dispGeo.vnormal[2]) > fabs(dispGeo.vnormal[0]) ) { if(fabs(dispGeo.vp[2]/spac[2]) < 0.4) dispGeo.vp[2] = 0.4*spac[2]; if(fabs(dispGeo.vp[2]/spac[2]) > (dims[2]-1)-0.4) dispGeo.vp[2] = ((dims[2]-1)-0.4)*spac[2]; dispGeo.vnormal[0] = 0; dispGeo.vnormal[1] = 0; } m_Planes[index]->SetTransform( (vtkAbstractTransform*)NULL ); m_Planes[index]->SetOrigin( dispGeo.vp ); m_Planes[index]->SetNormal( dispGeo.vnormal ); vtkSmartPointer points; vtkSmartPointer tmppoints; vtkSmartPointer polydata; vtkSmartPointer pointdata; vtkSmartPointer delaunay; vtkSmartPointer cuttedPlane; // the cutter only works if we do not have a 2D-image // or if we have a 2D-image and want to see the whole image. // // for side views of 2D-images, we need some special treatment if(!( (dims[0] == 1 && dispGeo.vnormal[0] != 0) || (dims[1] == 1 && dispGeo.vnormal[1] != 0) || (dims[2] == 1 && dispGeo.vnormal[2] != 0) )) { m_Cutters[index]->SetCutFunction( m_Planes[index] ); m_Cutters[index]->SetInputData( m_VtkImage ); m_Cutters[index]->Update(); cuttedPlane = m_Cutters[index]->GetOutput(); } else { // cutting of a 2D-Volume does not work, // so we have to build up our own polydata object cuttedPlane = vtkPolyData::New(); points = vtkPoints::New(); points->SetNumberOfPoints(m_VtkImage->GetNumberOfPoints()); for(int i=0; iGetNumberOfPoints(); i++) { points->SetPoint(i, m_VtkImage->GetPoint(i)); } cuttedPlane->SetPoints(points); pointdata = vtkFloatArray::New(); int comps = m_VtkImage->GetPointData()->GetScalars()->GetNumberOfComponents(); pointdata->SetNumberOfComponents(comps); int tuples = m_VtkImage->GetPointData()->GetScalars()->GetNumberOfTuples(); pointdata->SetNumberOfTuples(tuples); for(int i=0; iSetTuple(i,m_VtkImage->GetPointData()->GetScalars()->GetTuple(i)); pointdata->SetName( "vector" ); cuttedPlane->GetPointData()->AddArray(pointdata); int nZero1, nZero2; if(dims[0]==1) { nZero1 = 1; nZero2 = 2; } else if(dims[1]==1) { nZero1 = 0; nZero2 = 2; } else { nZero1 = 0; nZero2 = 1; } tmppoints = vtkPoints::New(); for(int j=0; jGetNumberOfPoints(); j++){ double pt[3]; m_VtkImage->GetPoint(j,pt); tmppoints->InsertNextPoint(pt[nZero1],pt[nZero2],0); } polydata = vtkPolyData::New(); polydata->SetPoints( tmppoints ); delaunay = vtkDelaunay2D::New(); delaunay->SetInputData( polydata ); delaunay->Update(); vtkCellArray* polys = delaunay->GetOutput()->GetPolys(); cuttedPlane->SetPolys(polys); } if(cuttedPlane->GetNumberOfPoints()) { // WINDOWING HERE inversetransform = vtkTransform::New(); inversetransform->Identity(); inversetransform->Concatenate(vtktransform->GetLinearInverse()); double myscale[3]; ((vtkTransform*)vtktransform)->GetScale(myscale); inversetransform->PostMultiply(); inversetransform->Scale(1*myscale[0],1*myscale[1],1*myscale[2]); dispGeo.vnormal[0] = dispGeo.M3D[0]-dispGeo.O3D[0]; dispGeo.vnormal[1] = dispGeo.M3D[1]-dispGeo.O3D[1]; dispGeo.vnormal[2] = dispGeo.M3D[2]-dispGeo.O3D[2]; vtkMath::Normalize(dispGeo.vnormal); dispGeo.vp[0] = dispGeo.M3D[0]; dispGeo.vp[1] = dispGeo.M3D[1]; dispGeo.vp[2] = dispGeo.M3D[2]; inversetransform->TransformPoint( dispGeo.vp, dispGeo.vp ); inversetransform->TransformNormalAtPoint( dispGeo.vp, dispGeo.vnormal, dispGeo.vnormal ); m_ThickPlanes1[index]->count = 0; m_ThickPlanes1[index]->SetTransform((vtkAbstractTransform*)NULL ); m_ThickPlanes1[index]->SetPose( dispGeo.vnormal, dispGeo.vp ); m_ThickPlanes1[index]->SetThickness(dispGeo.d2); m_Clippers1[index]->SetClipFunction( m_ThickPlanes1[index] ); m_Clippers1[index]->SetInputData( cuttedPlane ); m_Clippers1[index]->SetInsideOut(1); m_Clippers1[index]->Update(); dispGeo.vnormal[0] = dispGeo.M3D[0]-dispGeo.L3D[0]; dispGeo.vnormal[1] = dispGeo.M3D[1]-dispGeo.L3D[1]; dispGeo.vnormal[2] = dispGeo.M3D[2]-dispGeo.L3D[2]; vtkMath::Normalize(dispGeo.vnormal); dispGeo.vp[0] = dispGeo.M3D[0]; dispGeo.vp[1] = dispGeo.M3D[1]; dispGeo.vp[2] = dispGeo.M3D[2]; inversetransform->TransformPoint( dispGeo.vp, dispGeo.vp ); inversetransform->TransformNormalAtPoint( dispGeo.vp, dispGeo.vnormal, dispGeo.vnormal ); m_ThickPlanes2[index]->count = 0; m_ThickPlanes2[index]->SetTransform((vtkAbstractTransform*)NULL ); m_ThickPlanes2[index]->SetPose( dispGeo.vnormal, dispGeo.vp ); m_ThickPlanes2[index]->SetThickness(dispGeo.d1); m_Clippers2[index]->SetClipFunction( m_ThickPlanes2[index] ); m_Clippers2[index]->SetInputData( m_Clippers1[index]->GetOutput() ); m_Clippers2[index]->SetInsideOut(1); m_Clippers2[index]->Update(); cuttedPlane = m_Clippers2[index]->GetOutput (); if(cuttedPlane->GetNumberOfPoints()) { localStorage->m_OdfsPlanes[index]->RemoveAllInputs(); vtkSmartPointer normals = vtkSmartPointer::New(); normals->SetInputConnection( m_OdfSource->GetOutputPort() ); normals->SplittingOff(); normals->ConsistencyOff(); normals->AutoOrientNormalsOff(); normals->ComputePointNormalsOn(); normals->ComputeCellNormalsOff(); normals->FlipNormalsOff(); normals->NonManifoldTraversalOff(); vtkSmartPointer trans = vtkSmartPointer::New(); trans->SetInputConnection( normals->GetOutputPort() ); trans->SetTransform(m_OdfTransform); vtkSmartPointer glyphGenerator = vtkSmartPointer::New(); glyphGenerator->SetMaximumNumberOfPoints(std::min(m_ShowMaxNumber,(int)cuttedPlane->GetNumberOfPoints())); glyphGenerator->SetRandomMode(0); glyphGenerator->SetUseMaskPoints(1); glyphGenerator->SetSourceData(trans->GetOutput() ); glyphGenerator->SetInput(cuttedPlane); glyphGenerator->SetColorModeToColorBySource(); glyphGenerator->SetInputArrayToProcess(0,0,0, vtkDataObject::FIELD_ASSOCIATION_POINTS , "vector"); glyphGenerator->SetGeometry(this->GetDataNode()->GetData()->GetGeometry()); glyphGenerator->SetGlyphMethod(&(GlyphMethod),(void *)glyphGenerator); try { glyphGenerator->Update(); } catch( itk::ExceptionObject& err ) { std::cout << err << std::endl; } localStorage->m_OdfsPlanes[index]->AddInputConnection(glyphGenerator->GetOutputPort()); localStorage->m_OdfsPlanes[index]->Update(); } } localStorage->m_PropAssemblies[index]->VisibilityOn(); if(localStorage->m_PropAssemblies[index]->GetParts()->IsItemPresent(localStorage->m_OdfsActors[index])) localStorage->m_PropAssemblies[index]->RemovePart(localStorage->m_OdfsActors[index]); localStorage->m_OdfsMappers[index]->SetInputData(localStorage->m_OdfsPlanes[index]->GetOutput()); localStorage->m_PropAssemblies[index]->AddPart(localStorage->m_OdfsActors[index]); } template bool mitk::OdfVtkMapper2D ::IsVisibleOdfs(mitk::BaseRenderer* renderer) { mitk::Image::Pointer input = const_cast(this->GetInput()); const TimeGeometry *inputTimeGeometry = input->GetTimeGeometry(); if(inputTimeGeometry==NULL || inputTimeGeometry->CountTimeSteps()==0 || !inputTimeGeometry->IsValidTimeStep(this->GetTimestep())) return false; if(this->IsPlaneRotated(renderer)) return false; bool retval = false; switch(GetIndex(renderer)) { case 0: GetDataNode()->GetVisibility(retval, renderer, "VisibleOdfs_T"); break; case 1: GetDataNode()->GetVisibility(retval, renderer, "VisibleOdfs_S"); break; case 2: GetDataNode()->GetVisibility(retval, renderer, "VisibleOdfs_C"); break; } return retval; } template void mitk::OdfVtkMapper2D ::MitkRenderOverlay(mitk::BaseRenderer* renderer) { if ( this->IsVisibleOdfs(renderer)==false ) return; if ( this->GetVtkProp(renderer)->GetVisibility() ) this->GetVtkProp(renderer)->RenderOverlay(renderer->GetVtkRenderer()); } template void mitk::OdfVtkMapper2D ::MitkRenderOpaqueGeometry(mitk::BaseRenderer* renderer) { if ( this->IsVisibleOdfs( renderer )==false ) return; if ( this->GetVtkProp(renderer)->GetVisibility() ) { // adapt cam pos this->GetVtkProp(renderer)->RenderOpaqueGeometry( renderer->GetVtkRenderer() ); } } template void mitk::OdfVtkMapper2D ::MitkRenderTranslucentGeometry(mitk::BaseRenderer* renderer) { if ( this->IsVisibleOdfs(renderer)==false ) return; if ( this->GetVtkProp(renderer)->GetVisibility() ) this->GetVtkProp(renderer)->RenderTranslucentPolygonalGeometry(renderer->GetVtkRenderer()); } template void mitk::OdfVtkMapper2D ::Update(mitk::BaseRenderer* renderer) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if ( !visible ) return; mitk::Image::Pointer input = const_cast( this->GetInput() ); if ( input.IsNull() ) return ; std::string classname("TensorImage"); if(classname.compare(input->GetNameOfClass())==0) m_VtkImage = dynamic_cast( this->GetInput() )->GetNonRgbVtkImageData(); std::string qclassname("QBallImage"); if(qclassname.compare(input->GetNameOfClass())==0) m_VtkImage = dynamic_cast( this->GetInput() )->GetNonRgbVtkImageData(); if( m_VtkImage ) { // make sure, that we have point data with more than 1 component (as vectors) vtkPointData* pointData = m_VtkImage->GetPointData(); if ( pointData == NULL ) { itkWarningMacro( << "m_VtkImage->GetPointData() returns NULL!" ); return ; } if ( pointData->GetNumberOfArrays() == 0 ) { itkWarningMacro( << "m_VtkImage->GetPointData()->GetNumberOfArrays() is 0!" ); return ; } else if ( pointData->GetArray(0)->GetNumberOfComponents() != N && pointData->GetArray(0)->GetNumberOfComponents() != 6 /*for tensor visualization*/) { itkWarningMacro( << "number of components != number of directions in ODF!" ); return; } else if ( pointData->GetArrayName( 0 ) == NULL ) { m_VtkImage->GetPointData()->GetArray(0)->SetName("vector"); } GenerateDataForRenderer(renderer); } else { itkWarningMacro( << "m_VtkImage is NULL!" ); return ; } } template void mitk::OdfVtkMapper2D ::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); OdfDisplayGeometry dispGeo = MeasureDisplayedGeometry( renderer); if ( (localStorage->m_LastUpdateTime >= m_DataNode->GetMTime()) //was the node modified? && (localStorage->m_LastUpdateTime >= m_DataNode->GetPropertyList()->GetMTime()) //was a property modified? && (localStorage->m_LastUpdateTime >= m_DataNode->GetPropertyList(renderer)->GetMTime()) && dispGeo.Equals(m_LastDisplayGeometry)) return; localStorage->m_LastUpdateTime.Modified(); if(!IsVisibleOdfs(renderer)) { localStorage->m_OdfsActors[0]->VisibilityOff(); localStorage->m_OdfsActors[1]->VisibilityOff(); localStorage->m_OdfsActors[2]->VisibilityOff(); } else { localStorage->m_OdfsActors[0]->VisibilityOn(); localStorage->m_OdfsActors[1]->VisibilityOn(); localStorage->m_OdfsActors[2]->VisibilityOn(); m_OdfSource->SetAdditionalScale(GetMinImageSpacing(GetIndex(renderer))); ApplyPropertySettings(); Slice(renderer, dispGeo); m_LastDisplayGeometry = dispGeo; } } template double mitk::OdfVtkMapper2D::GetMinImageSpacing( int index ) { // Spacing adapted scaling double spacing[3]; m_VtkImage->GetSpacing(spacing); - double min; + double min = spacing[0]; if(index==0) { min = spacing[0]; min = min > spacing[1] ? spacing[1] : min; } if(index==1) { min = spacing[1]; min = min > spacing[2] ? spacing[2] : min; } if(index==2) { min = spacing[0]; min = min > spacing[2] ? spacing[2] : min; } return min; } template void mitk::OdfVtkMapper2D ::ApplyPropertySettings() { this->GetDataNode()->GetFloatProperty( "Scaling", m_Scaling ); this->GetDataNode()->GetIntProperty( "ShowMaxNumber", m_ShowMaxNumber ); OdfNormalizationMethodProperty* nmp = dynamic_cast(this->GetDataNode()->GetProperty( "Normalization" )); if(nmp) m_Normalization = nmp->GetNormalization(); OdfScaleByProperty* sbp = dynamic_cast(this->GetDataNode()->GetProperty( "ScaleBy" )); if(sbp) m_ScaleBy = sbp->GetScaleBy(); this->GetDataNode()->GetFloatProperty( "IndexParam1", m_IndexParam1); this->GetDataNode()->GetFloatProperty( "IndexParam2", m_IndexParam2); } template bool mitk::OdfVtkMapper2D ::IsPlaneRotated(mitk::BaseRenderer* renderer) { Geometry2D::ConstPointer worldGeometry = renderer->GetCurrentWorldGeometry2D(); PlaneGeometry::ConstPointer worldPlaneGeometry = dynamic_cast( worldGeometry.GetPointer() ); double vnormal[ 3 ]; Vector3D normal = worldPlaneGeometry->GetNormal(); normal.Normalize(); vnl2vtk( normal.GetVnlVector(), vnormal ); vtkLinearTransform * vtktransform = this->GetDataNode()->GetVtkTransform(this->GetTimestep()); vtkSmartPointer inversetransform = vtkSmartPointer::New(); inversetransform->Identity(); inversetransform->Concatenate(vtktransform->GetLinearInverse()); double* n = inversetransform->TransformNormal(vnormal); int nonZeros = 0; for (int j=0; j<3; j++) { if (fabs(n[j])>mitk::eps){ nonZeros++; } } if(nonZeros>1) return true; return false; } template void mitk::OdfVtkMapper2D ::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* /*renderer*/, bool /*overwrite*/) { node->SetProperty( "ShowMaxNumber", mitk::IntProperty::New( 150 ) ); node->SetProperty( "Scaling", mitk::FloatProperty::New( 1.0 ) ); node->SetProperty( "Normalization", mitk::OdfNormalizationMethodProperty::New()); node->SetProperty( "ScaleBy", mitk::OdfScaleByProperty::New()); node->SetProperty( "IndexParam1", mitk::FloatProperty::New(2)); node->SetProperty( "IndexParam2", mitk::FloatProperty::New(1)); node->SetProperty( "visible", mitk::BoolProperty::New( true ) ); node->SetProperty( "VisibleOdfs_T", mitk::BoolProperty::New( false ) ); node->SetProperty( "VisibleOdfs_C", mitk::BoolProperty::New( false ) ); node->SetProperty( "VisibleOdfs_S", mitk::BoolProperty::New( false ) ); node->SetProperty ("layer", mitk::IntProperty::New(100)); node->SetProperty( "DoRefresh", mitk::BoolProperty::New( true ) ); } #endif // __mitkOdfVtkMapper2D_txx__ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkFiberBuilder.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkFiberBuilder.cpp index f5add08263..e9d3fdfb7b 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkFiberBuilder.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkFiberBuilder.cpp @@ -1,138 +1,138 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkFiberBuilder.h" using namespace mitk; FiberBuilder::FiberBuilder(ParticleGrid* grid, ItkFloatImageType* image) { m_Grid = grid; m_Image = image; m_FiberLength = 0; } FiberBuilder::~FiberBuilder() { } vtkSmartPointer FiberBuilder::iterate(int minFiberLength) { m_VtkCellArray = vtkSmartPointer::New(); m_VtkPoints = vtkSmartPointer::New(); int cur_label = 1; int numFibers = 0; m_FiberLength = 0; for (int k = 0; k < m_Grid->m_NumParticles;k++) { Particle *dp = m_Grid->GetParticle(k); if (dp->label == 0) { vtkSmartPointer container = vtkSmartPointer::New(); dp->label = cur_label; LabelPredecessors(dp, -1, container); LabelSuccessors(dp, 1, container); cur_label++; if(m_FiberLength >= minFiberLength) { m_VtkCellArray->InsertNextCell(container); numFibers++; } m_FiberLength = 0; } } for (int k = 0; k < m_Grid->m_NumParticles;k++) { Particle *dp = m_Grid->GetParticle(k); dp->label = 0; } vtkSmartPointer fiberPolyData = vtkSmartPointer::New(); fiberPolyData->SetPoints(m_VtkPoints); fiberPolyData->SetLines(m_VtkCellArray); return fiberPolyData; } void FiberBuilder::LabelPredecessors(Particle* p, int ep, vtkPolyLine* container) { Particle* p2 = NULL; if (ep==1) p2 = m_Grid->GetParticle(p->pID); else p2 = m_Grid->GetParticle(p->mID); if (p2!=NULL && p2->label==0) { p2->label = 1; // assign particle to current fiber if (p2->pID==p->ID) LabelPredecessors(p2, -1, container); else if (p2->mID==p->ID) LabelPredecessors(p2, 1, container); else std::cout << "FiberBuilder: connection inconsistent (LabelPredecessors)" << std::endl; } AddPoint(p, container); } void FiberBuilder::LabelSuccessors(Particle* p, int ep, vtkPolyLine* container) { AddPoint(p, container); Particle* p2 = NULL; if (ep==1) p2 = m_Grid->GetParticle(p->pID); else p2 = m_Grid->GetParticle(p->mID); if (p2!=NULL && p2->label==0) { p2->label = 1; // assign particle to current fiber if (p2->pID==p->ID) LabelSuccessors(p2, -1, container); else if (p2->mID==p->ID) LabelSuccessors(p2, 1, container); else std::cout << "FiberBuilder: connection inconsistent (LabelPredecessors)" << std::endl; } } void FiberBuilder::AddPoint(Particle *dp, vtkSmartPointer container) { if (dp->label!=1) return; dp->label = 2; itk::ContinuousIndex index; - index[0] = dp->pos[0]/m_Image->GetSpacing()[0]-0.5; - index[1] = dp->pos[1]/m_Image->GetSpacing()[1]-0.5; - index[2] = dp->pos[2]/m_Image->GetSpacing()[2]-0.5; + index[0] = dp->GetPos()[0]/m_Image->GetSpacing()[0]-0.5; + index[1] = dp->GetPos()[1]/m_Image->GetSpacing()[1]-0.5; + index[2] = dp->GetPos()[2]/m_Image->GetSpacing()[2]-0.5; itk::Point point; m_Image->TransformContinuousIndexToPhysicalPoint( index, point ); vtkIdType id = m_VtkPoints->InsertNextPoint(point.GetDataPointer()); container->GetPointIds()->InsertNextId(id); if(container->GetNumberOfPoints()>1) m_FiberLength += m_LastPoint.EuclideanDistanceTo(point); m_LastPoint = point; } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkGibbsEnergyComputer.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkGibbsEnergyComputer.cpp index 449a5f75fa..00790910ba 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkGibbsEnergyComputer.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkGibbsEnergyComputer.cpp @@ -1,213 +1,218 @@ #include #include #include #include #include #include using namespace mitk; GibbsEnergyComputer::GibbsEnergyComputer(ItkQBallImgType* qballImage, ItkFloatImageType* mask, ParticleGrid* particleGrid, SphereInterpolator* interpolator, ItkRandGenType* randGen) :EnergyComputer(mask, particleGrid, interpolator, randGen) { m_Image = qballImage; } +GibbsEnergyComputer::~GibbsEnergyComputer() +{ + +} + float GibbsEnergyComputer::EvaluateOdf(vnl_vector_fixed& pos, vnl_vector_fixed dir) { const int sampleSteps = 10; // evaluate ODF at 2*sampleSteps+1 positions along dir vnl_vector_fixed samplePos; // current position to evaluate float result = 0; // average of sampled ODF values int xint, yint, zint; // voxel containing samplePos // rotate particle direction according to image rotation dir = m_RotationMatrix*dir; // get interpolation for rotated direction m_SphereInterpolator->getInterpolation(dir); // sample ODF values along particle direction for (int i=-sampleSteps; i <= sampleSteps;i++) { samplePos = pos + (dir * m_ParticleLength) * ((float)i/sampleSteps); if (!m_UseTrilinearInterpolation) // image has not enough slices to use trilinear interpolation { ItkQBallImgType::IndexType index; index[0] = floor(pos[0]/m_Spacing[0]); index[1] = floor(pos[1]/m_Spacing[1]); index[2] = floor(pos[2]/m_Spacing[2]); if (m_Image->GetLargestPossibleRegion().IsInside(index)) { result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2]); } } else // use trilinear interpolation { float Rx = samplePos[0]/m_Spacing[0]-0.5; float Ry = samplePos[1]/m_Spacing[1]-0.5; float Rz = samplePos[2]/m_Spacing[2]-0.5; xint = floor(Rx); yint = floor(Ry); zint = floor(Rz); if (xint >= 0 && xint < m_Size[0]-1 && yint >= 0 && yint < m_Size[1]-1 && zint >= 0 && zint < m_Size[2]-1) { float xfrac = Rx-xint; float yfrac = Ry-yint; float zfrac = Rz-zint; ItkQBallImgType::IndexType index; float weight; weight = (1-xfrac)*(1-yfrac)*(1-zfrac); index[0] = xint; index[1] = yint; index[2] = zint; result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2])*weight; weight = (xfrac)*(1-yfrac)*(1-zfrac); index[0] = xint+1; index[1] = yint; index[2] = zint; result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2])*weight; weight = (1-xfrac)*(yfrac)*(1-zfrac); index[0] = xint; index[1] = yint+1; index[2] = zint; result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2])*weight; weight = (1-xfrac)*(1-yfrac)*(zfrac); index[0] = xint; index[1] = yint; index[2] = zint+1; result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2])*weight; weight = (xfrac)*(yfrac)*(1-zfrac); index[0] = xint+1; index[1] = yint+1; index[2] = zint; result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2])*weight; weight = (1-xfrac)*(yfrac)*(zfrac); index[0] = xint; index[1] = yint+1; index[2] = zint+1; result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2])*weight; weight = (xfrac)*(1-yfrac)*(zfrac); index[0] = xint+1; index[1] = yint; index[2] = zint+1; result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2])*weight; weight = (xfrac)*(yfrac)*(zfrac); index[0] = xint+1; index[1] = yint+1; index[2] = zint+1; result += (m_Image->GetPixel(index)[m_SphereInterpolator->idx[0]-1]*m_SphereInterpolator->interpw[0] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[1]-1]*m_SphereInterpolator->interpw[1] + m_Image->GetPixel(index)[m_SphereInterpolator->idx[2]-1]* m_SphereInterpolator->interpw[2])*weight; } } } result /= (2*sampleSteps+1); // average result over taken samples return result; } float GibbsEnergyComputer::ComputeExternalEnergy(vnl_vector_fixed &R, vnl_vector_fixed &N, Particle *dp) { if (SpatProb(R) == 0) // check if position is inside mask return itk::NumericTraits::NonpositiveMin(); float odfVal = EvaluateOdf(R, N); // evaluate ODF in given direction float modelVal = 0; m_ParticleGrid->ComputeNeighbors(R); // retrieve neighbouring particles from particle grid Particle* neighbour = m_ParticleGrid->GetNextNeighbor(); while (neighbour!=NULL) // iterate over nieghbouring particles { if (dp != neighbour) // don't evaluate against itself { // see Reisert et al. "Global Reconstruction of Neuronal Fibers", MICCAI 2009 - float dot = fabs(dot_product(N,neighbour->dir)); + float dot = fabs(dot_product(N,neighbour->GetDir())); float bw = mbesseli0(dot); - float dpos = (neighbour->pos-R).squared_magnitude(); + float dpos = (neighbour->GetPos()-R).squared_magnitude(); float w = mexp(dpos*gamma_s); modelVal += w*(bw+m_ParticleChemicalPotential); w = mexp(dpos*gamma_reg_s); } neighbour = m_ParticleGrid->GetNextNeighbor(); } float energy = 2*(odfVal/m_ParticleWeight-modelVal) - (mbesseli0(1.0)+m_ParticleChemicalPotential); return energy*m_ExtStrength; } float GibbsEnergyComputer::ComputeInternalEnergy(Particle *dp) { float energy = 0; if (dp->pID != -1) // has predecessor energy += ComputeInternalEnergyConnection(dp,+1); if (dp->mID != -1) // has successor energy += ComputeInternalEnergyConnection(dp,-1); return energy; } float GibbsEnergyComputer::ComputeInternalEnergyConnection(Particle *p1,int ep1) { Particle *p2 = 0; - int ep2; + int ep2 = 0; if (ep1 == 1) p2 = m_ParticleGrid->GetParticle(p1->pID); // get predecessor else p2 = m_ParticleGrid->GetParticle(p1->mID); // get successor // check in which direction the connected particle is pointing if (p2->mID == p1->ID) ep2 = -1; else if (p2->pID == p1->ID) ep2 = 1; else std::cout << "EnergyComputer: Connections are inconsistent!" << std::endl; return ComputeInternalEnergyConnection(p1,ep1,p2,ep2); } float GibbsEnergyComputer::ComputeInternalEnergyConnection(Particle *p1,int ep1, Particle *p2, int ep2) { // see Reisert et al. "Global Reconstruction of Neuronal Fibers", MICCAI 2009 - if ((dot_product(p1->dir,p2->dir))*ep1*ep2 > -m_CurvatureThreshold) // angle between particles is too sharp + if ((dot_product(p1->GetDir(),p2->GetDir()))*ep1*ep2 > -m_CurvatureThreshold) // angle between particles is too sharp return itk::NumericTraits::NonpositiveMin(); // calculate the endpoints of the two particles - vnl_vector_fixed endPoint1 = p1->pos + (p1->dir * (m_ParticleLength * ep1)); - vnl_vector_fixed endPoint2 = p2->pos + (p2->dir * (m_ParticleLength * ep2)); + vnl_vector_fixed endPoint1 = p1->GetPos() + (p1->GetDir() * (m_ParticleLength * ep1)); + vnl_vector_fixed endPoint2 = p2->GetPos() + (p2->GetDir() * (m_ParticleLength * ep2)); // check if endpoints are too far apart to connect if ((endPoint1-endPoint2).squared_magnitude() > m_SquaredParticleLength) return itk::NumericTraits::NonpositiveMin(); // calculate center point of the two particles - vnl_vector_fixed R = (p2->pos + p1->pos); R *= 0.5; + vnl_vector_fixed R = (p2->GetPos() + p1->GetPos()); R *= 0.5; // they are not allowed to connect if the mask image does not allow it if (SpatProb(R) == 0) return itk::NumericTraits::NonpositiveMin(); // get distances of endpoints to center point float norm1 = (endPoint1-R).squared_magnitude(); float norm2 = (endPoint2-R).squared_magnitude(); // calculate actual internal energy float energy = (m_ConnectionPotential-norm1-norm2)*m_IntStrength; return energy; -} \ No newline at end of file +} diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkGibbsEnergyComputer.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkGibbsEnergyComputer.h index db0335e4fb..1e4516f98f 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkGibbsEnergyComputer.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkGibbsEnergyComputer.h @@ -1,44 +1,46 @@ #ifndef GIBBSENERGYCOMPUTER_H #define GIBBSENERGYCOMPUTER_H #include #include #include #include #include #include "mitkEnergyComputer.h" using namespace mitk; /** * \brief ODF lookuptable based energy computer. */ class FiberTracking_EXPORT GibbsEnergyComputer : public EnergyComputer { public: typedef itk::Vector OdfVectorType; typedef itk::Image ItkQBallImgType; typedef itk::Image ItkFloatImageType; typedef itk::Statistics::MersenneTwisterRandomVariateGenerator ItkRandGenType; GibbsEnergyComputer(ItkQBallImgType* qballImage, ItkFloatImageType* mask, ParticleGrid* particleGrid, SphereInterpolator* interpolator, ItkRandGenType* randGen); + virtual ~GibbsEnergyComputer(); + // external energy calculation float ComputeExternalEnergy(vnl_vector_fixed& R, vnl_vector_fixed& N, Particle* dp); // internal energy calculation float ComputeInternalEnergyConnection(Particle *p1,int ep1); float ComputeInternalEnergyConnection(Particle *p1,int ep1, Particle *p2, int ep2); float ComputeInternalEnergy(Particle *dp); float EvaluateOdf(vnl_vector_fixed& pos, vnl_vector_fixed dir); protected: ItkQBallImgType* m_Image; }; #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkMetropolisHastingsSampler.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkMetropolisHastingsSampler.cpp index 0007ba3368..40b2058dfe 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkMetropolisHastingsSampler.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkMetropolisHastingsSampler.cpp @@ -1,478 +1,478 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkMetropolisHastingsSampler.h" using namespace mitk; MetropolisHastingsSampler::MetropolisHastingsSampler(ParticleGrid* grid, EnergyComputer* enComp, ItkRandGenType* randGen, float curvThres) - : m_AcceptedProposals(0) - , m_ExTemp(0.01) + : m_ExTemp(0.01) , m_BirthProb(0.25) , m_DeathProb(0.05) , m_ShiftProb(0.15) , m_OptShiftProb(0.1) , m_ConnectionProb(0.45) , m_TractProb(0.5) , m_DelProb(0.1) , m_ChempotParticle(0.0) + , m_AcceptedProposals(0) { m_RandGen = randGen; m_ParticleGrid = grid; m_EnergyComputer = enComp; m_ParticleLength = m_ParticleGrid->m_ParticleLength; m_DistanceThreshold = m_ParticleLength*m_ParticleLength; m_Sigma = m_ParticleLength/8.0; m_Gamma = 1/(m_Sigma*m_Sigma*2); m_Z = pow(2*M_PI*m_Sigma,3.0/2.0)*(M_PI*m_Sigma/m_ParticleLength); m_CurvatureThreshold = curvThres; m_StopProb = exp(-1/m_TractProb); } void MetropolisHastingsSampler::SetProbabilities(float birth, float death, float shift, float optShift, float connect) { m_BirthProb = birth; m_DeathProb = death; m_ShiftProb = shift; m_OptShiftProb = optShift; m_ConnectionProb = connect; float sum = m_BirthProb+m_DeathProb+m_ShiftProb+m_OptShiftProb+m_ConnectionProb; if (sum!=1 && sum>mitk::eps) { m_BirthProb /= sum; m_DeathProb /= sum; m_ShiftProb /= sum; m_OptShiftProb /= sum; m_ConnectionProb /= sum; } std::cout << "Update proposal probabilities:" << std::endl; std::cout << "Birth: " << m_BirthProb << std::endl; std::cout << "Death: " << m_DeathProb << std::endl; std::cout << "Shift: " << m_ShiftProb << std::endl; std::cout << "Optimal shift: " << m_OptShiftProb << std::endl; std::cout << "Connection: " << m_ConnectionProb << std::endl; } // update temperature of simulated annealing process void MetropolisHastingsSampler::SetTemperature(float val) { m_InTemp = val; m_Density = exp(-m_ChempotParticle/m_InTemp); } // add small random number drawn from gaussian to each vector element void MetropolisHastingsSampler::DistortVector(float sigma, vnl_vector_fixed& vec) { vec[0] += m_RandGen->GetNormalVariate(0.0, sigma); vec[1] += m_RandGen->GetNormalVariate(0.0, sigma); vec[2] += m_RandGen->GetNormalVariate(0.0, sigma); } // generate normalized random vector vnl_vector_fixed MetropolisHastingsSampler::GetRandomDirection() { vnl_vector_fixed vec; vec[0] = m_RandGen->GetNormalVariate(); vec[1] = m_RandGen->GetNormalVariate(); vec[2] = m_RandGen->GetNormalVariate(); vec.normalize(); return vec; } // generate actual proposal (birth, death, shift and connection of particle) void MetropolisHastingsSampler::MakeProposal() { float randnum = m_RandGen->GetVariate(); // Birth Proposal if (randnum < m_BirthProb) { vnl_vector_fixed R; m_EnergyComputer->DrawRandomPosition(R); vnl_vector_fixed N = GetRandomDirection(); Particle prop; - prop.pos = R; - prop.dir = N; + prop.GetPos() = R; + prop.GetDir() = N; float prob = m_Density * m_DeathProb /((m_BirthProb)*(m_ParticleGrid->m_NumParticles+1)); float ex_energy = m_EnergyComputer->ComputeExternalEnergy(R,N,0); float in_energy = m_EnergyComputer->ComputeInternalEnergy(&prop); prob *= exp((in_energy/m_InTemp+ex_energy/m_ExTemp)) ; if (prob > 1 || m_RandGen->GetVariate() < prob) { Particle *p = m_ParticleGrid->NewParticle(R); if (p!=0) { - p->pos = R; - p->dir = N; + p->GetPos() = R; + p->GetDir() = N; m_AcceptedProposals++; } } } // Death Proposal else if (randnum < m_BirthProb+m_DeathProb) { if (m_ParticleGrid->m_NumParticles > 0) { int pnum = m_RandGen->GetIntegerVariate()%m_ParticleGrid->m_NumParticles; Particle *dp = m_ParticleGrid->GetParticle(pnum); if (dp->pID == -1 && dp->mID == -1) { - float ex_energy = m_EnergyComputer->ComputeExternalEnergy(dp->pos,dp->dir,dp); + float ex_energy = m_EnergyComputer->ComputeExternalEnergy(dp->GetPos(),dp->GetDir(),dp); float in_energy = m_EnergyComputer->ComputeInternalEnergy(dp); float prob = m_ParticleGrid->m_NumParticles * (m_BirthProb) /(m_Density*m_DeathProb); //*SpatProb(dp->R); prob *= exp(-(in_energy/m_InTemp+ex_energy/m_ExTemp)) ; if (prob > 1 || m_RandGen->GetVariate() < prob) { m_ParticleGrid->RemoveParticle(pnum); m_AcceptedProposals++; } } } } // Shift Proposal else if (randnum < m_BirthProb+m_DeathProb+m_ShiftProb) { if (m_ParticleGrid->m_NumParticles > 0) { int pnum = m_RandGen->GetIntegerVariate()%m_ParticleGrid->m_NumParticles; Particle *p = m_ParticleGrid->GetParticle(pnum); Particle prop_p = *p; - DistortVector(m_Sigma, prop_p.pos); - DistortVector(m_Sigma/(2*m_ParticleLength), prop_p.dir); - prop_p.dir.normalize(); + DistortVector(m_Sigma, prop_p.GetPos()); + DistortVector(m_Sigma/(2*m_ParticleLength), prop_p.GetDir()); + prop_p.GetDir().normalize(); - float ex_energy = m_EnergyComputer->ComputeExternalEnergy(prop_p.pos,prop_p.dir,p) - - m_EnergyComputer->ComputeExternalEnergy(p->pos,p->dir,p); + float ex_energy = m_EnergyComputer->ComputeExternalEnergy(prop_p.GetPos(),prop_p.GetDir(),p) + - m_EnergyComputer->ComputeExternalEnergy(p->GetPos(),p->GetDir(),p); float in_energy = m_EnergyComputer->ComputeInternalEnergy(&prop_p) - m_EnergyComputer->ComputeInternalEnergy(p); float prob = exp(ex_energy/m_ExTemp+in_energy/m_InTemp); if (m_RandGen->GetVariate() < prob) { - vnl_vector_fixed Rtmp = p->pos; - vnl_vector_fixed Ntmp = p->dir; - p->pos = prop_p.pos; - p->dir = prop_p.dir; + vnl_vector_fixed Rtmp = p->GetPos(); + vnl_vector_fixed Ntmp = p->GetDir(); + p->GetPos() = prop_p.GetPos(); + p->GetDir() = prop_p.GetDir(); if (!m_ParticleGrid->TryUpdateGrid(pnum)) { - p->pos = Rtmp; - p->dir = Ntmp; + p->GetPos() = Rtmp; + p->GetDir() = Ntmp; } m_AcceptedProposals++; } } } // Optimal Shift Proposal else if (randnum < m_BirthProb+m_DeathProb+m_ShiftProb+m_OptShiftProb) { if (m_ParticleGrid->m_NumParticles > 0) { int pnum = m_RandGen->GetIntegerVariate()%m_ParticleGrid->m_NumParticles; Particle *p = m_ParticleGrid->GetParticle(pnum); bool no_proposal = false; Particle prop_p = *p; if (p->pID != -1 && p->mID != -1) { Particle *plus = m_ParticleGrid->GetParticle(p->pID); int ep_plus = (plus->pID == p->ID)? 1 : -1; Particle *minus = m_ParticleGrid->GetParticle(p->mID); int ep_minus = (minus->pID == p->ID)? 1 : -1; - prop_p.pos = (plus->pos + plus->dir * (m_ParticleLength * ep_plus) + minus->pos + minus->dir * (m_ParticleLength * ep_minus)); - prop_p.pos *= 0.5; - prop_p.dir = plus->pos - minus->pos; - prop_p.dir.normalize(); + prop_p.GetPos() = (plus->GetPos() + plus->GetDir() * (m_ParticleLength * ep_plus) + minus->GetPos() + minus->GetDir() * (m_ParticleLength * ep_minus)); + prop_p.GetPos() *= 0.5; + prop_p.GetDir() = plus->GetPos() - minus->GetPos(); + prop_p.GetDir().normalize(); } else if (p->pID != -1) { Particle *plus = m_ParticleGrid->GetParticle(p->pID); int ep_plus = (plus->pID == p->ID)? 1 : -1; - prop_p.pos = plus->pos + plus->dir * (m_ParticleLength * ep_plus * 2); - prop_p.dir = plus->dir; + prop_p.GetPos() = plus->GetPos() + plus->GetDir() * (m_ParticleLength * ep_plus * 2); + prop_p.GetDir() = plus->GetDir(); } else if (p->mID != -1) { Particle *minus = m_ParticleGrid->GetParticle(p->mID); int ep_minus = (minus->pID == p->ID)? 1 : -1; - prop_p.pos = minus->pos + minus->dir * (m_ParticleLength * ep_minus * 2); - prop_p.dir = minus->dir; + prop_p.GetPos() = minus->GetPos() + minus->GetDir() * (m_ParticleLength * ep_minus * 2); + prop_p.GetDir() = minus->GetDir(); } else no_proposal = true; if (!no_proposal) { - float cos = dot_product(prop_p.dir, p->dir); - float p_rev = exp(-((prop_p.pos-p->pos).squared_magnitude() + (1-cos*cos))*m_Gamma)/m_Z; + float cos = dot_product(prop_p.GetDir(), p->GetDir()); + float p_rev = exp(-((prop_p.GetPos()-p->GetPos()).squared_magnitude() + (1-cos*cos))*m_Gamma)/m_Z; - float ex_energy = m_EnergyComputer->ComputeExternalEnergy(prop_p.pos,prop_p.dir,p) - - m_EnergyComputer->ComputeExternalEnergy(p->pos,p->dir,p); + float ex_energy = m_EnergyComputer->ComputeExternalEnergy(prop_p.GetPos(),prop_p.GetDir(),p) + - m_EnergyComputer->ComputeExternalEnergy(p->GetPos(),p->GetDir(),p); float in_energy = m_EnergyComputer->ComputeInternalEnergy(&prop_p) - m_EnergyComputer->ComputeInternalEnergy(p); float prob = exp(ex_energy/m_ExTemp+in_energy/m_InTemp)*m_ShiftProb*p_rev/(m_OptShiftProb+m_ShiftProb*p_rev); if (m_RandGen->GetVariate() < prob) { - vnl_vector_fixed Rtmp = p->pos; - vnl_vector_fixed Ntmp = p->dir; - p->pos = prop_p.pos; - p->dir = prop_p.dir; + vnl_vector_fixed Rtmp = p->GetPos(); + vnl_vector_fixed Ntmp = p->GetDir(); + p->GetPos() = prop_p.GetPos(); + p->GetDir() = prop_p.GetDir(); if (!m_ParticleGrid->TryUpdateGrid(pnum)) { - p->pos = Rtmp; - p->dir = Ntmp; + p->GetPos() = Rtmp; + p->GetDir() = Ntmp; } m_AcceptedProposals++; } } } } else { if (m_ParticleGrid->m_NumParticles > 0) { int pnum = m_RandGen->GetIntegerVariate()%m_ParticleGrid->m_NumParticles; Particle *p = m_ParticleGrid->GetParticle(pnum); EndPoint P; P.p = p; P.ep = (m_RandGen->GetVariate() > 0.5)? 1 : -1; RemoveAndSaveTrack(P); if (m_BackupTrack.m_Probability != 0) { MakeTrackProposal(P); float prob = (m_ProposalTrack.m_Energy-m_BackupTrack.m_Energy)/m_InTemp ; prob = exp(prob)*(m_BackupTrack.m_Probability * pow(m_DelProb,m_ProposalTrack.m_Length)) /(m_ProposalTrack.m_Probability * pow(m_DelProb,m_BackupTrack.m_Length)); if (m_RandGen->GetVariate() < prob) { ImplementTrack(m_ProposalTrack); m_AcceptedProposals++; } else { ImplementTrack(m_BackupTrack); } } else ImplementTrack(m_BackupTrack); } } } // establish connections between particles stored in input Track void MetropolisHastingsSampler::ImplementTrack(Track &T) { for (int k = 1; k < T.m_Length;k++) m_ParticleGrid->CreateConnection(T.track[k-1].p,T.track[k-1].ep,T.track[k].p,-T.track[k].ep); } // remove pending track from random particle, save it in m_BackupTrack and calculate its probability void MetropolisHastingsSampler::RemoveAndSaveTrack(EndPoint P) { EndPoint Current = P; int cnt = 0; float energy = 0; float AccumProb = 1.0; m_BackupTrack.track[cnt] = Current; EndPoint Next; for (;;) { Next.p = 0; if (Current.ep == 1) { if (Current.p->pID != -1) { Next.p = m_ParticleGrid->GetParticle(Current.p->pID); Current.p->pID = -1; m_ParticleGrid->m_NumConnections--; } } else if (Current.ep == -1) { if (Current.p->mID != -1) { Next.p = m_ParticleGrid->GetParticle(Current.p->mID); Current.p->mID = -1; m_ParticleGrid->m_NumConnections--; } } else { fprintf(stderr,"MetropolisHastingsSampler_randshift: Connection inconsistent 3\n"); break; } if (Next.p == 0) // no successor { Next.ep = 0; // mark as empty successor break; } else { if (Next.p->pID == Current.p->ID) { Next.p->pID = -1; Next.ep = 1; } else if (Next.p->mID == Current.p->ID) { Next.p->mID = -1; Next.ep = -1; } else { fprintf(stderr,"MetropolisHastingsSampler_randshift: Connection inconsistent 4\n"); break; } } ComputeEndPointProposalDistribution(Current); AccumProb *= (m_SimpSamp.probFor(Next)); if (Next.p == 0) // no successor -> break break; energy += m_EnergyComputer->ComputeInternalEnergyConnection(Current.p,Current.ep,Next.p,Next.ep); Current = Next; Current.ep *= -1; cnt++; m_BackupTrack.track[cnt] = Current; if (m_RandGen->GetVariate() > m_DelProb) break; } m_BackupTrack.m_Energy = energy; m_BackupTrack.m_Probability = AccumProb; m_BackupTrack.m_Length = cnt+1; } // generate new track using kind of a local tracking starting from P in the given direction, store it in m_ProposalTrack and calculate its probability void MetropolisHastingsSampler::MakeTrackProposal(EndPoint P) { EndPoint Current = P; int cnt = 0; float energy = 0; float AccumProb = 1.0; m_ProposalTrack.track[cnt++] = Current; Current.p->label = 1; for (;;) { // next candidate is already connected if ((Current.ep == 1 && Current.p->pID != -1) || (Current.ep == -1 && Current.p->mID != -1)) break; // track too long // if (cnt > 250) // break; ComputeEndPointProposalDistribution(Current); int k = m_SimpSamp.draw(m_RandGen->GetVariate()); // stop tracking proposed if (k==0) break; EndPoint Next = m_SimpSamp.objs[k]; float probability = m_SimpSamp.probFor(k); // accumulate energy and proposal distribution energy += m_EnergyComputer->ComputeInternalEnergyConnection(Current.p,Current.ep,Next.p,Next.ep); AccumProb *= probability; // track to next endpoint Current = Next; Current.ep *= -1; Current.p->label = 1; // put label to avoid loops m_ProposalTrack.track[cnt++] = Current; } m_ProposalTrack.m_Energy = energy; m_ProposalTrack.m_Probability = AccumProb; m_ProposalTrack.m_Length = cnt; // clear labels for (int j = 0; j < m_ProposalTrack.m_Length;j++) m_ProposalTrack.track[j].p->label = 0; } // get neigbouring particles of P and calculate the according connection probabilities void MetropolisHastingsSampler::ComputeEndPointProposalDistribution(EndPoint P) { Particle *p = P.p; int ep = P.ep; float dist,dot; - vnl_vector_fixed R = p->pos + (p->dir * (ep*m_ParticleLength) ); + vnl_vector_fixed R = p->GetPos() + (p->GetDir() * (ep*m_ParticleLength) ); m_ParticleGrid->ComputeNeighbors(R); m_SimpSamp.clear(); m_SimpSamp.add(m_StopProb,EndPoint(0,0)); for (;;) { Particle *p2 = m_ParticleGrid->GetNextNeighbor(); if (p2 == 0) break; if (p!=p2 && p2->label == 0) { if (p2->mID == -1) { - dist = (p2->pos - p2->dir * m_ParticleLength - R).squared_magnitude(); + dist = (p2->GetPos() - p2->GetDir() * m_ParticleLength - R).squared_magnitude(); if (dist < m_DistanceThreshold) { - dot = dot_product(p2->dir,p->dir) * ep; + dot = dot_product(p2->GetDir(),p->GetDir()) * ep; if (dot > m_CurvatureThreshold) { float en = m_EnergyComputer->ComputeInternalEnergyConnection(p,ep,p2,-1); m_SimpSamp.add(exp(en/m_TractProb),EndPoint(p2,-1)); } } } if (p2->pID == -1) { - dist = (p2->pos + p2->dir * m_ParticleLength - R).squared_magnitude(); + dist = (p2->GetPos() + p2->GetDir() * m_ParticleLength - R).squared_magnitude(); if (dist < m_DistanceThreshold) { - dot = dot_product(p2->dir,p->dir) * (-ep); + dot = dot_product(p2->GetDir(),p->GetDir()) * (-ep); if (dot > m_CurvatureThreshold) { float en = m_EnergyComputer->ComputeInternalEnergyConnection(p,ep,p2,+1); m_SimpSamp.add(exp(en/m_TractProb),EndPoint(p2,+1)); } } } } } } // return number of accepted proposals int MetropolisHastingsSampler::GetNumAcceptedProposals() { return m_AcceptedProposals; } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkParticle.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkParticle.h index 141c38b20a..03cb4c09db 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkParticle.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkParticle.h @@ -1,76 +1,94 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _PARTICLE #define _PARTICLE #include #include + namespace mitk { /** * \brief A particle is the basic element of the Gibbs fiber tractography method. */ class FiberTracking_EXPORT Particle { public: Particle() { label = 0; pID = -1; mID = -1; } ~Particle() { } - vnl_vector_fixed pos; // particle position (world coordinates. corner based voxels. not accounted for image rotation. - vnl_vector_fixed dir; // normalized direction vector - int gridindex; // index in the grid where it is living int ID; // particle ID int pID; // successor ID int mID; // predecessor ID unsigned char label; // label used in the fiber building process + + vnl_vector_fixed& GetPos() + { + return pos; + } + + vnl_vector_fixed& GetDir() + { + return dir; + } + +private: +#pragma warning(push) +#pragma warning(disable: 4251) + // this pragma ignores the following warning: + // warning C4251: 'mitk::Particle::pos' : class 'ATL::CStringT' needs to have dll-interface to be used by clients of class 'Particle' + vnl_vector_fixed pos; // particle position (world coordinates. corner based voxels. not accounted for image rotation. + vnl_vector_fixed dir; // normalized direction vector +#pragma warning(pop) + }; class FiberTracking_EXPORT EndPoint { public: EndPoint() {} EndPoint(Particle *p,int ep) { this->p = p; this->ep = ep; } Particle *p; int ep; inline bool operator==(EndPoint P) { return (P.p == p) && (P.ep == ep); } }; } #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkParticleGrid.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkParticleGrid.cpp index 4fcbe4ae49..e3ef96efe2 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkParticleGrid.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/GibbsTracking/mitkParticleGrid.cpp @@ -1,420 +1,420 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkParticleGrid.h" #include #include using namespace mitk; ParticleGrid::ParticleGrid(ItkFloatImageType* image, float particleLength, int cellCapacity) { // initialize counters m_NumParticles = 0; m_NumConnections = 0; m_NumCellOverflows = 0; m_ParticleLength = particleLength; // define isotropic grid from voxel spacing and particle length float cellSize = 2*m_ParticleLength; m_GridSize[0] = image->GetLargestPossibleRegion().GetSize()[0]*image->GetSpacing()[0]/cellSize +1; m_GridSize[1] = image->GetLargestPossibleRegion().GetSize()[1]*image->GetSpacing()[1]/cellSize +1; m_GridSize[2] = image->GetLargestPossibleRegion().GetSize()[2]*image->GetSpacing()[2]/cellSize +1; m_GridScale[0] = 1/cellSize; m_GridScale[1] = 1/cellSize; m_GridScale[2] = 1/cellSize; m_CellCapacity = cellCapacity; // maximum number of particles per grid cell m_ContainerCapacity = 100000; // initial particle container capacity unsigned long numCells = m_GridSize[0]*m_GridSize[1]*m_GridSize[2]; // number of grid cells unsigned long gridSize = numCells*m_CellCapacity; - if ( itk::NumericTraits::max()::max() R) { if (m_NumParticles >= m_ContainerCapacity) { if (!ReallocateGrid()) return NULL; } int xint = int(R[0]*m_GridScale[0]); if (xint < 0) return NULL; if (xint >= m_GridSize[0]) return NULL; int yint = int(R[1]*m_GridScale[1]); if (yint < 0) return NULL; if (yint >= m_GridSize[1]) return NULL; int zint = int(R[2]*m_GridScale[2]); if (zint < 0) return NULL; if (zint >= m_GridSize[2]) return NULL; int idx = xint + m_GridSize[0]*(yint + m_GridSize[1]*zint); if (m_OccupationCount[idx] < m_CellCapacity) { Particle *p = &(m_Particles[m_NumParticles]); - p->pos = R; + p->GetPos() = R; p->mID = -1; p->pID = -1; m_NumParticles++; p->gridindex = m_CellCapacity*idx + m_OccupationCount[idx]; m_Grid[p->gridindex] = p; m_OccupationCount[idx]++; return p; } else { m_NumCellOverflows++; return NULL; } } bool ParticleGrid::TryUpdateGrid(int k) { Particle* p = &(m_Particles[k]); - int xint = int(p->pos[0]*m_GridScale[0]); + int xint = int(p->GetPos()[0]*m_GridScale[0]); if (xint < 0) return false; if (xint >= m_GridSize[0]) return false; - int yint = int(p->pos[1]*m_GridScale[1]); + int yint = int(p->GetPos()[1]*m_GridScale[1]); if (yint < 0) return false; if (yint >= m_GridSize[1]) return false; - int zint = int(p->pos[2]*m_GridScale[2]); + int zint = int(p->GetPos()[2]*m_GridScale[2]); if (zint < 0) return false; if (zint >= m_GridSize[2]) return false; int idx = xint + m_GridSize[0]*(yint+ zint*m_GridSize[1]); int cellidx = p->gridindex/m_CellCapacity; if (idx != cellidx) // cell has changed { if (m_OccupationCount[idx] < m_CellCapacity) { // remove from old position in grid; int grdindex = p->gridindex; m_Grid[grdindex] = m_Grid[cellidx*m_CellCapacity + m_OccupationCount[cellidx]-1]; m_Grid[grdindex]->gridindex = grdindex; m_OccupationCount[cellidx]--; // insert at new position in grid p->gridindex = idx*m_CellCapacity + m_OccupationCount[idx]; m_Grid[p->gridindex] = p; m_OccupationCount[idx]++; return true; } else { m_NumCellOverflows++; return false; } } return true; } void ParticleGrid::RemoveParticle(int k) { Particle* p = &(m_Particles[k]); int gridIndex = p->gridindex; int cellIdx = gridIndex/m_CellCapacity; int idx = gridIndex%m_CellCapacity; // remove pending connections if (p->mID != -1) DestroyConnection(p,-1); if (p->pID != -1) DestroyConnection(p,+1); // remove from grid if (idx < m_OccupationCount[cellIdx]-1) { m_Grid[gridIndex] = m_Grid[cellIdx*m_CellCapacity+m_OccupationCount[cellIdx]-1]; m_Grid[cellIdx*m_CellCapacity+m_OccupationCount[cellIdx]-1] = NULL; m_Grid[gridIndex]->gridindex = gridIndex; } m_OccupationCount[cellIdx]--; // remove from container if (k < m_NumParticles-1) { Particle* last = &m_Particles[m_NumParticles-1]; // last particle // update connections of last particle because its index is changing if (last->mID!=-1) { if ( m_Particles[last->mID].mID == m_NumParticles-1 ) m_Particles[last->mID].mID = k; else if ( m_Particles[last->mID].pID == m_NumParticles-1 ) m_Particles[last->mID].pID = k; } if (last->pID!=-1) { if ( m_Particles[last->pID].mID == m_NumParticles-1 ) m_Particles[last->pID].mID = k; else if ( m_Particles[last->pID].pID == m_NumParticles-1 ) m_Particles[last->pID].pID = k; } m_Particles[k] = m_Particles[m_NumParticles-1]; // move very last particle to empty slot m_Particles[m_NumParticles-1].ID = m_NumParticles-1; // update ID of removed particle to match the index m_Particles[k].ID = k; // update ID of moved particle m_Grid[m_Particles[k].gridindex] = &m_Particles[k]; // update address of moved particle } m_NumParticles--; } void ParticleGrid::ComputeNeighbors(vnl_vector_fixed &R) { float xfrac = R[0]*m_GridScale[0]; float yfrac = R[1]*m_GridScale[1]; float zfrac = R[2]*m_GridScale[2]; int xint = int(xfrac); int yint = int(yfrac); int zint = int(zfrac); int dx = -1; if (xfrac-xint > 0.5) dx = 1; if (xint <= 0) { xint = 0; dx = 1; } if (xint >= m_GridSize[0]-1) { xint = m_GridSize[0]-1; dx = -1; } if (m_GridSize[0] <= 1) { dx = 0; } // Necessary with 2d images (bug 15416) int dy = -1; if (yfrac-yint > 0.5) dy = 1; if (yint <= 0) {yint = 0; dy = 1; } if (yint >= m_GridSize[1]-1) {yint = m_GridSize[1]-1; dy = -1;} if (m_GridSize[1] <= 1) { dy = 0; } // Necessary with 2d images (bug 15416) int dz = -1; if (zfrac-zint > 0.5) dz = 1; if (zint <= 0) {zint = 0; dz = 1; } if (zint >= m_GridSize[2]-1) {zint = m_GridSize[2]-1; dz = -1;} if (m_GridSize[2] <= 1) { dz = 0; } // Necessary with 2d images (bug 15416) m_NeighbourTracker.cellidx[0] = xint + m_GridSize[0]*(yint+zint*m_GridSize[1]); m_NeighbourTracker.cellidx[1] = m_NeighbourTracker.cellidx[0] + dx; m_NeighbourTracker.cellidx[2] = m_NeighbourTracker.cellidx[1] + dy*m_GridSize[0]; m_NeighbourTracker.cellidx[3] = m_NeighbourTracker.cellidx[2] - dx; m_NeighbourTracker.cellidx[4] = m_NeighbourTracker.cellidx[0] + dz*m_GridSize[0]*m_GridSize[1]; m_NeighbourTracker.cellidx[5] = m_NeighbourTracker.cellidx[4] + dx; m_NeighbourTracker.cellidx[6] = m_NeighbourTracker.cellidx[5] + dy*m_GridSize[0]; m_NeighbourTracker.cellidx[7] = m_NeighbourTracker.cellidx[6] - dx; m_NeighbourTracker.cellidx_c[0] = m_CellCapacity*m_NeighbourTracker.cellidx[0]; m_NeighbourTracker.cellidx_c[1] = m_CellCapacity*m_NeighbourTracker.cellidx[1]; m_NeighbourTracker.cellidx_c[2] = m_CellCapacity*m_NeighbourTracker.cellidx[2]; m_NeighbourTracker.cellidx_c[3] = m_CellCapacity*m_NeighbourTracker.cellidx[3]; m_NeighbourTracker.cellidx_c[4] = m_CellCapacity*m_NeighbourTracker.cellidx[4]; m_NeighbourTracker.cellidx_c[5] = m_CellCapacity*m_NeighbourTracker.cellidx[5]; m_NeighbourTracker.cellidx_c[6] = m_CellCapacity*m_NeighbourTracker.cellidx[6]; m_NeighbourTracker.cellidx_c[7] = m_CellCapacity*m_NeighbourTracker.cellidx[7]; m_NeighbourTracker.cellcnt = 0; m_NeighbourTracker.pcnt = 0; } Particle* ParticleGrid::GetNextNeighbor() { if (m_NeighbourTracker.pcnt < m_OccupationCount[m_NeighbourTracker.cellidx[m_NeighbourTracker.cellcnt]]) { return m_Grid[m_NeighbourTracker.cellidx_c[m_NeighbourTracker.cellcnt] + (m_NeighbourTracker.pcnt++)]; } else { for(;;) { m_NeighbourTracker.cellcnt++; if (m_NeighbourTracker.cellcnt >= 8) return 0; if (m_OccupationCount[m_NeighbourTracker.cellidx[m_NeighbourTracker.cellcnt]] > 0) break; } m_NeighbourTracker.pcnt = 1; return m_Grid[m_NeighbourTracker.cellidx_c[m_NeighbourTracker.cellcnt]]; } } void ParticleGrid::CreateConnection(Particle *P1,int ep1, Particle *P2, int ep2) { if (ep1 == -1) P1->mID = P2->ID; else P1->pID = P2->ID; if (ep2 == -1) P2->mID = P1->ID; else P2->pID = P1->ID; m_NumConnections++; } void ParticleGrid::DestroyConnection(Particle *P1,int ep1, Particle *P2, int ep2) { if (ep1 == -1) P1->mID = -1; else P1->pID = -1; if (ep2 == -1) P2->mID = -1; else P2->pID = -1; m_NumConnections--; } void ParticleGrid::DestroyConnection(Particle *P1,int ep1) { Particle *P2 = 0; if (ep1 == 1) { P2 = &m_Particles[P1->pID]; P1->pID = -1; } else { P2 = &m_Particles[P1->mID]; P1->mID = -1; } if (P2->mID == P1->ID) P2->mID = -1; else P2->pID = -1; m_NumConnections--; } bool ParticleGrid::CheckConsistency() { for (int i=0; iID != i) { std::cout << "Particle ID error!" << std::endl; return false; } if (p->mID!=-1) { Particle* p2 = &m_Particles[p->mID]; if (p2->mID!=p->ID && p2->pID!=p->ID) { std::cout << "Connection inconsistent!" << std::endl; return false; } } if (p->pID!=-1) { Particle* p2 = &m_Particles[p->pID]; if (p2->mID!=p->ID && p2->pID!=p->ID) { std::cout << "Connection inconsistent!" << std::endl; return false; } } } return true; } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkAddArtifactsToDwiImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkAddArtifactsToDwiImageFilter.cpp index 980796961a..80d1b97949 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkAddArtifactsToDwiImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkAddArtifactsToDwiImageFilter.cpp @@ -1,349 +1,349 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkAddArtifactsToDwiImageFilter_txx #define __itkAddArtifactsToDwiImageFilter_txx #include #include #include #include "itkAddArtifactsToDwiImageFilter.h" #include #include #include #include #include #include #include #define _USE_MATH_DEFINES #include namespace itk { template< class TPixelType > AddArtifactsToDwiImageFilter< TPixelType > ::AddArtifactsToDwiImageFilter() : m_NoiseModel(NULL) , m_FrequencyMap(NULL) , m_kOffset(0) , m_tLine(1) - , m_EddyGradientStrength(0.0) , m_SimulateEddyCurrents(false) + , m_EddyGradientStrength(0.0) , m_TE(100) , m_AddGibbsRinging(false) , m_Spikes(0) , m_SpikeAmplitude(1) , m_Wrap(1.0) , m_UseConstantRandSeed(false) { this->SetNumberOfRequiredInputs( 1 ); m_RandGen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); m_RandGen->SetSeed(); } template< class TPixelType > void AddArtifactsToDwiImageFilter< TPixelType > ::GenerateData() { if (m_UseConstantRandSeed) // always generate the same random numbers? m_RandGen->SetSeed(0); else m_RandGen->SetSeed(); m_StartTime = clock(); m_StatusText = "Starting simulation\n"; typename DiffusionImageType::Pointer inputImage = static_cast< DiffusionImageType * >( this->ProcessObject::GetInput(0) ); itk::ImageRegion<3> inputRegion = inputImage->GetLargestPossibleRegion(); typename itk::ImageDuplicator::Pointer duplicator = itk::ImageDuplicator::New(); duplicator->SetInputImage( inputImage ); duplicator->Update(); typename DiffusionImageType::Pointer outputImage = duplicator->GetOutput(); // is input slize size even? int xMax=inputRegion.GetSize(0); int yMax=inputRegion.GetSize(1); if ( xMax%2 == 1 ) xMax += 1; if ( yMax%2 == 1 ) yMax += 1; // create slice object typename SliceType::Pointer slice = SliceType::New(); ImageRegion<2> sliceRegion; sliceRegion.SetSize(0, xMax); sliceRegion.SetSize(1, yMax); slice->SetLargestPossibleRegion( sliceRegion ); slice->SetBufferedRegion( sliceRegion ); slice->SetRequestedRegion( sliceRegion ); slice->Allocate(); slice->FillBuffer(0.0); ImageRegion<2> upsampledSliceRegion; if (m_AddGibbsRinging) { upsampledSliceRegion.SetSize(0, xMax*2); upsampledSliceRegion.SetSize(1, yMax*2); } // frequency map slice typename SliceType::Pointer fMap = NULL; if (m_FrequencyMap.IsNotNull()) { fMap = SliceType::New(); fMap->SetLargestPossibleRegion( sliceRegion ); fMap->SetBufferedRegion( sliceRegion ); fMap->SetRequestedRegion( sliceRegion ); fMap->Allocate(); fMap->FillBuffer(0.0); } if (m_Spikes>0 || m_FrequencyMap.IsNotNull() || m_kOffset>0.0 || m_AddGibbsRinging || m_SimulateEddyCurrents || m_Wrap<1.0) { ImageRegion<3> croppedRegion = inputRegion; croppedRegion.SetSize(1, croppedRegion.GetSize(1)*m_Wrap); itk::Point shiftedOrigin = inputImage->GetOrigin(); shiftedOrigin[1] += (inputRegion.GetSize(1)-croppedRegion.GetSize(1))*inputImage->GetSpacing()[1]/2; outputImage = DiffusionImageType::New(); outputImage->SetSpacing( inputImage->GetSpacing() ); outputImage->SetOrigin( shiftedOrigin ); outputImage->SetDirection( inputImage->GetDirection() ); outputImage->SetLargestPossibleRegion( croppedRegion ); outputImage->SetBufferedRegion( croppedRegion ); outputImage->SetRequestedRegion( croppedRegion ); outputImage->SetVectorLength( inputImage->GetVectorLength() ); outputImage->Allocate(); typename DiffusionImageType::PixelType temp; temp.SetSize(inputImage->GetVectorLength()); temp.Fill(0.0); outputImage->FillBuffer(temp); int tempY=croppedRegion.GetSize(1); tempY += tempY%2; croppedRegion.SetSize(1, tempY); MatrixType transform = inputImage->GetDirection(); for (int i=0; i<3; i++) for (int j=0; j<3; j++) transform[i][j] *= inputImage->GetSpacing()[j]; m_StatusText += this->GetTime()+" > Adjusting complex signal\n"; if (m_FrequencyMap.IsNotNull()) m_StatusText += "Simulating distortions\n"; if (m_AddGibbsRinging) m_StatusText += "Simulating ringing artifacts\n"; if (m_SimulateEddyCurrents) m_StatusText += "Simulating eddy currents\n"; if (m_Spikes>0) m_StatusText += "Simulating spikes\n"; if (m_Wrap<1.0) m_StatusText += "Simulating aliasing artifacts\n"; if (m_kOffset>0) m_StatusText += "Simulating ghosts\n"; - std::vector< int > spikeVolume; + std::vector< unsigned int > spikeVolume; for (int i=0; iGetIntegerVariate()%inputImage->GetVectorLength()); std::sort (spikeVolume.begin(), spikeVolume.end()); std::reverse (spikeVolume.begin(), spikeVolume.end()); m_StatusText += "0% 10 20 30 40 50 60 70 80 90 100%\n"; m_StatusText += "|----|----|----|----|----|----|----|----|----|----|\n*"; unsigned long lastTick = 0; boost::progress_display disp(inputImage->GetVectorLength()*inputRegion.GetSize(2)); for (unsigned int g=0; gGetVectorLength(); g++) { - std::vector< int > spikeSlice; + std::vector< unsigned int > spikeSlice; while (!spikeVolume.empty() && spikeVolume.back()==g) { spikeSlice.push_back(m_RandGen->GetIntegerVariate()%inputImage->GetLargestPossibleRegion().GetSize(2)); spikeVolume.pop_back(); } std::sort (spikeSlice.begin(), spikeSlice.end()); std::reverse (spikeSlice.begin(), spikeSlice.end()); for (unsigned int z=0; zGetAbortGenerateData()) { m_StatusText += "\n"+this->GetTime()+" > Simulation aborted\n"; return; } std::vector< SliceType::Pointer > compartmentSlices; // extract slice from channel g for (unsigned int y=0; yGetPixel(index3D)[g]; slice->SetPixel(index2D, pix2D); if (fMap.IsNotNull()) fMap->SetPixel(index2D, m_FrequencyMap->GetPixel(index3D)); } if (m_AddGibbsRinging) { itk::ResampleImageFilter::Pointer resampler = itk::ResampleImageFilter::New(); resampler->SetInput(slice); resampler->SetOutputParametersFromImage(slice); resampler->SetSize(upsampledSliceRegion.GetSize()); resampler->SetOutputSpacing(slice->GetSpacing()/2); resampler->Update(); typename SliceType::Pointer upslice = resampler->GetOutput(); compartmentSlices.push_back(upslice); if (fMap.IsNotNull()) { itk::ResampleImageFilter::Pointer resampler = itk::ResampleImageFilter::New(); resampler->SetInput(fMap); resampler->SetOutputParametersFromImage(fMap); resampler->SetSize(upsampledSliceRegion.GetSize()); resampler->SetOutputSpacing(fMap->GetSpacing()/2); resampler->Update(); fMap = resampler->GetOutput(); } } else compartmentSlices.push_back(slice); // fourier transform slice typename ComplexSliceType::Pointer fSlice; itk::Size<2> outSize; outSize.SetElement(0, xMax); outSize.SetElement(1, croppedRegion.GetSize()[1]); typename itk::KspaceImageFilter< SliceType::PixelType >::Pointer idft = itk::KspaceImageFilter< SliceType::PixelType >::New(); idft->SetUseConstantRandSeed(m_UseConstantRandSeed); idft->SetCompartmentImages(compartmentSlices); idft->SetkOffset(m_kOffset); idft->SettLine(m_tLine); idft->SetSimulateRelaxation(false); idft->SetFrequencyMap(fMap); idft->SetDiffusionGradientDirection(m_GradientList.at(g)); idft->SetSimulateEddyCurrents(m_SimulateEddyCurrents); idft->SetEddyGradientMagnitude(m_EddyGradientStrength); idft->SetTE(m_TE); idft->SetZ((double)z-(double)inputRegion.GetSize(2)/2.0); idft->SetDirectionMatrix(transform); idft->SetOutSize(outSize); int numSpikes = 0; while (!spikeSlice.empty() && spikeSlice.back()==z) { numSpikes++; spikeSlice.pop_back(); } idft->SetSpikes(numSpikes); idft->SetSpikeAmplitude(m_SpikeAmplitude); idft->Update(); fSlice = idft->GetOutput(); // inverse fourier transform slice typename SliceType::Pointer newSlice; typename itk::DftImageFilter< SliceType::PixelType >::Pointer dft = itk::DftImageFilter< SliceType::PixelType >::New(); dft->SetInput(fSlice); dft->Update(); newSlice = dft->GetOutput(); // put slice back into channel g for (unsigned int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (unsigned int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { typename DiffusionImageType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; typename DiffusionImageType::PixelType pix3D = outputImage->GetPixel(index3D); typename SliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; double signal = newSlice->GetPixel(index2D); if (signal>0) signal = floor(signal+0.5); else signal = ceil(signal-0.5); pix3D[g] = signal; outputImage->SetPixel(index3D, pix3D); } ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned int tick = 0; tick<(newTick-lastTick); tick++) m_StatusText += "*"; lastTick = newTick; } } m_StatusText += "\n\n"; } if (m_NoiseModel!=NULL) { m_StatusText += this->GetTime()+" > Adding noise\n"; m_StatusText += "0% 10 20 30 40 50 60 70 80 90 100%\n"; m_StatusText += "|----|----|----|----|----|----|----|----|----|----|\n*"; unsigned long lastTick = 0; ImageRegionIterator it1 (outputImage, outputImage->GetLargestPossibleRegion()); boost::progress_display disp(outputImage->GetLargestPossibleRegion().GetNumberOfPixels()); while(!it1.IsAtEnd()) { if (this->GetAbortGenerateData()) { m_StatusText += "\n"+this->GetTime()+" > Simulation aborted\n"; return; } ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned int tick = 0; tick<(newTick-lastTick); tick++) m_StatusText += "*"; lastTick = newTick; typename DiffusionImageType::PixelType signal = it1.Get(); m_NoiseModel->AddNoise(signal); it1.Set(signal); ++it1; } m_StatusText += "\n\n"; } this->SetNthOutput(0, outputImage); m_StatusText += "Finished simulation\n"; m_StatusText += "Simulation time: "+GetTime(); } template< class TPixelType > std::string AddArtifactsToDwiImageFilter< TPixelType >::GetTime() { unsigned long total = (double)(clock() - m_StartTime)/CLOCKS_PER_SEC; unsigned long hours = total/3600; unsigned long minutes = (total%3600)/60; unsigned long seconds = total%60; std::string out = ""; out.append(boost::lexical_cast(hours)); out.append(":"); out.append(boost::lexical_cast(minutes)); out.append(":"); out.append(boost::lexical_cast(seconds)); return out; } } #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkEvaluateDirectionImagesFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkEvaluateDirectionImagesFilter.cpp index 28603a7c36..56d48bbb46 100755 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkEvaluateDirectionImagesFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkEvaluateDirectionImagesFilter.cpp @@ -1,363 +1,363 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkEvaluateDirectionImagesFilter_cpp #define __itkEvaluateDirectionImagesFilter_cpp #include "itkEvaluateDirectionImagesFilter.h" #include #include #include #include #define _USE_MATH_DEFINES #include namespace itk { template< class PixelType > EvaluateDirectionImagesFilter< PixelType > ::EvaluateDirectionImagesFilter(): m_ImageSet(NULL), m_ReferenceImageSet(NULL), m_IgnoreMissingDirections(false), m_Eps(0.0001) { this->SetNumberOfIndexedOutputs(2); } template< class PixelType > void EvaluateDirectionImagesFilter< PixelType >::GenerateData() { if (m_ImageSet.IsNull() || m_ReferenceImageSet.IsNull()) return; DirectionImageContainerType::Pointer set1 = DirectionImageContainerType::New(); DirectionImageContainerType::Pointer set2 = DirectionImageContainerType::New(); - for (int i=0; iSize(); i++) + for (unsigned int i=0; iSize(); i++) { typename itk::ImageDuplicator< DirectionImageType >::Pointer duplicator = itk::ImageDuplicator< DirectionImageType >::New(); duplicator->SetInputImage( m_ImageSet->GetElement(i) ); duplicator->Update(); set1->InsertElement(i, dynamic_cast(duplicator->GetOutput())); } - for (int i=0; iSize(); i++) + for (unsigned int i=0; iSize(); i++) { typename itk::ImageDuplicator< DirectionImageType >::Pointer duplicator = itk::ImageDuplicator< DirectionImageType >::New(); duplicator->SetInputImage( m_ReferenceImageSet->GetElement(i) ); duplicator->Update(); set2->InsertElement(i, dynamic_cast(duplicator->GetOutput())); } m_ImageSet = set1; m_ReferenceImageSet = set2; // angular error image typename OutputImageType::Pointer outputImage = OutputImageType::New(); outputImage->SetOrigin( m_ReferenceImageSet->GetElement(0)->GetOrigin() ); outputImage->SetRegions( m_ReferenceImageSet->GetElement(0)->GetLargestPossibleRegion() ); outputImage->SetSpacing( m_ReferenceImageSet->GetElement(0)->GetSpacing() ); outputImage->SetDirection( m_ReferenceImageSet->GetElement(0)->GetDirection() ); outputImage->Allocate(); outputImage->FillBuffer(0.0); this->SetNthOutput(0, outputImage); // length error image outputImage = OutputImageType::New(); outputImage->SetOrigin( m_ReferenceImageSet->GetElement(0)->GetOrigin() ); outputImage->SetRegions( m_ReferenceImageSet->GetElement(0)->GetLargestPossibleRegion() ); outputImage->SetSpacing( m_ReferenceImageSet->GetElement(0)->GetSpacing() ); outputImage->SetDirection( m_ReferenceImageSet->GetElement(0)->GetDirection() ); outputImage->Allocate(); outputImage->FillBuffer(0.0); this->SetNthOutput(1, outputImage); if (m_MaskImage.IsNull()) { m_MaskImage = UCharImageType::New(); m_MaskImage->SetOrigin( outputImage->GetOrigin() ); m_MaskImage->SetRegions( outputImage->GetLargestPossibleRegion() ); m_MaskImage->SetSpacing( outputImage->GetSpacing() ); m_MaskImage->SetDirection( outputImage->GetDirection() ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } m_MeanAngularError = 0.0; m_MedianAngularError = 0; m_MaxAngularError = 0.0; m_MinAngularError = itk::NumericTraits::max(); m_VarAngularError = 0.0; m_AngularErrorVector.clear(); m_MeanLengthError = 0.0; m_MedianLengthError = 0; m_MaxLengthError = 0.0; m_MinLengthError = itk::NumericTraits::max(); m_VarLengthError = 0.0; m_LengthErrorVector.clear(); if (m_ImageSet.IsNull() || m_ReferenceImageSet.IsNull()) return; outputImage = static_cast< OutputImageType* >(this->ProcessObject::GetOutput(0)); typename OutputImageType::Pointer outputImage2 = static_cast< OutputImageType* >(this->ProcessObject::GetOutput(1)); ImageRegionIterator< OutputImageType > oit(outputImage, outputImage->GetLargestPossibleRegion()); ImageRegionIterator< OutputImageType > oit2(outputImage2, outputImage2->GetLargestPossibleRegion()); ImageRegionIterator< UCharImageType > mit(m_MaskImage, m_MaskImage->GetLargestPossibleRegion()); int numTestImages = m_ImageSet->Size(); int numReferenceImages = m_ReferenceImageSet->Size(); int maxNumDirections = std::max(numReferenceImages, numTestImages); // matrix containing the angular error between the directions vnl_matrix< float > diffM; diffM.set_size(maxNumDirections, maxNumDirections); boost::progress_display disp(outputImage->GetLargestPossibleRegion().GetSize()[0]*outputImage->GetLargestPossibleRegion().GetSize()[1]*outputImage->GetLargestPossibleRegion().GetSize()[2]); while( !oit.IsAtEnd() ) { ++disp; if( mit.Get()!=1 ) { ++oit; ++oit2; ++mit; continue; } typename OutputImageType::IndexType index = oit.GetIndex(); float maxAngularError = 1.0; diffM.fill(10); // initialize with invalid error value // get number of valid directions (length > 0) int numRefDirs = 0; int numTestDirs = 0; std::vector< vnl_vector_fixed< PixelType, 3 > > testDirs; std::vector< vnl_vector_fixed< PixelType, 3 > > refDirs; for (int i=0; i refDir = m_ReferenceImageSet->GetElement(i)->GetPixel(index).GetVnlVector(); if (refDir.magnitude() > m_Eps ) { refDir.normalize(); refDirs.push_back(refDir); numRefDirs++; } } for (int i=0; i testDir = m_ImageSet->GetElement(i)->GetPixel(index).GetVnlVector(); if (testDir.magnitude() > m_Eps ) { testDir.normalize(); testDirs.push_back(testDir); numTestDirs++; } } // i: index of reference direction // j: index of test direction for (int i=0; i refDir; if (i testDir; if (j1.0) diffM[i][j] = 1.0; } } float angularError = 0.0; float lengthError = 0.0; int counter = 0; vnl_matrix< float > diffM_copy = diffM; for (int k=0; k small error) for (int i=0; ierror && diffM[i][j]<2) // found valid error entry { error = diffM[i][j]; a = i; b = j; missingDir = false; } else if (diffM[i][j]<0 && error<0) // found missing direction { a = i; b = j; missingDir = true; } } if (a<0 || b<0 || (m_IgnoreMissingDirections && missingDir)) continue; // no more directions found if (a>=numRefDirs && b>=numTestDirs) { MITK_INFO << "ERROR: missing test and reference direction. should not be possible. check code."; continue; } // remove processed directions from error matrix diffM.set_row(a, 10.0); diffM.set_column(b, 10.0); if (a>=numRefDirs) // missing reference direction (find next closest) { for (int i=0; ierror) { error = diffM_copy[i][b]; a = i; } } else if (b>=numTestDirs) // missing test direction (find next closest) { for (int i=0; ierror) { error = diffM_copy[a][i]; b = i; } } float refLength = 0; float testLength = 1; if (a>=numRefDirs || b>=numTestDirs || error<0) error = 0; else { refLength = m_ReferenceImageSet->GetElement(a)->GetPixel(index).GetVnlVector().magnitude(); testLength = m_ImageSet->GetElement(b)->GetPixel(index).GetVnlVector().magnitude(); } m_LengthErrorVector.push_back( fabs(refLength-testLength) ); m_AngularErrorVector.push_back( acos(error)*180.0/M_PI ); m_MeanAngularError += m_AngularErrorVector.back(); m_MeanLengthError += m_LengthErrorVector.back(); angularError += m_AngularErrorVector.back(); lengthError += m_LengthErrorVector.back(); counter++; } if (counter>0) { lengthError /= counter; angularError /= counter; } oit2.Set(lengthError); oit.Set(angularError); ++oit; ++oit2; ++mit; } std::sort( m_AngularErrorVector.begin(), m_AngularErrorVector.end() ); m_MeanAngularError /= m_AngularErrorVector.size(); // mean for (unsigned int i=0; im_MaxAngularError ) m_MaxAngularError = m_AngularErrorVector.at(i); if ( m_AngularErrorVector.at(i)1) { m_VarAngularError /= (m_AngularErrorVector.size()-1); // variance // median if (m_AngularErrorVector.size()%2 == 0) m_MedianAngularError = 0.5*( m_AngularErrorVector.at( m_AngularErrorVector.size()/2 ) + m_AngularErrorVector.at( m_AngularErrorVector.size()/2+1 ) ); else m_MedianAngularError = m_AngularErrorVector.at( (m_AngularErrorVector.size()+1)/2 ) ; } std::sort( m_LengthErrorVector.begin(), m_LengthErrorVector.end() ); m_MeanLengthError /= m_LengthErrorVector.size(); // mean for (unsigned int i=0; im_MaxLengthError ) m_MaxLengthError = m_LengthErrorVector.at(i); if ( m_LengthErrorVector.at(i)1) { m_VarLengthError /= (m_LengthErrorVector.size()-1); // variance // median if (m_LengthErrorVector.size()%2 == 0) m_MedianLengthError = 0.5*( m_LengthErrorVector.at( m_LengthErrorVector.size()/2 ) + m_LengthErrorVector.at( m_LengthErrorVector.size()/2+1 ) ); else m_MedianLengthError = m_LengthErrorVector.at( (m_LengthErrorVector.size()+1)/2 ) ; } } } #endif // __itkEvaluateDirectionImagesFilter_cpp diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkEvaluateDirectionImagesFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkEvaluateDirectionImagesFilter.h index 964c17e5fc..495231d160 100755 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkEvaluateDirectionImagesFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkEvaluateDirectionImagesFilter.h @@ -1,110 +1,110 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkEvaluateDirectionImagesFilter_h_ #define __itkEvaluateDirectionImagesFilter_h_ #include #include #include namespace itk{ /** \class EvaluateDirectionImagesFilter */ template< class PixelType > class EvaluateDirectionImagesFilter : public ImageSource< Image< PixelType, 3 > > { public: typedef EvaluateDirectionImagesFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageSource< Image< PixelType, 3 > > Superclass; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef typename Superclass::OutputImageType OutputImageType; /** Method for creation through the object factory. */ itkNewMacro(Self) /** Runtime information support. */ itkTypeMacro(EvaluateDirectionImagesFilter, ImageToImageFilter) typedef Vector< float, 3 > DirectionType; typedef Image< DirectionType, 3 > DirectionImageType; - typedef VectorContainer< int, DirectionImageType::Pointer > DirectionImageContainerType; + typedef VectorContainer< unsigned int, DirectionImageType::Pointer > DirectionImageContainerType; typedef Image< float, 3 > FloatImageType; typedef Image< bool, 3 > BoolImageType; typedef Image< unsigned char, 3 > UCharImageType; itkSetMacro( ImageSet , DirectionImageContainerType::Pointer) itkSetMacro( ReferenceImageSet , DirectionImageContainerType::Pointer) itkSetMacro( MaskImage , UCharImageType::Pointer) itkSetMacro( IgnoreMissingDirections , bool) itkGetMacro( MeanAngularError, float) itkGetMacro( MinAngularError, float) itkGetMacro( MaxAngularError, float) itkGetMacro( VarAngularError, float) itkGetMacro( MedianAngularError, float) itkGetMacro( MeanLengthError, float) itkGetMacro( MinLengthError, float) itkGetMacro( MaxLengthError, float) itkGetMacro( VarLengthError, float) itkGetMacro( MedianLengthError, float) protected: EvaluateDirectionImagesFilter(); ~EvaluateDirectionImagesFilter() {} void GenerateData(); UCharImageType::Pointer m_MaskImage; DirectionImageContainerType::Pointer m_ImageSet; DirectionImageContainerType::Pointer m_ReferenceImageSet; bool m_IgnoreMissingDirections; double m_MeanAngularError; double m_MedianAngularError; double m_MaxAngularError; double m_MinAngularError; double m_VarAngularError; std::vector< double > m_AngularErrorVector; double m_MeanLengthError; double m_MedianLengthError; double m_MaxLengthError; double m_MinLengthError; double m_VarLengthError; std::vector< double > m_LengthErrorVector; double m_Eps; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkEvaluateDirectionImagesFilter.cpp" #endif #endif //__itkEvaluateDirectionImagesFilter_h_ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFibersFromPlanarFiguresFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFibersFromPlanarFiguresFilter.cpp index b84c54ffc0..14703174e6 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFibersFromPlanarFiguresFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFibersFromPlanarFiguresFilter.cpp @@ -1,251 +1,251 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "itkFibersFromPlanarFiguresFilter.h" #define _USE_MATH_DEFINES #include // MITK #include #include #include #include #include #include #include #include #include // ITK #include #include #include #include // MISC #include namespace itk{ FibersFromPlanarFiguresFilter::FibersFromPlanarFiguresFilter() - : m_Density(1000) + : m_FiberDistribution(DISTRIBUTE_UNIFORM) + , m_Density(1000) , m_FiberSampling(1) , m_Tension(0) , m_Continuity(0) , m_Bias(0) - , m_FiberDistribution(DISTRIBUTE_UNIFORM) , m_Variance(0.1) { } FibersFromPlanarFiguresFilter::~FibersFromPlanarFiguresFilter() { } void FibersFromPlanarFiguresFilter::GeneratePoints() { Statistics::MersenneTwisterRandomVariateGenerator::Pointer randGen = Statistics::MersenneTwisterRandomVariateGenerator::New(); randGen->SetSeed((unsigned int)0); m_2DPoints.clear(); int count = 0; while (count < m_Density) { mitk::Vector2D p; switch (m_FiberDistribution) { case DISTRIBUTE_GAUSSIAN: p[0] = randGen->GetNormalVariate(0, m_Variance); p[1] = randGen->GetNormalVariate(0, m_Variance); break; default: p[0] = randGen->GetUniformVariate(-1, 1); p[1] = randGen->GetUniformVariate(-1, 1); } if (sqrt(p[0]*p[0]+p[1]*p[1]) <= 1) { m_2DPoints.push_back(p); count++; } } } // perform global tracking void FibersFromPlanarFiguresFilter::GenerateData() { // check if enough fiducials are available - for (int i=0; i m_VtkCellArray = vtkSmartPointer::New(); vtkSmartPointer m_VtkPoints = vtkSmartPointer::New(); vector< mitk::PlanarEllipse::Pointer > bundle = m_Fiducials.at(i); vector< unsigned int > fliplist; if (i container = vtkSmartPointer::New(); mitk::PlanarEllipse::Pointer figure = bundle.at(0); mitk::Point2D p0 = figure->GetControlPoint(0); mitk::Point2D p1 = figure->GetControlPoint(1); mitk::Point2D p2 = figure->GetControlPoint(2); mitk::Point2D p3 = figure->GetControlPoint(3); double r1 = p0.EuclideanDistanceTo(p1); double r2 = p0.EuclideanDistanceTo(p2); mitk::Vector2D eDir = p1-p0; eDir.Normalize(); mitk::Vector2D tDir = p3-p0; tDir.Normalize(); // apply twist vnl_matrix_fixed tRot; tRot[0][0] = tDir[0]; tRot[1][1] = tRot[0][0]; tRot[1][0] = sin(acos(tRot[0][0])); tRot[0][1] = -tRot[1][0]; if (tDir[1]<0) tRot.inplace_transpose(); m_2DPoints[j].SetVnlVector(tRot*m_2DPoints[j].GetVnlVector()); // apply new ellipse shape vnl_vector_fixed< double, 2 > newP; newP[0] = m_2DPoints.at(j)[0]; newP[1] = m_2DPoints.at(j)[1]; double alpha = acos(eDir[0]); if (eDir[1]>0) alpha = 2*M_PI-alpha; vnl_matrix_fixed eRot; eRot[0][0] = cos(alpha); eRot[1][1] = eRot[0][0]; eRot[1][0] = sin(alpha); eRot[0][1] = -eRot[1][0]; newP = eRot*newP; newP[0] *= r1; newP[1] *= r2; newP = eRot.transpose()*newP; p0[0] += newP[0]; p0[1] += newP[1]; const mitk::Geometry2D* pfgeometry = figure->GetGeometry2D(); const mitk::PlaneGeometry* planeGeo = dynamic_cast(pfgeometry); mitk::Point3D w, wc; planeGeo->Map(p0, w); wc = figure->GetWorldControlPoint(0); vtkIdType id = m_VtkPoints->InsertNextPoint(w.GetDataPointer()); container->GetPointIds()->InsertNextId(id); vnl_vector_fixed< double, 3 > n = planeGeo->GetNormalVnl(); - for (int k=1; kGetControlPoint(0); p1 = figure->GetControlPoint(1); p2 = figure->GetControlPoint(2); p3 = figure->GetControlPoint(3); r1 = p0.EuclideanDistanceTo(p1); r2 = p0.EuclideanDistanceTo(p2); eDir = p1-p0; eDir.Normalize(); mitk::Vector2D tDir2 = p3-p0; tDir2.Normalize(); mitk::Vector2D temp; temp.SetVnlVector(tRot.transpose() * tDir2.GetVnlVector()); // apply twist tRot[0][0] = tDir[0]*tDir2[0] + tDir[1]*tDir2[1]; tRot[1][1] = tRot[0][0]; tRot[1][0] = sin(acos(tRot[0][0])); tRot[0][1] = -tRot[1][0]; if (temp[1]<0) tRot.inplace_transpose(); m_2DPoints[j].SetVnlVector(tRot*m_2DPoints[j].GetVnlVector()); tDir = tDir2; // apply new ellipse shape newP[0] = m_2DPoints.at(j)[0]; newP[1] = m_2DPoints.at(j)[1]; // calculate normal mitk::Geometry2D* pfgeometry = const_cast(figure->GetGeometry2D()); mitk::PlaneGeometry* planeGeo = dynamic_cast(pfgeometry); mitk::Vector3D perp = wc-planeGeo->ProjectPointOntoPlane(wc); perp.Normalize(); vnl_vector_fixed< double, 3 > n2 = planeGeo->GetNormalVnl(); wc = figure->GetWorldControlPoint(0); // is flip needed? if (dot_product(perp.GetVnlVector(),n2)>0 && dot_product(n,n2)<=0.00001) newP[0] *= -1; if (fliplist.at(k)>0) newP[0] *= -1; n = n2; alpha = acos(eDir[0]); if (eDir[1]>0) alpha = 2*M_PI-alpha; eRot[0][0] = cos(alpha); eRot[1][1] = eRot[0][0]; eRot[1][0] = sin(alpha); eRot[0][1] = -eRot[1][0]; newP = eRot*newP; newP[0] *= r1; newP[1] *= r2; newP = eRot.transpose()*newP; p0[0] += newP[0]; p0[1] += newP[1]; mitk::Point3D w; planeGeo->Map(p0, w); vtkIdType id = m_VtkPoints->InsertNextPoint(w.GetDataPointer()); container->GetPointIds()->InsertNextId(id); } m_VtkCellArray->InsertNextCell(container); } vtkSmartPointer fiberPolyData = vtkSmartPointer::New(); fiberPolyData->SetPoints(m_VtkPoints); fiberPolyData->SetLines(m_VtkCellArray); mitk::FiberBundleX::Pointer mitkFiberBundle = mitk::FiberBundleX::New(fiberPolyData); mitkFiberBundle->DoFiberSmoothing(m_FiberSampling, m_Tension, m_Continuity, m_Bias); m_FiberBundles.push_back(mitkFiberBundle); } } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp index a93e25619b..aae8412a66 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp @@ -1,510 +1,510 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "itkGibbsTrackingFilter.h" // MITK #include #include #include #include #include //#include #include #include // ITK #include #include #include // MISC #include // #include #include #include #include #include #include namespace itk{ template< class ItkQBallImageType > GibbsTrackingFilter< ItkQBallImageType >::GibbsTrackingFilter(): m_StartTemperature(0.1), m_EndTemperature(0.001), m_Iterations(500000), + m_CurrentStep(0), m_ParticleWeight(0), m_ParticleWidth(0), m_ParticleLength(0), m_ConnectionPotential(10), m_InexBalance(0), m_ParticlePotential(0.2), m_MinFiberLength(10), m_AbortTracking(false), - m_NumConnections(0), - m_NumParticles(0), m_NumAcceptedFibers(0), - m_CurrentStep(0), m_BuildFibers(false), m_Steps(10), m_ProposalAcceptance(0), m_CurvatureThreshold(0.7), m_DuplicateImage(true), + m_NumParticles(0), + m_NumConnections(0), m_RandomSeed(-1), m_LoadParameterFile(""), m_LutPath(""), m_IsInValidState(true) { } template< class ItkQBallImageType > GibbsTrackingFilter< ItkQBallImageType >::~GibbsTrackingFilter() { } // fill output fiber bundle datastructure template< class ItkQBallImageType > typename GibbsTrackingFilter< ItkQBallImageType >::FiberPolyDataType GibbsTrackingFilter< ItkQBallImageType >::GetFiberBundle() { if (!m_AbortTracking) { m_BuildFibers = true; while (m_BuildFibers){} } return m_FiberPolyData; } template< class ItkQBallImageType > void GibbsTrackingFilter< ItkQBallImageType > ::EstimateParticleWeight() { MITK_INFO << "GibbsTrackingFilter: estimating particle weight"; float minSpacing; if(m_QBallImage->GetSpacing()[0]GetSpacing()[1] && m_QBallImage->GetSpacing()[0]GetSpacing()[2]) minSpacing = m_QBallImage->GetSpacing()[0]; else if (m_QBallImage->GetSpacing()[1] < m_QBallImage->GetSpacing()[2]) minSpacing = m_QBallImage->GetSpacing()[1]; else minSpacing = m_QBallImage->GetSpacing()[2]; float m_ParticleLength = 1.5*minSpacing; float m_ParticleWidth = 0.5*minSpacing; // seed random generators Statistics::MersenneTwisterRandomVariateGenerator::Pointer randGen = Statistics::MersenneTwisterRandomVariateGenerator::New(); if (m_RandomSeed>-1) randGen->SetSeed(m_RandomSeed); else randGen->SetSeed(); // instantiate all necessary components SphereInterpolator* interpolator = new SphereInterpolator(m_LutPath); // handle lookup table not found cases if( !interpolator->IsInValidState() ) { m_IsInValidState = false; m_AbortTracking = true; m_BuildFibers = false; mitkThrow() << "Unable to load lookup tables."; } ParticleGrid* particleGrid = new ParticleGrid(m_MaskImage, m_ParticleLength, m_ParticleGridCellCapacity); GibbsEnergyComputer* encomp = new GibbsEnergyComputer(m_QBallImage, m_MaskImage, particleGrid, interpolator, randGen); // EnergyComputer* encomp = new EnergyComputer(m_QBallImage, m_MaskImage, particleGrid, interpolator, randGen); MetropolisHastingsSampler* sampler = new MetropolisHastingsSampler(particleGrid, encomp, randGen, m_CurvatureThreshold); float alpha = log(m_EndTemperature/m_StartTemperature); m_ParticleWeight = 0.01; int ppv = 0; // main loop int neededParts = 3000; while (ppvSetParameters(m_ParticleWeight,m_ParticleWidth,m_ConnectionPotential*m_ParticleLength*m_ParticleLength,m_CurvatureThreshold,m_InexBalance,m_ParticlePotential); for( int step = 0; step < 10; step++ ) { // update temperatur for simulated annealing process float temperature = m_StartTemperature * exp(alpha*(((1.0)*step)/((1.0)*10))); sampler->SetTemperature(temperature); for (unsigned long i=0; i<10000; i++) sampler->MakeProposal(); } ppv = particleGrid->m_NumParticles; particleGrid->ResetGrid(); } delete sampler; delete encomp; delete particleGrid; delete interpolator; MITK_INFO << "GibbsTrackingFilter: finished estimating particle weight"; } // perform global tracking template< class ItkQBallImageType > void GibbsTrackingFilter< ItkQBallImageType >::GenerateData() { TimeProbe preClock; preClock.Start(); // check if input is qball or tensor image and generate qball if necessary if (m_QBallImage.IsNull() && m_TensorImage.IsNotNull()) { TensorImageToQBallImageFilter::Pointer filter = TensorImageToQBallImageFilter::New(); filter->SetInput( m_TensorImage ); filter->Update(); m_QBallImage = filter->GetOutput(); } else if (m_DuplicateImage) // generate local working copy of QBall image (if not disabled) { typedef itk::ImageDuplicator< ItkQBallImageType > DuplicateFilterType; typename DuplicateFilterType::Pointer duplicator = DuplicateFilterType::New(); duplicator->SetInputImage( m_QBallImage ); duplicator->Update(); m_QBallImage = duplicator->GetOutput(); } // perform mean subtraction on odfs typedef ImageRegionIterator< ItkQBallImageType > InputIteratorType; InputIteratorType it(m_QBallImage, m_QBallImage->GetLargestPossibleRegion() ); it.GoToBegin(); while (!it.IsAtEnd()) { itk::OrientationDistributionFunction odf(it.Get().GetDataPointer()); float mean = odf.GetMeanValue(); odf -= mean; it.Set(odf.GetDataPointer()); ++it; } // check if mask image is given if it needs resampling PrepareMaskImage(); // load parameter file LoadParameters(); // prepare parameters float minSpacing; if(m_QBallImage->GetSpacing()[0]GetSpacing()[1] && m_QBallImage->GetSpacing()[0]GetSpacing()[2]) minSpacing = m_QBallImage->GetSpacing()[0]; else if (m_QBallImage->GetSpacing()[1] < m_QBallImage->GetSpacing()[2]) minSpacing = m_QBallImage->GetSpacing()[1]; else minSpacing = m_QBallImage->GetSpacing()[2]; if(m_ParticleLength == 0) m_ParticleLength = 1.5*minSpacing; if(m_ParticleWidth == 0) m_ParticleWidth = 0.5*minSpacing; if(m_ParticleWeight == 0) EstimateParticleWeight(); float alpha = log(m_EndTemperature/m_StartTemperature); m_Steps = m_Iterations/10000; if (m_Steps<10) m_Steps = 10; if (m_Steps>m_Iterations) { MITK_INFO << "GibbsTrackingFilter: not enough iterations!"; m_AbortTracking = true; } if (m_CurvatureThreshold < mitk::eps) m_CurvatureThreshold = 0; unsigned long singleIts = (unsigned long)((1.0*m_Iterations) / (1.0*m_Steps)); // seed random generators Statistics::MersenneTwisterRandomVariateGenerator::Pointer randGen = Statistics::MersenneTwisterRandomVariateGenerator::New(); if (m_RandomSeed>-1) randGen->SetSeed(m_RandomSeed); else randGen->SetSeed(); // load sphere interpolator to evaluate the ODFs SphereInterpolator* interpolator = new SphereInterpolator(m_LutPath); // handle lookup table not found cases if( !interpolator->IsInValidState() ) { m_IsInValidState = false; m_AbortTracking = true; m_BuildFibers = false; mitkThrow() << "Unable to load lookup tables."; } // initialize the actual tracking components (ParticleGrid, Metropolis Hastings Sampler and Energy Computer) ParticleGrid* particleGrid; GibbsEnergyComputer* encomp; MetropolisHastingsSampler* sampler; try{ particleGrid = new ParticleGrid(m_MaskImage, m_ParticleLength, m_ParticleGridCellCapacity); encomp = new GibbsEnergyComputer(m_QBallImage, m_MaskImage, particleGrid, interpolator, randGen); encomp->SetParameters(m_ParticleWeight,m_ParticleWidth,m_ConnectionPotential*m_ParticleLength*m_ParticleLength,m_CurvatureThreshold,m_InexBalance,m_ParticlePotential); sampler = new MetropolisHastingsSampler(particleGrid, encomp, randGen, m_CurvatureThreshold); } catch(...) { MITK_ERROR << "Particle grid allocation failed. Not enough memory? Try to increase the particle length."; m_IsInValidState = false; m_AbortTracking = true; m_BuildFibers = false; return; } MITK_INFO << "----------------------------------------"; MITK_INFO << "Iterations: " << m_Iterations; MITK_INFO << "Steps: " << m_Steps; MITK_INFO << "Particle length: " << m_ParticleLength; MITK_INFO << "Particle width: " << m_ParticleWidth; MITK_INFO << "Particle weight: " << m_ParticleWeight; MITK_INFO << "Start temperature: " << m_StartTemperature; MITK_INFO << "End temperature: " << m_EndTemperature; MITK_INFO << "In/Ex balance: " << m_InexBalance; MITK_INFO << "Min. fiber length: " << m_MinFiberLength; MITK_INFO << "Curvature threshold: " << m_CurvatureThreshold; MITK_INFO << "Random seed: " << m_RandomSeed; MITK_INFO << "----------------------------------------"; // main loop preClock.Stop(); TimeProbe clock; clock.Start(); m_NumAcceptedFibers = 0; unsigned long counter = 1; boost::progress_display disp(m_Steps*singleIts); if (!m_AbortTracking) for( m_CurrentStep = 1; m_CurrentStep <= m_Steps; m_CurrentStep++ ) { // update temperatur for simulated annealing process float temperature = m_StartTemperature * exp(alpha*(((1.0)*m_CurrentStep)/((1.0)*m_Steps))); sampler->SetTemperature(temperature); for (unsigned long i=0; iMakeProposal(); if (m_BuildFibers || (i==singleIts-1 && m_CurrentStep==m_Steps)) { m_ProposalAcceptance = (float)sampler->GetNumAcceptedProposals()/counter; m_NumParticles = particleGrid->m_NumParticles; m_NumConnections = particleGrid->m_NumConnections; FiberBuilder fiberBuilder(particleGrid, m_MaskImage); m_FiberPolyData = fiberBuilder.iterate(m_MinFiberLength); m_NumAcceptedFibers = m_FiberPolyData->GetNumberOfLines(); m_BuildFibers = false; } counter++; } m_ProposalAcceptance = (float)sampler->GetNumAcceptedProposals()/counter; m_NumParticles = particleGrid->m_NumParticles; m_NumConnections = particleGrid->m_NumConnections; if (m_AbortTracking) break; } if (m_AbortTracking) { FiberBuilder fiberBuilder(particleGrid, m_MaskImage); m_FiberPolyData = fiberBuilder.iterate(m_MinFiberLength); m_NumAcceptedFibers = m_FiberPolyData->GetNumberOfLines(); } clock.Stop(); delete sampler; delete encomp; delete interpolator; delete particleGrid; m_AbortTracking = true; m_BuildFibers = false; int h = clock.GetTotal()/3600; int m = ((int)clock.GetTotal()%3600)/60; int s = (int)clock.GetTotal()%60; MITK_INFO << "GibbsTrackingFilter: finished gibbs tracking in " << h << "h, " << m << "m and " << s << "s"; m = (int)preClock.GetTotal()/60; s = (int)preClock.GetTotal()%60; MITK_INFO << "GibbsTrackingFilter: preparation of the data took " << m << "m and " << s << "s"; MITK_INFO << "GibbsTrackingFilter: " << m_NumAcceptedFibers << " fibers accepted"; SaveParameters(); } template< class ItkQBallImageType > void GibbsTrackingFilter< ItkQBallImageType >::PrepareMaskImage() { if(m_MaskImage.IsNull()) { MITK_INFO << "GibbsTrackingFilter: generating default mask image"; m_MaskImage = ItkFloatImageType::New(); m_MaskImage->SetSpacing( m_QBallImage->GetSpacing() ); m_MaskImage->SetOrigin( m_QBallImage->GetOrigin() ); m_MaskImage->SetDirection( m_QBallImage->GetDirection() ); m_MaskImage->SetRegions( m_QBallImage->GetLargestPossibleRegion() ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1.0); } else if ( m_MaskImage->GetLargestPossibleRegion().GetSize()[0]!=m_QBallImage->GetLargestPossibleRegion().GetSize()[0] || m_MaskImage->GetLargestPossibleRegion().GetSize()[1]!=m_QBallImage->GetLargestPossibleRegion().GetSize()[1] || m_MaskImage->GetLargestPossibleRegion().GetSize()[2]!=m_QBallImage->GetLargestPossibleRegion().GetSize()[2] || m_MaskImage->GetSpacing()[0]!=m_QBallImage->GetSpacing()[0] || m_MaskImage->GetSpacing()[1]!=m_QBallImage->GetSpacing()[1] || m_MaskImage->GetSpacing()[2]!=m_QBallImage->GetSpacing()[2] ) { MITK_INFO << "GibbsTrackingFilter: resampling mask image"; typedef itk::ResampleImageFilter< ItkFloatImageType, ItkFloatImageType, float > ResamplerType; ResamplerType::Pointer resampler = ResamplerType::New(); resampler->SetOutputSpacing( m_QBallImage->GetSpacing() ); resampler->SetOutputOrigin( m_QBallImage->GetOrigin() ); resampler->SetOutputDirection( m_QBallImage->GetDirection() ); resampler->SetSize( m_QBallImage->GetLargestPossibleRegion().GetSize() ); resampler->SetInput( m_MaskImage ); resampler->SetDefaultPixelValue(0.0); resampler->Update(); m_MaskImage = resampler->GetOutput(); MITK_INFO << "GibbsTrackingFilter: resampling finished"; } } // load tracking paramters from xml file (.gtp) template< class ItkQBallImageType > bool GibbsTrackingFilter< ItkQBallImageType >::LoadParameters() { m_AbortTracking = true; try { if( m_LoadParameterFile.length()==0 ) { m_AbortTracking = false; return true; } MITK_INFO << "GibbsTrackingFilter: loading parameter file " << m_LoadParameterFile; TiXmlDocument doc( m_LoadParameterFile ); doc.LoadFile(); TiXmlHandle hDoc(&doc); TiXmlElement* pElem; TiXmlHandle hRoot(0); pElem = hDoc.FirstChildElement().Element(); hRoot = TiXmlHandle(pElem); pElem = hRoot.FirstChildElement("parameter_set").Element(); string iterations(pElem->Attribute("iterations")); m_Iterations = boost::lexical_cast(iterations); string particleLength(pElem->Attribute("particle_length")); m_ParticleLength = boost::lexical_cast(particleLength); string particleWidth(pElem->Attribute("particle_width")); m_ParticleWidth = boost::lexical_cast(particleWidth); string partWeight(pElem->Attribute("particle_weight")); m_ParticleWeight = boost::lexical_cast(partWeight); string startTemp(pElem->Attribute("temp_start")); m_StartTemperature = boost::lexical_cast(startTemp); string endTemp(pElem->Attribute("temp_end")); m_EndTemperature = boost::lexical_cast(endTemp); string inExBalance(pElem->Attribute("inexbalance")); m_InexBalance = boost::lexical_cast(inExBalance); string fiberLength(pElem->Attribute("fiber_length")); m_MinFiberLength = boost::lexical_cast(fiberLength); string curvThres(pElem->Attribute("curvature_threshold")); m_CurvatureThreshold = cos(boost::lexical_cast(curvThres)*M_PI/180); m_AbortTracking = false; MITK_INFO << "GibbsTrackingFilter: parameter file loaded successfully"; return true; } catch(...) { MITK_INFO << "GibbsTrackingFilter: could not load parameter file"; return false; } } // save current tracking paramters to xml file (.gtp) template< class ItkQBallImageType > bool GibbsTrackingFilter< ItkQBallImageType >::SaveParameters() { try { if( m_SaveParameterFile.length()==0 ) { MITK_INFO << "GibbsTrackingFilter: no filename specified to save parameters"; return true; } MITK_INFO << "GibbsTrackingFilter: saving parameter file " << m_SaveParameterFile; TiXmlDocument documentXML; TiXmlDeclaration* declXML = new TiXmlDeclaration( "1.0", "", "" ); documentXML.LinkEndChild( declXML ); TiXmlElement* mainXML = new TiXmlElement("global_tracking_parameter_file"); mainXML->SetAttribute("file_version", "0.1"); documentXML.LinkEndChild(mainXML); TiXmlElement* paramXML = new TiXmlElement("parameter_set"); paramXML->SetAttribute("iterations", boost::lexical_cast(m_Iterations)); paramXML->SetAttribute("particle_length", boost::lexical_cast(m_ParticleLength)); paramXML->SetAttribute("particle_width", boost::lexical_cast(m_ParticleWidth)); paramXML->SetAttribute("particle_weight", boost::lexical_cast(m_ParticleWeight)); paramXML->SetAttribute("temp_start", boost::lexical_cast(m_StartTemperature)); paramXML->SetAttribute("temp_end", boost::lexical_cast(m_EndTemperature)); paramXML->SetAttribute("inexbalance", boost::lexical_cast(m_InexBalance)); paramXML->SetAttribute("fiber_length", boost::lexical_cast(m_MinFiberLength)); paramXML->SetAttribute("curvature_threshold", boost::lexical_cast(m_CurvatureThreshold)); mainXML->LinkEndChild(paramXML); if(!boost::algorithm::ends_with(m_SaveParameterFile, ".gtp")) m_SaveParameterFile.append(".gtp"); documentXML.SaveFile( m_SaveParameterFile ); MITK_INFO << "GibbsTrackingFilter: parameter file saved successfully"; return true; } catch(...) { MITK_INFO << "GibbsTrackingFilter: could not save parameter file"; return false; } } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.cpp index 376f921a67..e46cb29be6 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.cpp @@ -1,235 +1,235 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkKspaceImageFilter_txx #define __itkKspaceImageFilter_txx #include #include #include #include "itkKspaceImageFilter.h" #include #include #include #include #define _USE_MATH_DEFINES #include namespace itk { template< class TPixelType > KspaceImageFilter< TPixelType > ::KspaceImageFilter() - : m_tLine(1) - , m_kOffset(0) - , m_FrequencyMap(NULL) - , m_SimulateRelaxation(true) + : m_SimulateRelaxation(true) , m_SimulateEddyCurrents(false) + , m_FrequencyMap(NULL) + , m_tLine(1) + , m_kOffset(0) , m_Tau(70) , m_EddyGradientMagnitude(30) , m_IsBaseline(true) , m_SignalScale(1) , m_Spikes(0) , m_SpikeAmplitude(1) , m_UseConstantRandSeed(false) { m_DiffusionGradientDirection.Fill(0.0); m_RandGen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); m_RandGen->SetSeed(); } template< class TPixelType > void KspaceImageFilter< TPixelType > ::BeforeThreadedGenerateData() { if (m_UseConstantRandSeed) // always generate the same random numbers? m_RandGen->SetSeed(0); else m_RandGen->SetSeed(); typename OutputImageType::Pointer outputImage = OutputImageType::New(); itk::ImageRegion<2> region; region.SetSize(0, m_OutSize[0]); region.SetSize(1, m_OutSize[1]); outputImage->SetLargestPossibleRegion( region ); outputImage->SetBufferedRegion( region ); outputImage->SetRequestedRegion( region ); outputImage->Allocate(); m_SimulateDistortions = true; if (m_FrequencyMap.IsNull()) { m_SimulateDistortions = false; m_FrequencyMap = InputImageType::New(); m_FrequencyMap->SetLargestPossibleRegion( m_CompartmentImages.at(0)->GetLargestPossibleRegion() ); m_FrequencyMap->SetBufferedRegion( m_CompartmentImages.at(0)->GetLargestPossibleRegion() ); m_FrequencyMap->SetRequestedRegion( m_CompartmentImages.at(0)->GetLargestPossibleRegion() ); m_FrequencyMap->Allocate(); m_FrequencyMap->FillBuffer(0); } double gamma = 42576000; // Gyromagnetic ratio in Hz/T if (m_DiffusionGradientDirection.GetNorm()>0.001) { m_EddyGradientMagnitude /= 1000; // eddy gradient magnitude in T/m m_DiffusionGradientDirection.Normalize(); m_DiffusionGradientDirection = m_DiffusionGradientDirection * m_EddyGradientMagnitude * gamma; m_IsBaseline = false; } this->SetNthOutput(0, outputImage); m_Spike = vcl_complex(0,0); } template< class TPixelType > void KspaceImageFilter< TPixelType > ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType threadId) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); typedef ImageRegionConstIterator< InputImageType > InputIteratorType; double kxMax = outputImage->GetLargestPossibleRegion().GetSize(0); // k-space size in x-direction double kyMax = outputImage->GetLargestPossibleRegion().GetSize(1); // k-space size in y-direction double xMax = m_CompartmentImages.at(0)->GetLargestPossibleRegion().GetSize(0); // scanner coverage in x-direction double yMax = m_CompartmentImages.at(0)->GetLargestPossibleRegion().GetSize(1); // scanner coverage in y-direction double numPix = kxMax*kyMax; double dt = m_tLine/kxMax; double fromMaxEcho = - m_tLine*kyMax/2; double upsampling = xMax/kxMax; // discrepany between k-space resolution and image resolution double yMaxFov = kyMax*upsampling; // actual FOV in y-direction (in x-direction xMax==FOV) int xRingingOffset = xMax-kxMax; int yRingingOffset = yMaxFov-kyMax; while( !oit.IsAtEnd() ) { itk::Index< 2 > kIdx; kIdx[0] = oit.GetIndex()[0]; kIdx[1] = oit.GetIndex()[1]; double t = fromMaxEcho + ((double)kIdx[1]*kxMax+(double)kIdx[0])*dt; // dephasing time // rearrange slice if( kIdx[0] < kxMax/2 ) kIdx[0] = kIdx[0] + kxMax/2; else kIdx[0] = kIdx[0] - kxMax/2; if( kIdx[1] < kyMax/2 ) kIdx[1] = kIdx[1] + kyMax/2; else kIdx[1] = kIdx[1] - kyMax/2; // calculate eddy current decay factors double eddyDecay = 0; if (m_SimulateEddyCurrents) eddyDecay = exp(-(m_TE/2 + t)/m_Tau) * t/1000; // calcualte signal relaxation factors std::vector< double > relaxFactor; if (m_SimulateRelaxation) for (unsigned int i=0; i=kxMax/2) kx += xRingingOffset; if (ky>=kyMax/2) ky += yRingingOffset; vcl_complex s(0,0); InputIteratorType it(m_CompartmentImages.at(0), m_CompartmentImages.at(0)->GetLargestPossibleRegion() ); while( !it.IsAtEnd() ) { double x = it.GetIndex()[0]-xMax/2; double y = it.GetIndex()[1]-yMax/2; vcl_complex f(0, 0); // sum compartment signals and simulate relaxation for (unsigned int i=0; i( m_CompartmentImages.at(i)->GetPixel(it.GetIndex()) * relaxFactor.at(i) * m_SignalScale, 0); else f += std::complex( m_CompartmentImages.at(i)->GetPixel(it.GetIndex()) * m_SignalScale ); // simulate eddy currents and other distortions double omega_t = 0; if ( m_SimulateEddyCurrents && !m_IsBaseline) { itk::Vector< double, 3 > pos; pos[0] = x; pos[1] = y; pos[2] = m_Z; pos = m_DirectionMatrix*pos/1000; // vector from image center to current position (in meter) omega_t += (m_DiffusionGradientDirection[0]*pos[0]+m_DiffusionGradientDirection[1]*pos[1]+m_DiffusionGradientDirection[2]*pos[2])*eddyDecay; } if (m_SimulateDistortions) omega_t += m_FrequencyMap->GetPixel(it.GetIndex())*t/1000; if (y<-yMaxFov/2) y += yMaxFov; else if (y>=yMaxFov/2) y -= yMaxFov; // actual DFT term s += f * exp( std::complex(0, 2 * M_PI * (kx*x/xMax + ky*y/yMaxFov + omega_t )) ); ++it; } s /= numPix; if (m_Spikes>0 && sqrt(s.imag()*s.imag()+s.real()*s.real()) > sqrt(m_Spike.imag()*m_Spike.imag()+m_Spike.real()*m_Spike.real()) ) m_Spike = s; outputImage->SetPixel(kIdx, s); ++oit; } } template< class TPixelType > void KspaceImageFilter< TPixelType > ::AfterThreadedGenerateData() { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); double kxMax = outputImage->GetLargestPossibleRegion().GetSize(0); // k-space size in x-direction double kyMax = outputImage->GetLargestPossibleRegion().GetSize(1); // k-space size in y-direction m_Spike *= m_SpikeAmplitude; itk::Index< 2 > spikeIdx; for (int i=0; iGetIntegerVariate()%(int)kxMax; spikeIdx[1] = m_RandGen->GetIntegerVariate()%(int)kyMax; outputImage->SetPixel(spikeIdx, m_Spike); } } } #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.cpp index fcc0f997e6..9073dde2f8 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.cpp @@ -1,883 +1,883 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkStreamlineTrackingFilter_txx #define __itkStreamlineTrackingFilter_txx #include #include #include #include "itkStreamlineTrackingFilter.h" #include #include #include #define _USE_MATH_DEFINES #include namespace itk { //#define QBALL_RECON_PI M_PI template< class TTensorPixelType, class TPDPixelType> StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::StreamlineTrackingFilter(): m_FaThreshold(0.2), m_StepSize(1), m_MaxLength(10000), + m_MinTractLength(0.0), m_SeedsPerVoxel(1), m_F(1.0), m_G(0.0), m_Interpolate(true), - m_MinTractLength(0.0), m_ResampleFibers(false) { // At least 1 inputs is necessary for a vector image. // For images added one at a time we need at least six this->SetNumberOfRequiredInputs( 1 ); this->SetNumberOfIndexedInputs(3); } template< class TTensorPixelType, class TPDPixelType> double StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::RoundToNearest(double num) { return (num > 0.0) ? floor(num + 0.5) : ceil(num - 0.5); } template< class TTensorPixelType, class TPDPixelType> void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::BeforeThreadedGenerateData() { m_FiberPolyData = FiberPolyDataType::New(); m_Points = vtkPoints::New(); m_Cells = vtkCellArray::New(); InputImageType* inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); m_ImageSize.resize(3); m_ImageSize[0] = inputImage->GetLargestPossibleRegion().GetSize()[0]; m_ImageSize[1] = inputImage->GetLargestPossibleRegion().GetSize()[1]; m_ImageSize[2] = inputImage->GetLargestPossibleRegion().GetSize()[2]; if (m_ImageSize[0]<3 || m_ImageSize[1]<3 || m_ImageSize[2]<3) m_Interpolate = false; m_ImageSpacing.resize(3); m_ImageSpacing[0] = inputImage->GetSpacing()[0]; m_ImageSpacing[1] = inputImage->GetSpacing()[1]; m_ImageSpacing[2] = inputImage->GetSpacing()[2]; float minSpacing; if(m_ImageSpacing[0]::New(); for (unsigned int i=0; iGetNumberOfThreads(); i++) { FiberPolyDataType poly = FiberPolyDataType::New(); m_PolyDataContainer->InsertElement(i, poly); } if (m_SeedImage.IsNull()) { // initialize mask image m_SeedImage = ItkUcharImgType::New(); m_SeedImage->SetSpacing( inputImage->GetSpacing() ); m_SeedImage->SetOrigin( inputImage->GetOrigin() ); m_SeedImage->SetDirection( inputImage->GetDirection() ); m_SeedImage->SetRegions( inputImage->GetLargestPossibleRegion() ); m_SeedImage->Allocate(); m_SeedImage->FillBuffer(1); } if (m_MaskImage.IsNull()) { // initialize mask image m_MaskImage = ItkUcharImgType::New(); m_MaskImage->SetSpacing( inputImage->GetSpacing() ); m_MaskImage->SetOrigin( inputImage->GetOrigin() ); m_MaskImage->SetDirection( inputImage->GetDirection() ); m_MaskImage->SetRegions( inputImage->GetLargestPossibleRegion() ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } bool useUserFaImage = true; if (m_FaImage.IsNull()) { m_FaImage = ItkFloatImgType::New(); m_FaImage->SetSpacing( inputImage->GetSpacing() ); m_FaImage->SetOrigin( inputImage->GetOrigin() ); m_FaImage->SetDirection( inputImage->GetDirection() ); m_FaImage->SetRegions( inputImage->GetLargestPossibleRegion() ); m_FaImage->Allocate(); m_FaImage->FillBuffer(0.0); useUserFaImage = false; } m_NumberOfInputs = 0; for (unsigned int i=0; iGetNumberOfIndexedInputs(); i++) { if (this->ProcessObject::GetInput(i)==NULL) break; ItkPDImgType::Pointer pdImage = ItkPDImgType::New(); pdImage->SetSpacing( inputImage->GetSpacing() ); pdImage->SetOrigin( inputImage->GetOrigin() ); pdImage->SetDirection( inputImage->GetDirection() ); pdImage->SetRegions( inputImage->GetLargestPossibleRegion() ); pdImage->Allocate(); m_PdImage.push_back(pdImage); ItkFloatImgType::Pointer emaxImage = ItkFloatImgType::New(); emaxImage->SetSpacing( inputImage->GetSpacing() ); emaxImage->SetOrigin( inputImage->GetOrigin() ); emaxImage->SetDirection( inputImage->GetDirection() ); emaxImage->SetRegions( inputImage->GetLargestPossibleRegion() ); emaxImage->Allocate(); emaxImage->FillBuffer(1.0); m_EmaxImage.push_back(emaxImage); typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(i) ); m_InputImage.push_back(inputImage); m_NumberOfInputs++; } MITK_INFO << "Processing " << m_NumberOfInputs << " tensor files"; typedef itk::DiffusionTensor3D TensorType; typename TensorType::EigenValuesArrayType eigenvalues; typename TensorType::EigenVectorsMatrixType eigenvectors; for (int x=0; xGetPixel(index); vnl_vector_fixed dir; tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors); dir[0] = eigenvectors(2, 0); dir[1] = eigenvectors(2, 1); dir[2] = eigenvectors(2, 2); dir.normalize(); m_PdImage.at(i)->SetPixel(index, dir); if (!useUserFaImage) m_FaImage->SetPixel(index, m_FaImage->GetPixel(index)+tensor.GetFractionalAnisotropy()); m_EmaxImage.at(i)->SetPixel(index, 2/eigenvalues[2]); } if (!useUserFaImage) m_FaImage->SetPixel(index, m_FaImage->GetPixel(index)/m_NumberOfInputs); } if (m_Interpolate) std::cout << "StreamlineTrackingFilter: using trilinear interpolation" << std::endl; else { if (m_MinCurvatureRadius<0.0) m_MinCurvatureRadius = 0.1*minSpacing; std::cout << "StreamlineTrackingFilter: using nearest neighbor interpolation" << std::endl; } if (m_MinCurvatureRadius<0.0) m_MinCurvatureRadius = 0.5*minSpacing; std::cout << "StreamlineTrackingFilter: Min. curvature radius: " << m_MinCurvatureRadius << std::endl; std::cout << "StreamlineTrackingFilter: FA threshold: " << m_FaThreshold << std::endl; std::cout << "StreamlineTrackingFilter: stepsize: " << m_StepSize << " mm" << std::endl; std::cout << "StreamlineTrackingFilter: f: " << m_F << std::endl; std::cout << "StreamlineTrackingFilter: g: " << m_G << std::endl; std::cout << "StreamlineTrackingFilter: starting streamline tracking using " << this->GetNumberOfThreads() << " threads." << std::endl; } template< class TTensorPixelType, class TPDPixelType> void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::CalculateNewPosition(itk::ContinuousIndex& pos, vnl_vector_fixed& dir, typename InputImageType::IndexType& index) { vnl_matrix_fixed< double, 3, 3 > rot = m_InputImage.at(0)->GetDirection().GetTranspose(); dir = rot*dir; if (true) { dir *= m_StepSize; pos[0] += dir[0]/m_ImageSpacing[0]; pos[1] += dir[1]/m_ImageSpacing[1]; pos[2] += dir[2]/m_ImageSpacing[2]; index[0] = RoundToNearest(pos[0]); index[1] = RoundToNearest(pos[1]); index[2] = RoundToNearest(pos[2]); } else { dir[0] /= m_ImageSpacing[0]; dir[1] /= m_ImageSpacing[1]; dir[2] /= m_ImageSpacing[2]; int smallest = 0; float x = 100000; if (dir[0]>0) { if (fabs(fabs(RoundToNearest(pos[0])-pos[0])-0.5)>mitk::eps) x = fabs(pos[0]-RoundToNearest(pos[0])-0.5)/dir[0]; else x = fabs(pos[0]-std::ceil(pos[0])-0.5)/dir[0]; } else if (dir[0]<0) { if (fabs(fabs(RoundToNearest(pos[0])-pos[0])-0.5)>mitk::eps) x = -fabs(pos[0]-RoundToNearest(pos[0])+0.5)/dir[0]; else x = -fabs(pos[0]-std::floor(pos[0])+0.5)/dir[0]; } float s = x; float y = 100000; if (dir[1]>0) { if (fabs(fabs(RoundToNearest(pos[1])-pos[1])-0.5)>mitk::eps) y = fabs(pos[1]-RoundToNearest(pos[1])-0.5)/dir[1]; else y = fabs(pos[1]-std::ceil(pos[1])-0.5)/dir[1]; } else if (dir[1]<0) { if (fabs(fabs(RoundToNearest(pos[1])-pos[1])-0.5)>mitk::eps) y = -fabs(pos[1]-RoundToNearest(pos[1])+0.5)/dir[1]; else y = -fabs(pos[1]-std::floor(pos[1])+0.5)/dir[1]; } if (s>y) { s=y; smallest = 1; } float z = 100000; if (dir[2]>0) { if (fabs(fabs(RoundToNearest(pos[2])-pos[2])-0.5)>mitk::eps) z = fabs(pos[2]-RoundToNearest(pos[2])-0.5)/dir[2]; else z = fabs(pos[2]-std::ceil(pos[2])-0.5)/dir[2]; } else if (dir[2]<0) { if (fabs(fabs(RoundToNearest(pos[2])-pos[2])-0.5)>mitk::eps) z = -fabs(pos[2]-RoundToNearest(pos[2])+0.5)/dir[2]; else z = -fabs(pos[2]-std::floor(pos[2])+0.5)/dir[2]; } if (s>z) { s=z; smallest = 2; } // MITK_INFO << "---------------------------------------------"; // MITK_INFO << "s: " << s; // MITK_INFO << "dir: " << dir; // MITK_INFO << "old: " << pos[0] << ", " << pos[1] << ", " << pos[2]; pos[0] += dir[0]*s; pos[1] += dir[1]*s; pos[2] += dir[2]*s; switch (smallest) { case 0: if (dir[0]<0) index[0] = std::floor(pos[0]); else index[0] = std::ceil(pos[0]); index[1] = RoundToNearest(pos[1]); index[2] = RoundToNearest(pos[2]); break; case 1: if (dir[1]<0) index[1] = std::floor(pos[1]); else index[1] = std::ceil(pos[1]); index[0] = RoundToNearest(pos[0]); index[2] = RoundToNearest(pos[2]); break; case 2: if (dir[2]<0) index[2] = std::floor(pos[2]); else index[2] = std::ceil(pos[2]); index[1] = RoundToNearest(pos[1]); index[0] = RoundToNearest(pos[0]); } // float x = 100000; // if (dir[0]>0) // x = fabs(pos[0]-RoundToNearest(pos[0])-0.5)/dir[0]; // else if (dir[0]<0) // x = -fabs(pos[0]-RoundToNearest(pos[0])+0.5)/dir[0]; // float s = x; // float y = 100000; // if (dir[1]>0) // y = fabs(pos[1]-RoundToNearest(pos[1])-0.5)/dir[1]; // else if (dir[1]<0) // y = -fabs(pos[1]-RoundToNearest(pos[1])+0.5)/dir[1]; // if (s>y) // s=y; // float z = 100000; // if (dir[2]>0) // z = fabs(pos[2]-RoundToNearest(pos[2])-0.5)/dir[2]; // else if (dir[2]<0) // z = -fabs(pos[2]-RoundToNearest(pos[2])+0.5)/dir[2]; // if (s>z) // s=z; // s *= 1.001; // pos[0] += dir[0]*s; // pos[1] += dir[1]*s; // pos[2] += dir[2]*s; // index[0] = RoundToNearest(pos[0]); // index[1] = RoundToNearest(pos[1]); // index[2] = RoundToNearest(pos[2]); // MITK_INFO << "new: " << pos[0] << ", " << pos[1] << ", " << pos[2]; } } template< class TTensorPixelType, class TPDPixelType> bool StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::IsValidPosition(itk::ContinuousIndex& pos, typename InputImageType::IndexType &index, vnl_vector_fixed< float, 8 >& interpWeights, int imageIdx) { if (!m_InputImage.at(imageIdx)->GetLargestPossibleRegion().IsInside(index) || m_MaskImage->GetPixel(index)==0) return false; if (m_Interpolate) { float frac_x = pos[0] - index[0]; float frac_y = pos[1] - index[1]; float frac_z = pos[2] - index[2]; if (frac_x<0) { index[0] -= 1; frac_x += 1; } if (frac_y<0) { index[1] -= 1; frac_y += 1; } if (frac_z<0) { index[2] -= 1; frac_z += 1; } frac_x = 1-frac_x; frac_y = 1-frac_y; frac_z = 1-frac_z; // int coordinates inside image? if (index[0] < 0 || index[0] >= m_ImageSize[0]-1) return false; if (index[1] < 0 || index[1] >= m_ImageSize[1]-1) return false; if (index[2] < 0 || index[2] >= m_ImageSize[2]-1) return false; interpWeights[0] = ( frac_x)*( frac_y)*( frac_z); interpWeights[1] = (1-frac_x)*( frac_y)*( frac_z); interpWeights[2] = ( frac_x)*(1-frac_y)*( frac_z); interpWeights[3] = ( frac_x)*( frac_y)*(1-frac_z); interpWeights[4] = (1-frac_x)*(1-frac_y)*( frac_z); interpWeights[5] = ( frac_x)*(1-frac_y)*(1-frac_z); interpWeights[6] = (1-frac_x)*( frac_y)*(1-frac_z); interpWeights[7] = (1-frac_x)*(1-frac_y)*(1-frac_z); typename InputImageType::IndexType tmpIdx; float FA = m_FaImage->GetPixel(index) * interpWeights[0]; tmpIdx = index; tmpIdx[0]++; FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[1]; tmpIdx = index; tmpIdx[1]++; FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[2]; tmpIdx = index; tmpIdx[2]++; FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[3]; tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++; FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[4]; tmpIdx = index; tmpIdx[1]++; tmpIdx[2]++; FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[5]; tmpIdx = index; tmpIdx[2]++; tmpIdx[0]++; FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[6]; tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++; tmpIdx[2]++; FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[7]; if (FAGetPixel(index) float StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::FollowStreamline(itk::ContinuousIndex pos, int dirSign, vtkPoints* points, std::vector< vtkIdType >& ids, int imageIdx) { float tractLength = 0; typedef itk::DiffusionTensor3D TensorType; typename TensorType::EigenValuesArrayType eigenvalues; typename TensorType::EigenVectorsMatrixType eigenvectors; vnl_vector_fixed< float, 8 > interpWeights; typename InputImageType::IndexType index, indexOld; indexOld[0] = -1; indexOld[1] = -1; indexOld[2] = -1; itk::Point worldPos; float distance = 0; float distanceInVoxel = 0; // starting index and direction index[0] = RoundToNearest(pos[0]); index[1] = RoundToNearest(pos[1]); index[2] = RoundToNearest(pos[2]); vnl_vector_fixed dir = m_PdImage.at(imageIdx)->GetPixel(index); dir *= dirSign; // reverse direction vnl_vector_fixed dirOld = dir; if (dir.magnitude()TransformContinuousIndexToPhysicalPoint( pos, worldPos ); ids.push_back(points->InsertNextPoint(worldPos.GetDataPointer())); return tractLength; } else if (distance>=m_PointPistance) { m_SeedImage->TransformContinuousIndexToPhysicalPoint( pos, worldPos ); ids.push_back(points->InsertNextPoint(worldPos.GetDataPointer())); distance = 0; } if (!m_Interpolate) // use nearest neighbour interpolation { if (indexOld!=index) // did we enter a new voxel? if yes, calculate new direction { double minAngle = 0; for (int img=0; img newDir = m_PdImage.at(img)->GetPixel(index); // get principal direction if (newDir.magnitude()GetPixel(index); float scale = m_EmaxImage.at(img)->GetPixel(index); newDir[0] = m_F*newDir[0] + (1-m_F)*( (1-m_G)*dirOld[0] + scale*m_G*(tensor[0]*dirOld[0] + tensor[1]*dirOld[1] + tensor[2]*dirOld[2])); newDir[1] = m_F*newDir[1] + (1-m_F)*( (1-m_G)*dirOld[1] + scale*m_G*(tensor[1]*dirOld[0] + tensor[3]*dirOld[1] + tensor[4]*dirOld[2])); newDir[2] = m_F*newDir[2] + (1-m_F)*( (1-m_G)*dirOld[2] + scale*m_G*(tensor[2]*dirOld[0] + tensor[4]*dirOld[1] + tensor[5]*dirOld[2])); newDir.normalize(); float angle = dot_product(dirOld, newDir); if (angle<0) { newDir *= -1; angle *= -1; } if (angle>minAngle) { minAngle = angle; dir = newDir; } } //float r = m_StepSize/(2*std::asin(std::acos(minAngle)/2)); vnl_vector_fixed v3 = dir+dirOld; v3 *= m_StepSize; float a = m_StepSize; float b = m_StepSize; float c = v3.magnitude(); float r = a*b*c/std::sqrt((a+b+c)*(a+b-c)*(b+c-a)*(a-b+c)); // radius of triangle via Heron's formula (area of triangle) if (r1) { double minAngle = 0; for (int img=0; imgGetPixel(tmpIdx)); if (fabs(angle)>minAngle) { minAngle = angle; tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx); } } tensor = tmpTensor * interpWeights[0]; minAngle = 0; tmpIdx = index; tmpIdx[0]++; for (int img=0; imgGetPixel(tmpIdx)); if (fabs(angle)>minAngle) { minAngle = angle; tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx); } } tensor += tmpTensor * interpWeights[1]; minAngle = 0; tmpIdx = index; tmpIdx[1]++; for (int img=0; imgGetPixel(tmpIdx)); if (fabs(angle)>minAngle) { minAngle = angle; tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx); } } tensor += tmpTensor * interpWeights[2]; minAngle = 0; tmpIdx = index; tmpIdx[2]++; for (int img=0; imgGetPixel(tmpIdx)); if (fabs(angle)>minAngle) { minAngle = angle; tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx); } } tensor += tmpTensor * interpWeights[3]; minAngle = 0; tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++; for (int img=0; imgGetPixel(tmpIdx)); if (fabs(angle)>minAngle) { minAngle = angle; tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx); } } tensor += tmpTensor * interpWeights[4]; minAngle = 0; tmpIdx = index; tmpIdx[1]++; tmpIdx[2]++; for (int img=0; imgGetPixel(tmpIdx)); if (fabs(angle)>minAngle) { minAngle = angle; tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx); } } tensor += tmpTensor * interpWeights[5]; minAngle = 0; tmpIdx = index; tmpIdx[2]++; tmpIdx[0]++; for (int img=0; imgGetPixel(tmpIdx)); if (fabs(angle)>minAngle) { minAngle = angle; tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx); } } tensor += tmpTensor * interpWeights[6]; minAngle = 0; tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++; tmpIdx[2]++; for (int img=0; imgGetPixel(tmpIdx)); if (fabs(angle)>minAngle) { minAngle = angle; tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx); } } tensor += tmpTensor * interpWeights[7]; } else { tensor = m_InputImage.at(0)->GetPixel(index) * interpWeights[0]; typename InputImageType::IndexType tmpIdx = index; tmpIdx[0]++; tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[1]; tmpIdx = index; tmpIdx[1]++; tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[2]; tmpIdx = index; tmpIdx[2]++; tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[3]; tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++; tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[4]; tmpIdx = index; tmpIdx[1]++; tmpIdx[2]++; tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[5]; tmpIdx = index; tmpIdx[2]++; tmpIdx[0]++; tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[6]; tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++; tmpIdx[2]++; tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[7]; } tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors); dir[0] = eigenvectors(2, 0); dir[1] = eigenvectors(2, 1); dir[2] = eigenvectors(2, 2); if (dir.magnitude() v3 = dir+dirOld; v3 *= m_StepSize; float a = m_StepSize; float b = m_StepSize; float c = v3.magnitude(); float r = a*b*c/std::sqrt((a+b+c)*(a+b-c)*(b+c-a)*(a-b+c)); // radius of triangle via Heron's formula (area of triangle) if (r void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType threadId) { FiberPolyDataType poly = m_PolyDataContainer->GetElement(threadId); vtkSmartPointer points = vtkSmartPointer::New(); vtkSmartPointer Cells = vtkSmartPointer::New(); typedef itk::DiffusionTensor3D TensorType; typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typedef ImageRegionConstIterator< ItkUcharImgType > MaskIteratorType; typedef ImageRegionConstIterator< ItkFloatImgType > FloatIteratorType; typedef typename InputImageType::PixelType InputTensorType; MaskIteratorType sit(m_SeedImage, outputRegionForThread ); FloatIteratorType fit(m_FaImage, outputRegionForThread ); MaskIteratorType mit(m_MaskImage, outputRegionForThread ); for (int img=0; img worldPos; while( !sit.IsAtEnd() ) { if (sit.Value()==0 || fit.Value() line = vtkSmartPointer::New(); std::vector< vtkIdType > pointIDs; typename InputImageType::IndexType index = sit.GetIndex(); itk::ContinuousIndex start; unsigned int counter = 0; if (m_SeedsPerVoxel>1) { start[0] = index[0]+(double)(rand()%99-49)/100; start[1] = index[1]+(double)(rand()%99-49)/100; start[2] = index[2]+(double)(rand()%99-49)/100; } else { start[0] = index[0]; start[1] = index[1]; start[2] = index[2]; } // forward tracking float tractLength = FollowStreamline(start, 1, points, pointIDs, img); // add ids to line counter += pointIDs.size(); while (!pointIDs.empty()) { line->GetPointIds()->InsertNextId(pointIDs.back()); pointIDs.pop_back(); } // insert start point m_SeedImage->TransformContinuousIndexToPhysicalPoint( start, worldPos ); line->GetPointIds()->InsertNextId(points->InsertNextPoint(worldPos.GetDataPointer())); // backward tracking tractLength += FollowStreamline(start, -1, points, pointIDs, img); counter += pointIDs.size(); //MITK_INFO << "Tract length " << tractLength; if (tractLengthGetPointIds()->InsertNextId(pointIDs.at(i)); Cells->InsertNextCell(line); } ++sit; ++mit; ++fit; } } poly->SetPoints(points); poly->SetLines(Cells); std::cout << "Thread " << threadId << " finished tracking" << std::endl; } template< class TTensorPixelType, class TPDPixelType> vtkSmartPointer< vtkPolyData > StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::AddPolyData(FiberPolyDataType poly1, FiberPolyDataType poly2) { vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = poly1->GetLines(); vtkSmartPointer vNewPoints = poly1->GetPoints(); for( int i=0; iGetNumberOfLines(); i++ ) { vtkCell* cell = poly2->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } // initialize polydata vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); return vNewPolyData; } template< class TTensorPixelType, class TPDPixelType> void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::AfterThreadedGenerateData() { MITK_INFO << "Generating polydata "; m_FiberPolyData = m_PolyDataContainer->GetElement(0); for (unsigned int i=1; iGetNumberOfThreads(); i++) { m_FiberPolyData = AddPolyData(m_FiberPolyData, m_PolyDataContainer->GetElement(i)); } MITK_INFO << "done"; } template< class TTensorPixelType, class TPDPixelType> void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::PrintSelf(std::ostream& os, Indent indent) const { } } #endif // __itkDiffusionQballPrincipleDirectionsImageFilter_txx diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp index 12acaee9d2..48f94a4d87 100755 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp @@ -1,989 +1,989 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "itkTractsToDWIImageFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace itk { template< class PixelType > TractsToDWIImageFilter< PixelType >::TractsToDWIImageFilter() : m_CircleDummy(false) , m_VolumeAccuracy(10) , m_AddGibbsRinging(false) , m_NumberOfRepetitions(1) , m_EnforcePureFiberVoxels(false) , m_InterpolationShrink(1000) , m_FiberRadius(0) , m_SignalScale(25) , m_kOffset(0) , m_tLine(1) , m_UseInterpolation(false) , m_SimulateRelaxation(true) , m_tInhom(50) , m_TE(100) , m_FrequencyMap(NULL) , m_EddyGradientStrength(0.001) , m_SimulateEddyCurrents(false) , m_Spikes(0) , m_Wrap(1.0) , m_NoiseModel(NULL) , m_SpikeAmplitude(1) , m_AddMotionArtifact(false) , m_UseConstantRandSeed(false) { m_Spacing.Fill(2.5); m_Origin.Fill(0.0); m_DirectionMatrix.SetIdentity(); m_ImageRegion.SetSize(0, 10); m_ImageRegion.SetSize(1, 10); m_ImageRegion.SetSize(2, 10); m_MaxTranslation.Fill(0.0); m_MaxRotation.Fill(0.0); m_RandGen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); m_RandGen->SetSeed(); } template< class PixelType > TractsToDWIImageFilter< PixelType >::~TractsToDWIImageFilter() { } template< class PixelType > TractsToDWIImageFilter< PixelType >::DoubleDwiType::Pointer TractsToDWIImageFilter< PixelType >::DoKspaceStuff( std::vector< DoubleDwiType::Pointer >& images ) { // create slice object ImageRegion<2> sliceRegion; sliceRegion.SetSize(0, m_UpsampledImageRegion.GetSize()[0]); sliceRegion.SetSize(1, m_UpsampledImageRegion.GetSize()[1]); Vector< double, 2 > sliceSpacing; sliceSpacing[0] = m_UpsampledSpacing[0]; sliceSpacing[1] = m_UpsampledSpacing[1]; // frequency map slice SliceType::Pointer fMapSlice = NULL; if (m_FrequencyMap.IsNotNull()) { fMapSlice = SliceType::New(); ImageRegion<2> region; region.SetSize(0, m_UpsampledImageRegion.GetSize()[0]); region.SetSize(1, m_UpsampledImageRegion.GetSize()[1]); fMapSlice->SetLargestPossibleRegion( region ); fMapSlice->SetBufferedRegion( region ); fMapSlice->SetRequestedRegion( region ); fMapSlice->Allocate(); fMapSlice->FillBuffer(0.0); } DoubleDwiType::Pointer newImage = DoubleDwiType::New(); newImage->SetSpacing( m_Spacing ); newImage->SetOrigin( m_Origin ); newImage->SetDirection( m_DirectionMatrix ); newImage->SetLargestPossibleRegion( m_ImageRegion ); newImage->SetBufferedRegion( m_ImageRegion ); newImage->SetRequestedRegion( m_ImageRegion ); newImage->SetVectorLength( images.at(0)->GetVectorLength() ); newImage->Allocate(); MatrixType transform = m_DirectionMatrix; for (int i=0; i<3; i++) for (int j=0; j<3; j++) { if (j<2) transform[i][j] *= m_UpsampledSpacing[j]; else transform[i][j] *= m_Spacing[j]; } std::vector< unsigned int > spikeVolume; for (int i=0; iGetIntegerVariate()%images.at(0)->GetVectorLength()); std::sort (spikeVolume.begin(), spikeVolume.end()); std::reverse (spikeVolume.begin(), spikeVolume.end()); m_StatusText += "0% 10 20 30 40 50 60 70 80 90 100%\n"; m_StatusText += "|----|----|----|----|----|----|----|----|----|----|\n*"; unsigned long lastTick = 0; boost::progress_display disp(2*images.at(0)->GetVectorLength()*images.at(0)->GetLargestPossibleRegion().GetSize(2)); for (unsigned int g=0; gGetVectorLength(); g++) { - std::vector< int > spikeSlice; + std::vector< unsigned int > spikeSlice; while (!spikeVolume.empty() && spikeVolume.back()==g) { spikeSlice.push_back(m_RandGen->GetIntegerVariate()%images.at(0)->GetLargestPossibleRegion().GetSize(2)); spikeVolume.pop_back(); } std::sort (spikeSlice.begin(), spikeSlice.end()); std::reverse (spikeSlice.begin(), spikeSlice.end()); for (unsigned int z=0; zGetLargestPossibleRegion().GetSize(2); z++) { std::vector< SliceType::Pointer > compartmentSlices; std::vector< double > t2Vector; for (unsigned int i=0; i* signalModel; if (iSetLargestPossibleRegion( sliceRegion ); slice->SetBufferedRegion( sliceRegion ); slice->SetRequestedRegion( sliceRegion ); slice->SetSpacing(sliceSpacing); slice->Allocate(); slice->FillBuffer(0.0); // extract slice from channel g for (unsigned int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (unsigned int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { SliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; slice->SetPixel(index2D, images.at(i)->GetPixel(index3D)[g]); if (fMapSlice.IsNotNull() && i==0) fMapSlice->SetPixel(index2D, m_FrequencyMap->GetPixel(index3D)); } compartmentSlices.push_back(slice); t2Vector.push_back(signalModel->GetT2()); } if (this->GetAbortGenerateData()) return NULL; // create k-sapce (inverse fourier transform slices) itk::Size<2> outSize; outSize.SetElement(0, m_ImageRegion.GetSize(0)); outSize.SetElement(1, m_ImageRegion.GetSize(1)); itk::KspaceImageFilter< SliceType::PixelType >::Pointer idft = itk::KspaceImageFilter< SliceType::PixelType >::New(); idft->SetCompartmentImages(compartmentSlices); idft->SetT2(t2Vector); idft->SetUseConstantRandSeed(m_UseConstantRandSeed); idft->SetkOffset(m_kOffset); idft->SettLine(m_tLine); idft->SetTE(m_TE); idft->SetTinhom(m_tInhom); idft->SetSimulateRelaxation(m_SimulateRelaxation); idft->SetSimulateEddyCurrents(m_SimulateEddyCurrents); idft->SetEddyGradientMagnitude(m_EddyGradientStrength); idft->SetZ((double)z-(double)images.at(0)->GetLargestPossibleRegion().GetSize(2)/2.0); idft->SetDirectionMatrix(transform); idft->SetDiffusionGradientDirection(m_FiberModels.at(0)->GetGradientDirection(g)); idft->SetFrequencyMap(fMapSlice); idft->SetSignalScale(m_SignalScale); idft->SetOutSize(outSize); - int numSpikes = 0; + unsigned int numSpikes = 0; while (!spikeSlice.empty() && spikeSlice.back()==z) { numSpikes++; spikeSlice.pop_back(); } idft->SetSpikes(numSpikes); idft->SetSpikeAmplitude(m_SpikeAmplitude); idft->Update(); ComplexSliceType::Pointer fSlice; fSlice = idft->GetOutput(); ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); - for (int tick = 0; tick<(newTick-lastTick); tick++) + for (unsigned int tick = 0; tick<(newTick-lastTick); tick++) m_StatusText += "*"; lastTick = newTick; // fourier transform slice SliceType::Pointer newSlice; itk::DftImageFilter< SliceType::PixelType >::Pointer dft = itk::DftImageFilter< SliceType::PixelType >::New(); dft->SetInput(fSlice); dft->Update(); newSlice = dft->GetOutput(); // put slice back into channel g for (unsigned int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (unsigned int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; SliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; DoubleDwiType::PixelType pix3D = newImage->GetPixel(index3D); pix3D[g] = newSlice->GetPixel(index2D); newImage->SetPixel(index3D, pix3D); } ++disp; newTick = 50*disp.count()/disp.expected_count(); - for (int tick = 0; tick<(newTick-lastTick); tick++) + for (unsigned int tick = 0; tick<(newTick-lastTick); tick++) m_StatusText += "*"; lastTick = newTick; } } m_StatusText += "\n\n"; return newImage; } template< class PixelType > void TractsToDWIImageFilter< PixelType >::GenerateData() { m_StartTime = clock(); m_StatusText = "Starting simulation\n"; // check input data if (m_FiberBundle.IsNull()) itkExceptionMacro("Input fiber bundle is NULL!"); int numFibers = m_FiberBundle->GetNumFibers(); if (numFibers<=0) itkExceptionMacro("Input fiber bundle contains no fibers!"); if (m_FiberModels.empty()) itkExceptionMacro("No diffusion model for fiber compartments defined!"); if (m_EnforcePureFiberVoxels) while (m_FiberModels.size()>1) m_FiberModels.pop_back(); if (m_NonFiberModels.empty()) itkExceptionMacro("No diffusion model for non-fiber compartments defined!"); int baselineIndex = m_FiberModels[0]->GetFirstBaselineIndex(); if (baselineIndex<0) itkExceptionMacro("No baseline index found!"); if (m_UseConstantRandSeed) // always generate the same random numbers? m_RandGen->SetSeed(0); else m_RandGen->SetSeed(); // initialize output dwi image ImageRegion<3> croppedRegion = m_ImageRegion; croppedRegion.SetSize(1, croppedRegion.GetSize(1)*m_Wrap); itk::Point shiftedOrigin = m_Origin; shiftedOrigin[1] += (m_ImageRegion.GetSize(1)-croppedRegion.GetSize(1))*m_Spacing[1]/2; typename OutputImageType::Pointer outImage = OutputImageType::New(); outImage->SetSpacing( m_Spacing ); outImage->SetOrigin( shiftedOrigin ); outImage->SetDirection( m_DirectionMatrix ); outImage->SetLargestPossibleRegion( croppedRegion ); outImage->SetBufferedRegion( croppedRegion ); outImage->SetRequestedRegion( croppedRegion ); outImage->SetVectorLength( m_FiberModels[0]->GetNumGradients() ); outImage->Allocate(); typename OutputImageType::PixelType temp; temp.SetSize(m_FiberModels[0]->GetNumGradients()); temp.Fill(0.0); outImage->FillBuffer(temp); // ADJUST GEOMETRY FOR FURTHER PROCESSING // is input slize size a power of two? unsigned int x=m_ImageRegion.GetSize(0); unsigned int y=m_ImageRegion.GetSize(1); ItkDoubleImgType::SizeType pad; pad[0]=x%2; pad[1]=y%2; pad[2]=0; m_ImageRegion.SetSize(0, x+pad[0]); m_ImageRegion.SetSize(1, y+pad[1]); if (m_FrequencyMap.IsNotNull() && (pad[0]>0 || pad[1]>0)) { itk::ConstantPadImageFilter::Pointer zeroPadder = itk::ConstantPadImageFilter::New(); zeroPadder->SetInput(m_FrequencyMap); zeroPadder->SetConstant(0); zeroPadder->SetPadUpperBound(pad); zeroPadder->Update(); m_FrequencyMap = zeroPadder->GetOutput(); } if (m_TissueMask.IsNotNull() && (pad[0]>0 || pad[1]>0)) { itk::ConstantPadImageFilter::Pointer zeroPadder = itk::ConstantPadImageFilter::New(); zeroPadder->SetInput(m_TissueMask); zeroPadder->SetConstant(0); zeroPadder->SetPadUpperBound(pad); zeroPadder->Update(); m_TissueMask = zeroPadder->GetOutput(); } // apply in-plane upsampling double upsampling = 1; if (m_AddGibbsRinging) upsampling = 2; m_UpsampledSpacing = m_Spacing; m_UpsampledSpacing[0] /= upsampling; m_UpsampledSpacing[1] /= upsampling; m_UpsampledImageRegion = m_ImageRegion; m_UpsampledImageRegion.SetSize(0, m_ImageRegion.GetSize()[0]*upsampling); m_UpsampledImageRegion.SetSize(1, m_ImageRegion.GetSize()[1]*upsampling); m_UpsampledOrigin = m_Origin; m_UpsampledOrigin[0] -= m_Spacing[0]/2; m_UpsampledOrigin[0] += m_UpsampledSpacing[0]/2; m_UpsampledOrigin[1] -= m_Spacing[1]/2; m_UpsampledOrigin[1] += m_UpsampledSpacing[1]/2; m_UpsampledOrigin[2] -= m_Spacing[2]/2; m_UpsampledOrigin[2] += m_UpsampledSpacing[2]/2; // generate double images to store the individual compartment signals std::vector< DoubleDwiType::Pointer > compartments; for (unsigned int i=0; iSetSpacing( m_UpsampledSpacing ); doubleDwi->SetOrigin( m_UpsampledOrigin ); doubleDwi->SetDirection( m_DirectionMatrix ); doubleDwi->SetLargestPossibleRegion( m_UpsampledImageRegion ); doubleDwi->SetBufferedRegion( m_UpsampledImageRegion ); doubleDwi->SetRequestedRegion( m_UpsampledImageRegion ); doubleDwi->SetVectorLength( m_FiberModels[0]->GetNumGradients() ); doubleDwi->Allocate(); DoubleDwiType::PixelType pix; pix.SetSize(m_FiberModels[0]->GetNumGradients()); pix.Fill(0.0); doubleDwi->FillBuffer(pix); compartments.push_back(doubleDwi); } // initialize volume fraction images m_VolumeFractions.clear(); for (unsigned int i=0; iSetSpacing( m_UpsampledSpacing ); doubleImg->SetOrigin( m_UpsampledOrigin ); doubleImg->SetDirection( m_DirectionMatrix ); doubleImg->SetLargestPossibleRegion( m_UpsampledImageRegion ); doubleImg->SetBufferedRegion( m_UpsampledImageRegion ); doubleImg->SetRequestedRegion( m_UpsampledImageRegion ); doubleImg->Allocate(); doubleImg->FillBuffer(0); m_VolumeFractions.push_back(doubleImg); } // resample mask image and frequency map to fit upsampled geometry if (m_AddGibbsRinging) { if (m_TissueMask.IsNotNull()) { // rescale mask image (otherwise there are problems with the resampling) itk::RescaleIntensityImageFilter::Pointer rescaler = itk::RescaleIntensityImageFilter::New(); rescaler->SetInput(0,m_TissueMask); rescaler->SetOutputMaximum(100); rescaler->SetOutputMinimum(0); rescaler->Update(); // resample mask image itk::ResampleImageFilter::Pointer resampler = itk::ResampleImageFilter::New(); resampler->SetInput(rescaler->GetOutput()); resampler->SetOutputParametersFromImage(m_TissueMask); resampler->SetSize(m_UpsampledImageRegion.GetSize()); resampler->SetOutputSpacing(m_UpsampledSpacing); resampler->SetOutputOrigin(m_UpsampledOrigin); resampler->Update(); m_TissueMask = resampler->GetOutput(); } // resample frequency map if (m_FrequencyMap.IsNotNull()) { itk::ResampleImageFilter::Pointer resampler = itk::ResampleImageFilter::New(); resampler->SetInput(m_FrequencyMap); resampler->SetOutputParametersFromImage(m_FrequencyMap); resampler->SetSize(m_UpsampledImageRegion.GetSize()); resampler->SetOutputSpacing(m_UpsampledSpacing); resampler->SetOutputOrigin(m_UpsampledOrigin); resampler->Update(); m_FrequencyMap = resampler->GetOutput(); } } // no input tissue mask is set -> create default bool maskImageSet = true; if (m_TissueMask.IsNull()) { m_StatusText += "No tissue mask set\n"; MITK_INFO << "No tissue mask set"; m_TissueMask = ItkUcharImgType::New(); m_TissueMask->SetSpacing( m_UpsampledSpacing ); m_TissueMask->SetOrigin( m_UpsampledOrigin ); m_TissueMask->SetDirection( m_DirectionMatrix ); m_TissueMask->SetLargestPossibleRegion( m_UpsampledImageRegion ); m_TissueMask->SetBufferedRegion( m_UpsampledImageRegion ); m_TissueMask->SetRequestedRegion( m_UpsampledImageRegion ); m_TissueMask->Allocate(); m_TissueMask->FillBuffer(1); maskImageSet = false; } else { m_StatusText += "Using tissue mask\n"; MITK_INFO << "Using tissue mask"; } m_ImageRegion = croppedRegion; x=m_ImageRegion.GetSize(0); y=m_ImageRegion.GetSize(1); if ( x%2 == 1 ) m_ImageRegion.SetSize(0, x+1); if ( y%2 == 1 ) m_ImageRegion.SetSize(1, y+1); // resample fiber bundle for sufficient voxel coverage m_StatusText += "\n"+this->GetTime()+" > Resampling fibers ...\n"; double segmentVolume = 0.0001; float minSpacing = 1; if(m_UpsampledSpacing[0]GetDeepCopy(); fiberBundle->ResampleFibers(minSpacing/m_VolumeAccuracy); double mmRadius = m_FiberRadius/1000; if (mmRadius>0) segmentVolume = M_PI*mmRadius*mmRadius*minSpacing/m_VolumeAccuracy; double interpFact = 2*atan(-0.5*m_InterpolationShrink); double maxVolume = 0; double voxelVolume = m_UpsampledSpacing[0]*m_UpsampledSpacing[1]*m_UpsampledSpacing[2]; if (m_AddMotionArtifact) { if (m_RandomMotion) { m_StatusText += "Adding random motion artifacts:\n"; m_StatusText += "Maximum rotation: +/-" + boost::lexical_cast(m_MaxRotation) + "°\n"; m_StatusText += "Maximum translation: +/-" + boost::lexical_cast(m_MaxTranslation) + "mm\n"; } else { m_StatusText += "Adding linear motion artifacts:\n"; m_StatusText += "Maximum rotation: " + boost::lexical_cast(m_MaxRotation) + "°\n"; m_StatusText += "Maximum translation: " + boost::lexical_cast(m_MaxTranslation) + "mm\n"; } MITK_INFO << "Adding motion artifacts"; MITK_INFO << "Maximum rotation: " << m_MaxRotation; MITK_INFO << "Maxmimum translation: " << m_MaxTranslation; } maxVolume = 0; m_StatusText += "\n"+this->GetTime()+" > Generating signal of " + boost::lexical_cast(m_FiberModels.size()) + " fiber compartments\n"; MITK_INFO << "Generating signal of " << m_FiberModels.size() << " fiber compartments"; boost::progress_display disp(numFibers*m_FiberModels.at(0)->GetNumGradients()); ofstream logFile; logFile.open("fiberfox_motion.log"); logFile << "0 rotation: 0,0,0; translation: 0,0,0\n"; // get transform for motion artifacts FiberBundleType fiberBundleTransformed = fiberBundle; VectorType rotation = m_MaxRotation/m_FiberModels.at(0)->GetNumGradients(); VectorType translation = m_MaxTranslation/m_FiberModels.at(0)->GetNumGradients(); // creat image to hold transformed mask (motion artifact) ItkUcharImgType::Pointer tempTissueMask = ItkUcharImgType::New(); itk::ImageDuplicator::Pointer duplicator = itk::ImageDuplicator::New(); duplicator->SetInputImage(m_TissueMask); duplicator->Update(); tempTissueMask = duplicator->GetOutput(); // second upsampling needed for motion artifacts ImageRegion<3> upsampledImageRegion = m_UpsampledImageRegion; itk::Vector upsampledSpacing = m_UpsampledSpacing; upsampledSpacing[0] /= 4; upsampledSpacing[1] /= 4; upsampledSpacing[2] /= 4; upsampledImageRegion.SetSize(0, m_UpsampledImageRegion.GetSize()[0]*4); upsampledImageRegion.SetSize(1, m_UpsampledImageRegion.GetSize()[1]*4); upsampledImageRegion.SetSize(2, m_UpsampledImageRegion.GetSize()[2]*4); itk::Point upsampledOrigin = m_UpsampledOrigin; upsampledOrigin[0] -= m_UpsampledSpacing[0]/2; upsampledOrigin[0] += upsampledSpacing[0]/2; upsampledOrigin[1] -= m_UpsampledSpacing[1]/2; upsampledOrigin[1] += upsampledSpacing[1]/2; upsampledOrigin[2] -= m_UpsampledSpacing[2]/2; upsampledOrigin[2] += upsampledSpacing[2]/2; ItkUcharImgType::Pointer upsampledTissueMask = ItkUcharImgType::New(); itk::ResampleImageFilter::Pointer upsampler = itk::ResampleImageFilter::New(); upsampler->SetInput(m_TissueMask); upsampler->SetOutputParametersFromImage(m_TissueMask); upsampler->SetSize(upsampledImageRegion.GetSize()); upsampler->SetOutputSpacing(upsampledSpacing); upsampler->SetOutputOrigin(upsampledOrigin); itk::NearestNeighborInterpolateImageFunction::Pointer nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); upsampler->SetInterpolator(nn_interpolator); upsampler->Update(); upsampledTissueMask = upsampler->GetOutput(); m_StatusText += "0% 10 20 30 40 50 60 70 80 90 100%\n"; m_StatusText += "|----|----|----|----|----|----|----|----|----|----|\n*"; unsigned int lastTick = 0; for (int g=0; gGetNumGradients(); g++) { vtkPolyData* fiberPolyData = fiberBundleTransformed->GetFiberPolyData(); ItkDoubleImgType::Pointer intraAxonalVolume = ItkDoubleImgType::New(); intraAxonalVolume->SetSpacing( m_UpsampledSpacing ); intraAxonalVolume->SetOrigin( m_UpsampledOrigin ); intraAxonalVolume->SetDirection( m_DirectionMatrix ); intraAxonalVolume->SetLargestPossibleRegion( m_UpsampledImageRegion ); intraAxonalVolume->SetBufferedRegion( m_UpsampledImageRegion ); intraAxonalVolume->SetRequestedRegion( m_UpsampledImageRegion ); intraAxonalVolume->Allocate(); intraAxonalVolume->FillBuffer(0); // generate fiber signal for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints<2) continue; for( int j=0; jGetAbortGenerateData()) { m_StatusText += "\n"+this->GetTime()+" > Simulation aborted\n"; return; } double* temp = points->GetPoint(j); itk::Point vertex = GetItkPoint(temp); itk::Vector v = GetItkVector(temp); itk::Vector dir(3); if (jGetPoint(j+1))-v; else dir = v-GetItkVector(points->GetPoint(j-1)); if (dir.GetSquaredNorm()<0.0001 || dir[0]!=dir[0] || dir[1]!=dir[1] || dir[2]!=dir[2]) continue; itk::Index<3> idx; itk::ContinuousIndex contIndex; tempTissueMask->TransformPhysicalPointToIndex(vertex, idx); tempTissueMask->TransformPhysicalPointToContinuousIndex(vertex, contIndex); if (!m_UseInterpolation) // use nearest neighbour interpolation { if (!tempTissueMask->GetLargestPossibleRegion().IsInside(idx) || tempTissueMask->GetPixel(idx)<=0) continue; // generate signal for each fiber compartment for (unsigned int k=0; kSetFiberDirection(dir); DoubleDwiType::PixelType pix = doubleDwi->GetPixel(idx); pix[g] += segmentVolume*m_FiberModels[k]->SimulateMeasurement(g); doubleDwi->SetPixel(idx, pix ); double vol = intraAxonalVolume->GetPixel(idx) + segmentVolume; intraAxonalVolume->SetPixel(idx, vol ); if (g==0 && vol>maxVolume) maxVolume = vol; } continue; } double frac_x = contIndex[0] - idx[0]; double frac_y = contIndex[1] - idx[1]; double frac_z = contIndex[2] - idx[2]; if (frac_x<0) { idx[0] -= 1; frac_x += 1; } if (frac_y<0) { idx[1] -= 1; frac_y += 1; } if (frac_z<0) { idx[2] -= 1; frac_z += 1; } frac_x = atan((0.5-frac_x)*m_InterpolationShrink)/interpFact + 0.5; frac_y = atan((0.5-frac_y)*m_InterpolationShrink)/interpFact + 0.5; frac_z = atan((0.5-frac_z)*m_InterpolationShrink)/interpFact + 0.5; // use trilinear interpolation itk::Index<3> newIdx; for (int x=0; x<2; x++) { frac_x = 1-frac_x; for (int y=0; y<2; y++) { frac_y = 1-frac_y; for (int z=0; z<2; z++) { frac_z = 1-frac_z; newIdx[0] = idx[0]+x; newIdx[1] = idx[1]+y; newIdx[2] = idx[2]+z; double frac = frac_x*frac_y*frac_z; // is position valid? if (!tempTissueMask->GetLargestPossibleRegion().IsInside(newIdx) || tempTissueMask->GetPixel(newIdx)<=0) continue; // generate signal for each fiber compartment for (unsigned int k=0; kSetFiberDirection(dir); DoubleDwiType::PixelType pix = doubleDwi->GetPixel(newIdx); pix[g] += segmentVolume*frac*m_FiberModels[k]->SimulateMeasurement(g); doubleDwi->SetPixel(newIdx, pix ); double vol = intraAxonalVolume->GetPixel(idx) + segmentVolume; intraAxonalVolume->SetPixel(idx, vol ); if (g==0 && vol>maxVolume) maxVolume = vol; } } } } } ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); - for (int tick = 0; tick<(newTick-lastTick); tick++) + for (unsigned int tick = 0; tick<(newTick-lastTick); tick++) m_StatusText += "*"; lastTick = newTick; } // generate non-fiber signal ImageRegionIterator it3(tempTissueMask, tempTissueMask->GetLargestPossibleRegion()); double fact = 1; if (m_FiberRadius<0.0001) fact = voxelVolume/maxVolume; while(!it3.IsAtEnd()) { if (it3.Get()>0) { DoubleDwiType::IndexType index = it3.GetIndex(); // get fiber volume fraction DoubleDwiType::Pointer fiberDwi = compartments.at(0); DoubleDwiType::PixelType fiberPix = fiberDwi->GetPixel(index); // intra axonal compartment if (fact>1) // auto scale intra-axonal if no fiber radius is specified { fiberPix[g] *= fact; fiberDwi->SetPixel(index, fiberPix); } double f = intraAxonalVolume->GetPixel(index)*fact; if (f>voxelVolume || (f>0.0 && m_EnforcePureFiberVoxels) ) // more fiber than space in voxel? { fiberPix[g] *= voxelVolume/f; fiberDwi->SetPixel(index, fiberPix); m_VolumeFractions.at(0)->SetPixel(index, 1); } else { m_VolumeFractions.at(0)->SetPixel(index, f/voxelVolume); double nonf = voxelVolume-f; // non-fiber volume double inter = 0; if (m_FiberModels.size()>1) inter = nonf * f/voxelVolume; // inter-axonal fraction of non fiber compartment scales linearly with f double other = nonf - inter; // rest of compartment double singleinter = inter/(m_FiberModels.size()-1); // adjust non-fiber and intra-axonal signal for (unsigned int i=1; iGetPixel(index); if (f>0) pix[g] /= f; pix[g] *= singleinter; doubleDwi->SetPixel(index, pix); m_VolumeFractions.at(i)->SetPixel(index, singleinter/voxelVolume); } for (unsigned int i=0; iGetPixel(index); // if (dynamic_cast< mitk::AstroStickModel* >(m_NonFiberModels.at(i))) // { // mitk::AstroStickModel* model = dynamic_cast< mitk::AstroStickModel* >(m_NonFiberModels.at(i)); // model->SetSeed(8111984); // } pix[g] += m_NonFiberModels[i]->SimulateMeasurement(g)*other*m_NonFiberModels[i]->GetWeight(); doubleDwi->SetPixel(index, pix); m_VolumeFractions.at(i+m_FiberModels.size())->SetPixel(index, other/voxelVolume*m_NonFiberModels[i]->GetWeight()); } } } ++it3; } // move fibers if (m_AddMotionArtifact) { if (m_RandomMotion) { fiberBundleTransformed = fiberBundle->GetDeepCopy(); rotation[0] = m_RandGen->GetVariateWithClosedRange(m_MaxRotation[0]*2)-m_MaxRotation[0]; rotation[1] = m_RandGen->GetVariateWithClosedRange(m_MaxRotation[1]*2)-m_MaxRotation[1]; rotation[2] = m_RandGen->GetVariateWithClosedRange(m_MaxRotation[2]*2)-m_MaxRotation[2]; translation[0] = m_RandGen->GetVariateWithClosedRange(m_MaxTranslation[0]*2)-m_MaxTranslation[0]; translation[1] = m_RandGen->GetVariateWithClosedRange(m_MaxTranslation[1]*2)-m_MaxTranslation[1]; translation[2] = m_RandGen->GetVariateWithClosedRange(m_MaxTranslation[2]*2)-m_MaxTranslation[2]; } // rotate mask image if (maskImageSet) { ImageRegionIterator maskIt(upsampledTissueMask, upsampledTissueMask->GetLargestPossibleRegion()); tempTissueMask->FillBuffer(0); while(!maskIt.IsAtEnd()) { if (maskIt.Get()<=0) { ++maskIt; continue; } DoubleDwiType::IndexType index = maskIt.GetIndex(); itk::Point point; upsampledTissueMask->TransformIndexToPhysicalPoint(index, point); if (m_RandomMotion) point = fiberBundle->TransformPoint(point.GetVnlVector(), rotation[0],rotation[1],rotation[2],translation[0],translation[1],translation[2]); else point = fiberBundle->TransformPoint(point.GetVnlVector(), rotation[0]*(g+1),rotation[1]*(g+1),rotation[2]*(g+1),translation[0]*(g+1),translation[1]*(g+1),translation[2]*(g+1)); tempTissueMask->TransformPhysicalPointToIndex(point, index); if (tempTissueMask->GetLargestPossibleRegion().IsInside(index)) tempTissueMask->SetPixel(index,100); ++maskIt; } } // rotate fibers logFile << g+1 << " rotation:" << rotation[0] << "," << rotation[1] << "," << rotation[2] << ";"; logFile << " translation:" << translation[0] << "," << translation[1] << "," << translation[2] << "\n"; fiberBundleTransformed->TransformFibers(rotation[0],rotation[1],rotation[2],translation[0],translation[1],translation[2]); } } logFile.close(); m_StatusText += "\n\n"; if (this->GetAbortGenerateData()) { m_StatusText += "\n"+this->GetTime()+" > Simulation aborted\n"; return; } // do k-space stuff DoubleDwiType::Pointer doubleOutImage; if (m_Spikes>0 || m_FrequencyMap.IsNotNull() || m_kOffset>0 || m_SimulateRelaxation || m_SimulateEddyCurrents || m_AddGibbsRinging || m_Wrap<1.0) { m_StatusText += this->GetTime()+" > Adjusting complex signal\n"; MITK_INFO << "Adjusting complex signal:"; if (m_SimulateRelaxation) m_StatusText += "Simulating signal relaxation\n"; if (m_FrequencyMap.IsNotNull()) m_StatusText += "Simulating distortions\n"; if (m_AddGibbsRinging) m_StatusText += "Simulating ringing artifacts\n"; if (m_SimulateEddyCurrents) m_StatusText += "Simulating eddy currents\n"; if (m_Spikes>0) m_StatusText += "Simulating spikes\n"; if (m_Wrap<1.0) m_StatusText += "Simulating aliasing artifacts\n"; if (m_kOffset>0) m_StatusText += "Simulating ghosts\n"; doubleOutImage = DoKspaceStuff(compartments); m_SignalScale = 1; } else { m_StatusText += this->GetTime()+" > Summing compartments\n"; MITK_INFO << "Summing compartments"; doubleOutImage = compartments.at(0); for (unsigned int i=1; i::Pointer adder = itk::AddImageFilter< DoubleDwiType, DoubleDwiType, DoubleDwiType>::New(); adder->SetInput1(doubleOutImage); adder->SetInput2(compartments.at(i)); adder->Update(); doubleOutImage = adder->GetOutput(); } } if (this->GetAbortGenerateData()) { m_StatusText += "\n"+this->GetTime()+" > Simulation aborted\n"; return; } m_StatusText += this->GetTime()+" > Finalizing image\n"; MITK_INFO << "Finalizing image"; if (m_SignalScale>1) m_StatusText += " Scaling signal\n"; if (m_NoiseModel!=NULL) m_StatusText += " Adding noise\n"; unsigned int window = 0; unsigned int min = itk::NumericTraits::max(); ImageRegionIterator it4 (outImage, outImage->GetLargestPossibleRegion()); DoubleDwiType::PixelType signal; signal.SetSize(m_FiberModels[0]->GetNumGradients()); boost::progress_display disp2(outImage->GetLargestPossibleRegion().GetNumberOfPixels()); m_StatusText += "0% 10 20 30 40 50 60 70 80 90 100%\n"; m_StatusText += "|----|----|----|----|----|----|----|----|----|----|\n*"; lastTick = 0; while(!it4.IsAtEnd()) { if (this->GetAbortGenerateData()) { m_StatusText += "\n"+this->GetTime()+" > Simulation aborted\n"; return; } ++disp2; unsigned long newTick = 50*disp2.count()/disp2.expected_count(); - for (int tick = 0; tick<(newTick-lastTick); tick++) + for (unsigned int tick = 0; tick<(newTick-lastTick); tick++) m_StatusText += "*"; lastTick = newTick; typename OutputImageType::IndexType index = it4.GetIndex(); signal = doubleOutImage->GetPixel(index)*m_SignalScale; if (m_NoiseModel!=NULL) { DoubleDwiType::PixelType accu = signal; accu.Fill(0.0); for (unsigned int i=0; iAddNoise(temp); accu += temp; } signal = accu/m_NumberOfRepetitions; } for (unsigned int i=0; i0) signal[i] = floor(signal[i]+0.5); else signal[i] = ceil(signal[i]-0.5); if (!m_FiberModels.at(0)->IsBaselineIndex(i) && signal[i]>window) window = signal[i]; if (!m_FiberModels.at(0)->IsBaselineIndex(i) && signal[i]SetNthOutput(0, outImage); m_StatusText += "\n\n"; m_StatusText += "Finished simulation\n"; m_StatusText += "Simulation time: "+GetTime(); } template< class PixelType > itk::Point TractsToDWIImageFilter< PixelType >::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } template< class PixelType > itk::Vector TractsToDWIImageFilter< PixelType >::GetItkVector(double point[3]) { itk::Vector itkVector; itkVector[0] = point[0]; itkVector[1] = point[1]; itkVector[2] = point[2]; return itkVector; } template< class PixelType > vnl_vector_fixed TractsToDWIImageFilter< PixelType >::GetVnlVector(double point[3]) { vnl_vector_fixed vnlVector; vnlVector[0] = point[0]; vnlVector[1] = point[1]; vnlVector[2] = point[2]; return vnlVector; } template< class PixelType > vnl_vector_fixed TractsToDWIImageFilter< PixelType >::GetVnlVector(Vector& vector) { vnl_vector_fixed vnlVector; vnlVector[0] = vector[0]; vnlVector[1] = vector[1]; vnlVector[2] = vector[2]; return vnlVector; } template< class PixelType > std::string TractsToDWIImageFilter< PixelType >::GetTime() { unsigned long total = (double)(clock() - m_StartTime)/CLOCKS_PER_SEC; unsigned long hours = total/3600; unsigned long minutes = (total%3600)/60; unsigned long seconds = total%60; std::string out = ""; out.append(boost::lexical_cast(hours)); out.append(":"); out.append(boost::lexical_cast(minutes)); out.append(":"); out.append(boost::lexical_cast(seconds)); return out; } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h index e75a6b5208..cb9e1d4b32 100755 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h @@ -1,172 +1,172 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkTractsToDWIImageFilter_h__ #define __itkTractsToDWIImageFilter_h__ // MITK #include #include #include // ITK #include #include #include #include #include #include #include #include namespace itk { /** * \brief Generates artificial diffusion weighted image volume from the input fiberbundle using a generic multicompartment model. */ template< class PixelType > class TractsToDWIImageFilter : public ImageSource< itk::VectorImage< PixelType, 3 > > { public: typedef TractsToDWIImageFilter Self; typedef ImageSource< itk::VectorImage< PixelType, 3 > > Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef typename Superclass::OutputImageType OutputImageType; typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkFloatImgType; typedef itk::Image ItkUcharImgType; typedef mitk::FiberBundleX::Pointer FiberBundleType; typedef itk::VectorImage< double, 3 > DoubleDwiType; typedef std::vector< mitk::DiffusionSignalModel* > DiffusionModelList; typedef itk::Matrix MatrixType; typedef mitk::DiffusionNoiseModel NoiseModelType; typedef itk::Image< double, 2 > SliceType; typedef itk::VnlForwardFFTImageFilter::OutputImageType ComplexSliceType; typedef itk::Vector< double,3> VectorType; typedef itk::Point< double,3> PointType; itkNewMacro(Self) itkTypeMacro( TractsToDWIImageFilter, ImageToImageFilter ) // input itkSetMacro( SignalScale, double ) itkSetMacro( FiberRadius, double ) itkSetMacro( InterpolationShrink, double ) ///< large values shrink (towards nearest neighbour interpolation), small values strech interpolation function (towards linear interpolation) itkSetMacro( VolumeAccuracy, unsigned int ) ///< determines fiber sampling density and thereby the accuracy of the fiber volume fraction itkSetMacro( FiberBundle, FiberBundleType ) ///< input fiber bundle itkSetMacro( Spacing, VectorType ) ///< output image spacing itkSetMacro( Origin, PointType ) ///< output image origin itkSetMacro( DirectionMatrix, MatrixType ) ///< output image rotation itkSetMacro( EnforcePureFiberVoxels, bool ) ///< treat all voxels containing at least one fiber as fiber-only (actually disable non-fiber compartments for this voxel). itkSetMacro( ImageRegion, ImageRegion<3> ) ///< output image size itkSetMacro( NumberOfRepetitions, unsigned int ) ///< number of acquisition repetitions to reduce noise (default is no additional repetition) itkSetMacro( TissueMask, ItkUcharImgType::Pointer ) ///< voxels outside of this binary mask contain only noise (are treated as air) void SetNoiseModel(NoiseModelType* noiseModel){ m_NoiseModel = noiseModel; } ///< generates the noise added to the image values void SetFiberModels(DiffusionModelList modelList){ m_FiberModels = modelList; } ///< generate signal of fiber compartments void SetNonFiberModels(DiffusionModelList modelList){ m_NonFiberModels = modelList; } ///< generate signal of non-fiber compartments mitk::LevelWindow GetLevelWindow(){ return m_LevelWindow; } itkSetMacro( FrequencyMap, ItkDoubleImgType::Pointer ) itkSetMacro( kOffset, double ) itkSetMacro( tLine, double ) itkSetMacro( tInhom, double ) itkSetMacro( TE, double ) itkSetMacro( UseInterpolation, bool ) itkSetMacro( SimulateEddyCurrents, bool ) itkSetMacro( SimulateRelaxation, bool ) itkSetMacro( EddyGradientStrength, double ) itkSetMacro( AddGibbsRinging, bool ) itkSetMacro( Spikes, int ) itkSetMacro( SpikeAmplitude, double ) itkSetMacro( Wrap, double ) itkSetMacro( MaxTranslation, VectorType ) itkSetMacro( MaxRotation, VectorType ) itkSetMacro( AddMotionArtifact, bool ) itkSetMacro( RandomMotion, bool ) itkGetMacro( StatusText, std::string ) itkSetMacro( UseConstantRandSeed, bool ) // output std::vector< ItkDoubleImgType::Pointer > GetVolumeFractions(){ return m_VolumeFractions; } void GenerateData(); protected: TractsToDWIImageFilter(); virtual ~TractsToDWIImageFilter(); itk::Point GetItkPoint(double point[3]); itk::Vector GetItkVector(double point[3]); vnl_vector_fixed GetVnlVector(double point[3]); vnl_vector_fixed GetVnlVector(Vector< float, 3 >& vector); std::string GetTime(); /** Transform generated image compartment by compartment, channel by channel and slice by slice using FFT and add k-space artifacts. */ DoubleDwiType::Pointer DoKspaceStuff(std::vector< DoubleDwiType::Pointer >& images); - itk::Vector m_Spacing; ///< output image spacing - itk::Vector m_UpsampledSpacing; - itk::Point m_Origin; ///< output image origin - itk::Point m_UpsampledOrigin; - MatrixType m_DirectionMatrix; ///< output image rotation - ImageRegion<3> m_ImageRegion; ///< output image size - ImageRegion<3> m_UpsampledImageRegion; - ItkUcharImgType::Pointer m_TissueMask; ///< voxels outside of this binary mask contain only noise (are treated as air) - ItkDoubleImgType::Pointer m_FrequencyMap; ///< map of the B0 inhomogeneities - double m_kOffset; - double m_tLine; - double m_TE; - double m_tInhom; - FiberBundleType m_FiberBundle; ///< input fiber bundle - DiffusionModelList m_FiberModels; ///< generate signal of fiber compartments - DiffusionModelList m_NonFiberModels; ///< generate signal of non-fiber compartments - NoiseModelType* m_NoiseModel; ///< generates the noise added to the image values bool m_CircleDummy; unsigned int m_VolumeAccuracy; bool m_AddGibbsRinging; ///< causes ringing artifacts unsigned int m_NumberOfRepetitions; bool m_EnforcePureFiberVoxels; double m_InterpolationShrink; double m_FiberRadius; double m_SignalScale; - mitk::LevelWindow m_LevelWindow; + double m_kOffset; + double m_tLine; bool m_UseInterpolation; std::vector< ItkDoubleImgType::Pointer > m_VolumeFractions; ///< one double image for each compartment containing the corresponding volume fraction per voxel bool m_SimulateRelaxation; - bool m_SimulateEddyCurrents; + double m_tInhom; + double m_TE; + ItkDoubleImgType::Pointer m_FrequencyMap; ///< map of the B0 inhomogeneities double m_EddyGradientStrength; + bool m_SimulateEddyCurrents; int m_Spikes; - double m_SpikeAmplitude; double m_Wrap; + NoiseModelType* m_NoiseModel; ///< generates the noise added to the image values + double m_SpikeAmplitude; + itk::Vector m_Spacing; ///< output image spacing + itk::Vector m_UpsampledSpacing; + itk::Point m_Origin; ///< output image origin + itk::Point m_UpsampledOrigin; + MatrixType m_DirectionMatrix; ///< output image rotation + ImageRegion<3> m_ImageRegion; ///< output image size + ImageRegion<3> m_UpsampledImageRegion; + ItkUcharImgType::Pointer m_TissueMask; ///< voxels outside of this binary mask contain only noise (are treated as air) + FiberBundleType m_FiberBundle; ///< input fiber bundle + DiffusionModelList m_FiberModels; ///< generate signal of fiber compartments + DiffusionModelList m_NonFiberModels; ///< generate signal of non-fiber compartments + mitk::LevelWindow m_LevelWindow; VectorType m_MaxTranslation; VectorType m_MaxRotation; bool m_AddMotionArtifact; bool m_RandomMotion; itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer m_RandGen; std::string m_StatusText; time_t m_StartTime; bool m_UseConstantRandSeed; }; } #include "itkTractsToDWIImageFilter.cpp" #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.cpp index e2857935cd..fe4df6a770 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.cpp @@ -1,832 +1,832 @@ #include "itkTractsToVectorImageFilter.h" // VTK #include #include #include // ITK #include #include // misc #define _USE_MATH_DEFINES #include #include namespace itk{ static bool CompareVectorLengths(const vnl_vector_fixed< double, 3 >& v1, const vnl_vector_fixed< double, 3 >& v2) { return (v1.magnitude()>v2.magnitude()); } template< class PixelType > TractsToVectorImageFilter< PixelType >::TractsToVectorImageFilter(): m_AngularThreshold(0.7), + m_Epsilon(0.999), m_MaskImage(NULL), - m_NumDirectionsImage(NULL), m_NormalizeVectors(false), - m_Epsilon(0.999), m_UseWorkingCopy(true), - m_MaxNumDirections(3), m_UseTrilinearInterpolation(false), - m_Thres(0.5) + m_MaxNumDirections(3), + m_Thres(0.5), + m_NumDirectionsImage(NULL) { this->SetNumberOfRequiredOutputs(1); } template< class PixelType > TractsToVectorImageFilter< PixelType >::~TractsToVectorImageFilter() { } template< class PixelType > vnl_vector_fixed TractsToVectorImageFilter< PixelType >::GetVnlVector(double point[3]) { vnl_vector_fixed vnlVector; vnlVector[0] = point[0]; vnlVector[1] = point[1]; vnlVector[2] = point[2]; return vnlVector; } template< class PixelType > itk::Point TractsToVectorImageFilter< PixelType >::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } template< class PixelType > void TractsToVectorImageFilter< PixelType >::GenerateData() { mitk::Geometry3D::Pointer geometry = m_FiberBundle->GetGeometry(); // calculate new image parameters itk::Vector spacing; itk::Point origin; itk::Matrix direction; ImageRegion<3> imageRegion; if (!m_MaskImage.IsNull()) { spacing = m_MaskImage->GetSpacing(); imageRegion = m_MaskImage->GetLargestPossibleRegion(); origin = m_MaskImage->GetOrigin(); direction = m_MaskImage->GetDirection(); } else { spacing = geometry->GetSpacing(); origin = geometry->GetOrigin(); mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); origin[0] += bounds.GetElement(0); origin[1] += bounds.GetElement(2); origin[2] += bounds.GetElement(4); for (int i=0; i<3; i++) for (int j=0; j<3; j++) direction[j][i] = geometry->GetMatrixColumn(i)[j]; imageRegion.SetSize(0, geometry->GetExtent(0)); imageRegion.SetSize(1, geometry->GetExtent(1)); imageRegion.SetSize(2, geometry->GetExtent(2)); m_MaskImage = ItkUcharImgType::New(); m_MaskImage->SetSpacing( spacing ); m_MaskImage->SetOrigin( origin ); m_MaskImage->SetDirection( direction ); m_MaskImage->SetRegions( imageRegion ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } OutputImageType::RegionType::SizeType outImageSize = imageRegion.GetSize(); m_OutImageSpacing = m_MaskImage->GetSpacing(); m_ClusteredDirectionsContainer = ContainerType::New(); // initialize crossings image m_CrossingsImage = ItkUcharImgType::New(); m_CrossingsImage->SetSpacing( spacing ); m_CrossingsImage->SetOrigin( origin ); m_CrossingsImage->SetDirection( direction ); m_CrossingsImage->SetRegions( imageRegion ); m_CrossingsImage->Allocate(); m_CrossingsImage->FillBuffer(0); // initialize num directions image m_NumDirectionsImage = ItkUcharImgType::New(); m_NumDirectionsImage->SetSpacing( spacing ); m_NumDirectionsImage->SetOrigin( origin ); m_NumDirectionsImage->SetDirection( direction ); m_NumDirectionsImage->SetRegions( imageRegion ); m_NumDirectionsImage->Allocate(); m_NumDirectionsImage->FillBuffer(0); // resample fiber bundle float minSpacing = 1; if(m_OutImageSpacing[0]GetDeepCopy(); // resample fiber bundle for sufficient voxel coverage m_FiberBundle->ResampleFibers(minSpacing/3); // iterate over all fibers vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); vtkSmartPointer vLines = fiberPolyData->GetLines(); vLines->InitTraversal(); int numFibers = m_FiberBundle->GetNumFibers(); itk::TimeProbe clock; m_DirectionsContainer = ContainerType::New(); if (m_UseTrilinearInterpolation) MITK_INFO << "Generating directions from tractogram (trilinear interpolation)"; else MITK_INFO << "Generating directions from tractogram"; boost::progress_display disp(numFibers); for( int i=0; iGetNextCell ( numPoints, points ); if (numPoints<2) continue; itk::Index<3> index; index.Fill(0); itk::ContinuousIndex contIndex; vnl_vector_fixed dir, wDir; itk::Point worldPos; vnl_vector v; for( int j=0; jGetPoint(points[j]); worldPos = GetItkPoint(temp); v = GetVnlVector(temp); dir = GetVnlVector(fiberPolyData->GetPoint(points[j+1]))-v; dir.normalize(); m_MaskImage->TransformPhysicalPointToIndex(worldPos, index); m_MaskImage->TransformPhysicalPointToContinuousIndex(worldPos, contIndex); if (m_MaskImage->GetPixel(index)==0) continue; if (!m_UseTrilinearInterpolation) { - if (index[0] < 0 || index[0] >= outImageSize[0]) + if (index[0] < 0 || (unsigned long)index[0] >= outImageSize[0]) continue; - if (index[1] < 0 || index[1] >= outImageSize[1]) + if (index[1] < 0 || (unsigned long)index[1] >= outImageSize[1]) continue; - if (index[2] < 0 || index[2] >= outImageSize[2]) + if (index[2] < 0 || (unsigned long)index[2] >= outImageSize[2]) continue; - int idx = index[0] + outImageSize[0]*(index[1] + outImageSize[1]*index[2]); + unsigned int idx = index[0] + outImageSize[0]*(index[1] + outImageSize[1]*index[2]); DirectionContainerType::Pointer dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, dir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), dir); } else { dirCont->InsertElement(0, dir); m_DirectionsContainer->InsertElement(idx, dirCont); } continue; } float frac_x = contIndex[0] - index[0]; float frac_y = contIndex[1] - index[1]; float frac_z = contIndex[2] - index[2]; if (frac_x<0) { index[0] -= 1; frac_x += 1; } if (frac_y<0) { index[1] -= 1; frac_y += 1; } if (frac_z<0) { index[2] -= 1; frac_z += 1; } frac_x = 1-frac_x; frac_y = 1-frac_y; frac_z = 1-frac_z; // int coordinates inside image? - if (index[0] < 0 || index[0] >= outImageSize[0]-1) + if (index[0] < 0 || (unsigned long)index[0] >= outImageSize[0]-1) continue; - if (index[1] < 0 || index[1] >= outImageSize[1]-1) + if (index[1] < 0 || (unsigned long)index[1] >= outImageSize[1]-1) continue; - if (index[2] < 0 || index[2] >= outImageSize[2]-1) + if (index[2] < 0 || (unsigned long)index[2] >= outImageSize[2]-1) continue; DirectionContainerType::Pointer dirCont; int idx; wDir = dir; float weight = ( frac_x)*( frac_y)*( frac_z); if (weight>m_Thres) { wDir *= weight; idx = index[0] + outImageSize[0]*(index[1] + outImageSize[1]*index[2] ); dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), wDir); } else { dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } } wDir = dir; weight = ( frac_x)*(1-frac_y)*( frac_z); if (weight>m_Thres) { wDir *= weight; idx = index[0] + outImageSize[0]*(index[1]+1+ outImageSize[1]*index[2] ); dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), wDir); } else { dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } } wDir = dir; weight = ( frac_x)*( frac_y)*(1-frac_z); if (weight>m_Thres) { wDir *= weight; idx = index[0] + outImageSize[0]*(index[1] + outImageSize[1]*index[2]+outImageSize[1]); dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), wDir); } else { dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } } wDir = dir; weight = ( frac_x)*(1-frac_y)*(1-frac_z); if (weight>m_Thres) { wDir *= weight; idx = index[0] + outImageSize[0]*(index[1]+1+ outImageSize[1]*index[2]+outImageSize[1]); dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), wDir); } else { dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } } wDir = dir; weight = (1-frac_x)*( frac_y)*( frac_z); if (weight>m_Thres) { wDir *= weight; idx = index[0]+1 + outImageSize[0]*(index[1] + outImageSize[1]*index[2] ); dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), wDir); } else { dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } } wDir = dir; weight = (1-frac_x)*( frac_y)*(1-frac_z); if (weight>m_Thres) { wDir *= weight; idx = index[0]+1 + outImageSize[0]*(index[1] + outImageSize[1]*index[2]+outImageSize[1]); dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), wDir); } else { dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } } wDir = dir; weight = (1-frac_x)*(1-frac_y)*( frac_z); if (weight>m_Thres) { wDir *= weight; idx = index[0]+1 + outImageSize[0]*(index[1]+1+ outImageSize[1]*index[2] ); dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), wDir); } else { dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } } wDir = dir; weight = (1-frac_x)*(1-frac_y)*(1-frac_z); if (weight>m_Thres) { wDir *= weight; idx = index[0]+1 + outImageSize[0]*(index[1]+1+ outImageSize[1]*index[2]+outImageSize[1]); dirCont = DirectionContainerType::New(); if (m_DirectionsContainer->IndexExists(idx)) { dirCont = m_DirectionsContainer->GetElement(idx); if (dirCont.IsNull()) { dirCont = DirectionContainerType::New(); dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } else dirCont->InsertElement(dirCont->Size(), wDir); } else { dirCont->InsertElement(0, wDir); m_DirectionsContainer->InsertElement(idx, dirCont); } } } clock.Stop(); } vtkSmartPointer m_VtkCellArray = vtkSmartPointer::New(); vtkSmartPointer m_VtkPoints = vtkSmartPointer::New(); itk::ImageRegionIterator dirIt(m_NumDirectionsImage, m_NumDirectionsImage->GetLargestPossibleRegion()); itk::ImageRegionIterator crossIt(m_CrossingsImage, m_CrossingsImage->GetLargestPossibleRegion()); m_DirectionImageContainer = DirectionImageContainerType::New(); - int maxNumDirections = 0; + unsigned int maxNumDirections = 0; MITK_INFO << "Clustering directions"; boost::progress_display disp2(outImageSize[0]*outImageSize[1]*outImageSize[2]); for(crossIt.GoToBegin(); !crossIt.IsAtEnd(); ++crossIt) { ++disp2; OutputImageType::IndexType index = crossIt.GetIndex(); int idx = index[0]+(index[1]+index[2]*outImageSize[1])*outImageSize[0]; if (!m_DirectionsContainer->IndexExists(idx)) { ++dirIt; continue; } DirectionContainerType::Pointer dirCont = m_DirectionsContainer->GetElement(idx); - if (dirCont.IsNull() || index[0] < 0 || index[0] >= outImageSize[0] || index[1] < 0 || index[1] >= outImageSize[1] || index[2] < 0 || index[2] >= outImageSize[2]) + if (dirCont.IsNull() || index[0] < 0 || (unsigned long)index[0] >= outImageSize[0] || index[1] < 0 || (unsigned long)index[1] >= outImageSize[1] || index[2] < 0 || (unsigned long)index[2] >= outImageSize[2]) { ++dirIt; continue; } std::vector< DirectionType > directions; - for (int i=0; iSize(); i++) + for (unsigned int i=0; iSize(); i++) if (dirCont->ElementAt(i).magnitude()>0.0001) directions.push_back(dirCont->ElementAt(i)); if (!directions.empty()) directions = FastClustering(directions); std::sort( directions.begin(), directions.end(), CompareVectorLengths ); if ( directions.size() > maxNumDirections ) { - for (int i=maxNumDirections; i(directions.size(), m_MaxNumDirections); i++) { ItkDirectionImageType::Pointer directionImage = ItkDirectionImageType::New(); directionImage->SetSpacing( spacing ); directionImage->SetOrigin( origin ); directionImage->SetDirection( direction ); directionImage->SetRegions( imageRegion ); directionImage->Allocate(); Vector< float, 3 > nullVec; nullVec.Fill(0.0); directionImage->FillBuffer(nullVec); m_DirectionImageContainer->InsertElement(i, directionImage); } - maxNumDirections = std::min((int)directions.size(), m_MaxNumDirections); + maxNumDirections = std::min(directions.size(), m_MaxNumDirections); } - int numDir = directions.size(); + unsigned int numDir = directions.size(); if (numDir>m_MaxNumDirections) numDir = m_MaxNumDirections; - for (int i=0; i container = vtkSmartPointer::New(); itk::ContinuousIndex center; center[0] = index[0]; center[1] = index[1]; center[2] = index[2]; itk::Point worldCenter; m_MaskImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter ); DirectionType dir = directions.at(i); // set direction image pixel ItkDirectionImageType::Pointer directionImage = m_DirectionImageContainer->GetElement(i); Vector< float, 3 > pixel; pixel.SetElement(0, dir[0]); pixel.SetElement(1, dir[1]); pixel.SetElement(2, dir[2]); directionImage->SetPixel(index, pixel); // add direction to vector field (with spacing compensation) itk::Point worldStart; worldStart[0] = worldCenter[0]-dir[0]/2*minSpacing; worldStart[1] = worldCenter[1]-dir[1]/2*minSpacing; worldStart[2] = worldCenter[2]-dir[2]/2*minSpacing; vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer()); container->GetPointIds()->InsertNextId(id); itk::Point worldEnd; worldEnd[0] = worldCenter[0]+dir[0]/2*minSpacing; worldEnd[1] = worldCenter[1]+dir[1]/2*minSpacing; worldEnd[2] = worldCenter[2]+dir[2]/2*minSpacing; id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer()); container->GetPointIds()->InsertNextId(id); m_VtkCellArray->InsertNextCell(container); } dirIt.Set(numDir); ++dirIt; } vtkSmartPointer directionsPolyData = vtkSmartPointer::New(); directionsPolyData->SetPoints(m_VtkPoints); directionsPolyData->SetLines(m_VtkCellArray); m_OutputFiberBundle = mitk::FiberBundleX::New(directionsPolyData); } template< class PixelType > std::vector< vnl_vector_fixed< double, 3 > > TractsToVectorImageFilter< PixelType >::FastClustering(std::vector< vnl_vector_fixed< double, 3 > >& inDirs) { std::vector< vnl_vector_fixed< double, 3 > > outDirs; if (inDirs.empty()) return outDirs; vnl_vector_fixed< double, 3 > oldMean, currentMean, workingMean; std::vector< vnl_vector_fixed< double, 3 > > normalizedDirs; std::vector< int > touched; - for (int i=0; i0.0001) { counter = 0; oldMean = currentMean; workingMean = oldMean; workingMean.normalize(); currentMean.fill(0.0); - for (int i=0; i=m_AngularThreshold) { currentMean += inDirs[i]; touched[i] = 1; counter++; } else if (-angle>=m_AngularThreshold) { currentMean -= inDirs[i]; touched[i] = 1; counter++; } } } // found stable mean if (counter>0) { currentMean /= counter; float mag = currentMean.magnitude(); if (mag>0) { if (mag>max) max = mag; outDirs.push_back(currentMean); } } // find next unused seed free = false; - for (int i=0; i0) - for (int i=0; i std::vector< vnl_vector_fixed< double, 3 > > TractsToVectorImageFilter< PixelType >::Clustering(std::vector< vnl_vector_fixed< double, 3 > >& inDirs) { std::vector< vnl_vector_fixed< double, 3 > > outDirs; if (inDirs.empty()) return outDirs; vnl_vector_fixed< double, 3 > oldMean, currentMean, workingMean; std::vector< vnl_vector_fixed< double, 3 > > normalizedDirs; std::vector< int > touched; for (int i=0; i0.0001) { counter = 0; oldMean = currentMean; workingMean = oldMean; workingMean.normalize(); currentMean.fill(0.0); for (int i=0; i=m_AngularThreshold) { currentMean += inDirs[i]; counter++; } else if (-angle>=m_AngularThreshold) { currentMean -= inDirs[i]; counter++; } } } // found stable mean if (counter>0) { bool add = true; vnl_vector_fixed< double, 3 > normMean = currentMean; normMean.normalize(); for (int i=0; i dir = outDirs[i]; dir.normalize(); if ((normMean-dir).magnitude()<=0.0001) { add = false; break; } } currentMean /= counter; if (add) { float mag = currentMean.magnitude(); if (mag>0) { if (mag>max) max = mag; outDirs.push_back(currentMean); } } } } if (m_NormalizeVectors) for (int i=0; i0) for (int i=0; i TractsToVectorImageFilter< PixelType >::DirectionContainerType::Pointer TractsToVectorImageFilter< PixelType >::MeanShiftClustering(DirectionContainerType::Pointer dirCont) { DirectionContainerType::Pointer container = DirectionContainerType::New(); float max = 0; for (DirectionContainerType::ConstIterator it = dirCont->Begin(); it!=dirCont->End(); ++it) { vnl_vector_fixed mean = ClusterStep(dirCont, it.Value()); if (mean.is_zero()) continue; bool addMean = true; for (DirectionContainerType::ConstIterator it2 = container->Begin(); it2!=container->End(); ++it2) { vnl_vector_fixed dir = it2.Value(); float angle = fabs(dot_product(mean, dir)/(mean.magnitude()*dir.magnitude())); if (angle>=m_Epsilon) { addMean = false; break; } } if (addMean) { if (m_NormalizeVectors) mean.normalize(); else if (mean.magnitude()>max) max = mean.magnitude(); container->InsertElement(container->Size(), mean); } } // max normalize voxel directions if (max>0 && !m_NormalizeVectors) for (int i=0; iSize(); i++) container->ElementAt(i) /= max; if (container->Size()Size()) return MeanShiftClustering(container); else return container; } template< class PixelType > vnl_vector_fixed TractsToVectorImageFilter< PixelType >::ClusterStep(DirectionContainerType::Pointer dirCont, vnl_vector_fixed currentMean) { vnl_vector_fixed newMean; newMean.fill(0); for (DirectionContainerType::ConstIterator it = dirCont->Begin(); it!=dirCont->End(); ++it) { vnl_vector_fixed dir = it.Value(); float angle = dot_product(currentMean, dir)/(currentMean.magnitude()*dir.magnitude()); if (angle>=m_AngularThreshold) newMean += dir; else if (-angle>=m_AngularThreshold) newMean -= dir; } if (fabs(dot_product(currentMean, newMean)/(currentMean.magnitude()*newMean.magnitude()))>=m_Epsilon || newMean.is_zero()) return newMean; else return ClusterStep(dirCont, newMean); } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.h index f7fd1e434e..09ae1fa4aa 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.h @@ -1,108 +1,108 @@ #ifndef __itkTractsToVectorImageFilter_h__ #define __itkTractsToVectorImageFilter_h__ // MITK #include // ITK #include #include // VTK #include #include #include #include #include using namespace mitk; namespace itk{ /** * \brief Extracts the voxel-wise main directions of the input fiber bundle. */ template< class PixelType > class TractsToVectorImageFilter : public ImageSource< VectorImage< float, 3 > > { public: typedef TractsToVectorImageFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef itk::Vector OutputVectorType; typedef itk::Image OutputImageType; typedef std::vector< OutputImageType::Pointer > OutputImageContainerType; typedef vnl_vector_fixed< double, 3 > DirectionType; - typedef VectorContainer< int, DirectionType > DirectionContainerType; - typedef VectorContainer< int, DirectionContainerType::Pointer > ContainerType; + typedef VectorContainer< unsigned int, DirectionType > DirectionContainerType; + typedef VectorContainer< unsigned int, DirectionContainerType::Pointer > ContainerType; typedef Image< Vector< float, 3 >, 3> ItkDirectionImageType; - typedef VectorContainer< int, ItkDirectionImageType::Pointer > DirectionImageContainerType; + typedef VectorContainer< unsigned int, ItkDirectionImageType::Pointer > DirectionImageContainerType; typedef itk::Image ItkUcharImgType; itkNewMacro(Self) itkTypeMacro( TractsToVectorImageFilter, ImageSource ) itkSetMacro( AngularThreshold, float) ///< cluster directions that are closer together than the specified threshold itkGetMacro( AngularThreshold, float) ///< cluster directions that are closer together than the specified threshold itkSetMacro( NormalizeVectors, bool) ///< Normalize vectors to length 1 itkGetMacro( NormalizeVectors, bool) ///< Normalize vectors to length 1 itkSetMacro( UseWorkingCopy, bool) ///< Do not modify input fiber bundle. Use a copy. itkGetMacro( UseWorkingCopy, bool) ///< Do not modify input fiber bundle. Use a copy. - itkSetMacro( MaxNumDirections, int) ///< If more directions are extracted, only the largest are kept. - itkGetMacro( MaxNumDirections, int) ///< If more directions are extracted, only the largest are kept. + itkSetMacro( MaxNumDirections, unsigned long) ///< If more directions are extracted, only the largest are kept. + itkGetMacro( MaxNumDirections, unsigned long) ///< If more directions are extracted, only the largest are kept. itkSetMacro( MaskImage, ItkUcharImgType::Pointer) ///< only process voxels inside mask itkSetMacro( FiberBundle, FiberBundleX::Pointer) ///< input fiber bundle itkGetMacro( ClusteredDirectionsContainer, ContainerType::Pointer) ///< output directions itkGetMacro( NumDirectionsImage, ItkUcharImgType::Pointer) ///< nimber of directions per voxel itkGetMacro( CrossingsImage, ItkUcharImgType::Pointer) ///< mask voxels containing crossings itkGetMacro( OutputFiberBundle, FiberBundleX::Pointer) ///< vector field for visualization purposes itkGetMacro( DirectionImageContainer, DirectionImageContainerType::Pointer) ///< output directions void GenerateData(); protected: std::vector< DirectionType > Clustering(std::vector< DirectionType >& inDirs); std::vector< DirectionType > FastClustering(std::vector< DirectionType >& inDirs); ///< cluster fiber directions DirectionContainerType::Pointer MeanShiftClustering(DirectionContainerType::Pointer dirCont); vnl_vector_fixed ClusterStep(DirectionContainerType::Pointer dirCont, vnl_vector_fixed currentMean); vnl_vector_fixed GetVnlVector(double point[3]); itk::Point GetItkPoint(double point[3]); TractsToVectorImageFilter(); virtual ~TractsToVectorImageFilter(); FiberBundleX::Pointer m_FiberBundle; ///< input fiber bundle float m_AngularThreshold; ///< cluster directions that are closer together than the specified threshold float m_Epsilon; ///< epsilon for vector equality check ItkUcharImgType::Pointer m_MaskImage; ///< only voxels inside the binary mask are processed bool m_NormalizeVectors; ///< normalize vectors to length 1 itk::Vector m_OutImageSpacing; ///< spacing of output image ContainerType::Pointer m_DirectionsContainer; ///< container for fiber directions bool m_UseWorkingCopy; ///< do not modify input fiber bundle but work on copy bool m_UseTrilinearInterpolation; ///< trilinearly interpolate between neighbouring voxels - int m_MaxNumDirections; ///< if more directions per voxel are extracted, only the largest are kept + unsigned long m_MaxNumDirections; ///< if more directions per voxel are extracted, only the largest are kept float m_Thres; ///< distance threshold for trilinear interpolation // output datastructures ContainerType::Pointer m_ClusteredDirectionsContainer; ///< contains direction vectors for each voxel ItkUcharImgType::Pointer m_NumDirectionsImage; ///< shows number of fibers per voxel ItkUcharImgType::Pointer m_CrossingsImage; ///< shows voxels containing more than one fiber DirectionImageContainerType::Pointer m_DirectionImageContainer; ///< contains images that contain the output directions FiberBundleX::Pointer m_OutputFiberBundle; ///< vector field for visualization purposes }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkTractsToVectorImageFilter.cpp" #endif #endif // __itkTractsToVectorImageFilter_h__ diff --git a/Modules/DiffusionImaging/FiberTracking/CMakeLists.txt b/Modules/DiffusionImaging/FiberTracking/CMakeLists.txt index 833650d9e1..803120e8b6 100644 --- a/Modules/DiffusionImaging/FiberTracking/CMakeLists.txt +++ b/Modules/DiffusionImaging/FiberTracking/CMakeLists.txt @@ -1,44 +1,45 @@ MITK_CHECK_MODULE(_missing_deps DiffusionCore MitkGraphAlgorithms) if(NOT _missing_deps) set(lut_url http://mitk.org/download/data/FibertrackingLUT.tar.gz) set(lut_tarball ${CMAKE_CURRENT_BINARY_DIR}/FibertrackingLUT.tar.gz) message("Downloading FiberTracking LUT ${lut_url}...") file(DOWNLOAD ${lut_url} ${lut_tarball} EXPECTED_MD5 38ecb6d4a826c9ebb0f4965eb9aeee44 TIMEOUT 20 STATUS status SHOW_PROGRESS ) list(GET status 0 status_code) list(GET status 1 status_msg) if(NOT status_code EQUAL 0) message(SEND_ERROR "${status_msg} (error code ${status_code})") else() message("done.") endif() file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Resources) message("Unpacking FiberTracking LUT tarball...") execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ../FibertrackingLUT.tar.gz WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Resources RESULT_VARIABLE result ERROR_VARIABLE err_msg) if(result) message(SEND_ERROR "Unpacking FibertrackingLUT.tar.gz failed: ${err_msg}") else() message("done.") endif() endif() MITK_CREATE_MODULE( FiberTracking SUBPROJECTS MITK-DTI INCLUDE_DIRS Algorithms Algorithms/GibbsTracking Algorithms/StochasticTracking IODataStructures IODataStructures/FiberBundleX IODataStructures/PlanarFigureComposite Interactions SignalModels Rendering ${CMAKE_CURRENT_BINARY_DIR} DEPENDS DiffusionCore MitkGraphAlgorithms + WARNINGS_AS_ERRORS ) if(MODULE_IS_ENABLED) add_subdirectory(Testing) endif() diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleX.cpp b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleX.cpp index b3d6bc7b3e..d459ac560a 100755 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleX.cpp +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleX.cpp @@ -1,1965 +1,1965 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #define _USE_MATH_DEFINES #include "mitkFiberBundleX.h" #include #include #include #include "mitkImagePixelReadAccessor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const char* mitk::FiberBundleX::COLORCODING_ORIENTATION_BASED = "Color_Orient"; //const char* mitk::FiberBundleX::COLORCODING_FA_AS_OPACITY = "Color_Orient_FA_Opacity"; const char* mitk::FiberBundleX::COLORCODING_FA_BASED = "FA_Values"; const char* mitk::FiberBundleX::COLORCODING_CUSTOM = "custom"; const char* mitk::FiberBundleX::FIBER_ID_ARRAY = "Fiber_IDs"; using namespace std; mitk::FiberBundleX::FiberBundleX( vtkPolyData* fiberPolyData ) : m_CurrentColorCoding(NULL) , m_NumFibers(0) , m_FiberSampling(0) { m_FiberPolyData = vtkSmartPointer::New(); if (fiberPolyData != NULL) { m_FiberPolyData = fiberPolyData; //m_FiberPolyData->DeepCopy(fiberPolyData); this->DoColorCodingOrientationBased(); } this->UpdateFiberGeometry(); this->SetColorCoding(COLORCODING_ORIENTATION_BASED); this->GenerateFiberIds(); } mitk::FiberBundleX::~FiberBundleX() { } mitk::FiberBundleX::Pointer mitk::FiberBundleX::GetDeepCopy() { mitk::FiberBundleX::Pointer newFib = mitk::FiberBundleX::New(m_FiberPolyData); newFib->SetColorCoding(m_CurrentColorCoding); return newFib; } vtkSmartPointer mitk::FiberBundleX::GeneratePolyDataByIds(std::vector fiberIds) { MITK_DEBUG << "\n=====FINAL RESULT: fib_id ======\n"; MITK_DEBUG << "Number of new Fibers: " << fiberIds.size(); // iterate through the vectorcontainer hosting all desired fiber Ids vtkSmartPointer newFiberPolyData = vtkSmartPointer::New(); vtkSmartPointer newLineSet = vtkSmartPointer::New(); vtkSmartPointer newPointSet = vtkSmartPointer::New(); // if FA array available, initialize fa double array // if color orient array is available init color array vtkSmartPointer faValueArray; vtkSmartPointer colorsT; //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; int componentSize = sizeof(rgba); if (m_FiberIdDataSet->GetPointData()->HasArray(COLORCODING_FA_BASED)){ MITK_DEBUG << "FA VALUES AVAILABLE, init array for new fiberbundle"; faValueArray = vtkSmartPointer::New(); } if (m_FiberIdDataSet->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED)){ MITK_DEBUG << "colorValues available, init array for new fiberbundle"; colorsT = vtkUnsignedCharArray::New(); colorsT->SetNumberOfComponents(componentSize); colorsT->SetName(COLORCODING_ORIENTATION_BASED); } std::vector::iterator finIt = fiberIds.begin(); while ( finIt != fiberIds.end() ) { if (*finIt < 0 || *finIt>GetNumFibers()){ MITK_INFO << "FiberID can not be negative or >NumFibers!!! check id Extraction!" << *finIt; break; } vtkSmartPointer fiber = m_FiberIdDataSet->GetCell(*finIt);//->DeepCopy(fiber); vtkSmartPointer fibPoints = fiber->GetPoints(); vtkSmartPointer newFiber = vtkSmartPointer::New(); newFiber->GetPointIds()->SetNumberOfIds( fibPoints->GetNumberOfPoints() ); for(int i=0; iGetNumberOfPoints(); i++) { // MITK_DEBUG << "id: " << fiber->GetPointId(i); // MITK_DEBUG << fibPoints->GetPoint(i)[0] << " | " << fibPoints->GetPoint(i)[1] << " | " << fibPoints->GetPoint(i)[2]; newFiber->GetPointIds()->SetId(i, newPointSet->GetNumberOfPoints()); newPointSet->InsertNextPoint(fibPoints->GetPoint(i)[0], fibPoints->GetPoint(i)[1], fibPoints->GetPoint(i)[2]); if (m_FiberIdDataSet->GetPointData()->HasArray(COLORCODING_FA_BASED)){ // MITK_DEBUG << m_FiberIdDataSet->GetPointData()->GetArray(FA_VALUE_ARRAY)->GetTuple(fiber->GetPointId(i)); } if (m_FiberIdDataSet->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED)){ // MITK_DEBUG << "ColorValue: " << m_FiberIdDataSet->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED)->GetTuple(fiber->GetPointId(i))[0]; } } newLineSet->InsertNextCell(newFiber); ++finIt; } newFiberPolyData->SetPoints(newPointSet); newFiberPolyData->SetLines(newLineSet); MITK_DEBUG << "new fiberbundle polydata points: " << newFiberPolyData->GetNumberOfPoints(); MITK_DEBUG << "new fiberbundle polydata lines: " << newFiberPolyData->GetNumberOfLines(); MITK_DEBUG << "=====================\n"; // mitk::FiberBundleX::Pointer newFib = mitk::FiberBundleX::New(newFiberPolyData); return newFiberPolyData; } // merge two fiber bundles mitk::FiberBundleX::Pointer mitk::FiberBundleX::AddBundle(mitk::FiberBundleX* fib) { if (fib==NULL) { MITK_WARN << "trying to call AddBundle with NULL argument"; return NULL; } MITK_INFO << "Adding fibers"; vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); // add current fiber bundle for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } // add new fiber bundle for (int i=0; iGetFiberPolyData()->GetNumberOfCells(); i++) { vtkCell* cell = fib->GetFiberPolyData()->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } // initialize polydata vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundleX::Pointer newFib = mitk::FiberBundleX::New(vNewPolyData); return newFib; } // subtract two fiber bundles mitk::FiberBundleX::Pointer mitk::FiberBundleX::SubtractBundle(mitk::FiberBundleX* fib) { MITK_INFO << "Subtracting fibers"; vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); // iterate over current fibers boost::progress_display disp(m_NumFibers); for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (points==NULL || numPoints<=0) continue; int numFibers2 = fib->GetNumFibers(); bool contained = false; for( int i2=0; i2GetFiberPolyData()->GetCell(i2); int numPoints2 = cell2->GetNumberOfPoints(); vtkPoints* points2 = cell2->GetPoints(); if (points2==NULL)// || numPoints2<=0) continue; // check endpoints if (numPoints2==numPoints) { itk::Point point_start = GetItkPoint(points->GetPoint(0)); itk::Point point_end = GetItkPoint(points->GetPoint(numPoints-1)); itk::Point point2_start = GetItkPoint(points2->GetPoint(0)); itk::Point point2_end = GetItkPoint(points2->GetPoint(numPoints2-1)); - if (point_start.SquaredEuclideanDistanceTo(point2_start)<=mitk::eps && point_end.SquaredEuclideanDistanceTo(point2_end)<=mitk::eps || - point_start.SquaredEuclideanDistanceTo(point2_end)<=mitk::eps && point_end.SquaredEuclideanDistanceTo(point2_start)<=mitk::eps) + if ((point_start.SquaredEuclideanDistanceTo(point2_start)<=mitk::eps && point_end.SquaredEuclideanDistanceTo(point2_end)<=mitk::eps) || + (point_start.SquaredEuclideanDistanceTo(point2_end)<=mitk::eps && point_end.SquaredEuclideanDistanceTo(point2_start)<=mitk::eps)) { // further checking ??? contained = true; break; } } } // add to result because fiber is not subtracted if (!contained) { vtkSmartPointer container = vtkSmartPointer::New(); for( int j=0; jInsertNextPoint(points->GetPoint(j)); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } } if(vNewLines->GetNumberOfCells()==0) return NULL; // initialize polydata vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle return mitk::FiberBundleX::New(vNewPolyData); } itk::Point mitk::FiberBundleX::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } /* * set polydata (additional flag to recompute fiber geometry, default = true) */ void mitk::FiberBundleX::SetFiberPolyData(vtkSmartPointer fiberPD, bool updateGeometry) { if (fiberPD == NULL) this->m_FiberPolyData = vtkSmartPointer::New(); else { m_FiberPolyData->DeepCopy(fiberPD); DoColorCodingOrientationBased(); } m_NumFibers = m_FiberPolyData->GetNumberOfLines(); if (updateGeometry) UpdateFiberGeometry(); SetColorCoding(COLORCODING_ORIENTATION_BASED); GenerateFiberIds(); } /* * return vtkPolyData */ vtkSmartPointer mitk::FiberBundleX::GetFiberPolyData() { return m_FiberPolyData; } void mitk::FiberBundleX::DoColorCodingOrientationBased() { //===== FOR WRITING A TEST ======================== // colorT size == tupelComponents * tupelElements // compare color results // to cover this code 100% also polydata needed, where colorarray already exists // + one fiber with exactly 1 point // + one fiber with 0 points //================================================= /* make sure that processing colorcoding is only called when necessary */ if ( m_FiberPolyData->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED) && m_FiberPolyData->GetNumberOfPoints() == m_FiberPolyData->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED)->GetNumberOfTuples() ) { // fiberstructure is already colorcoded MITK_DEBUG << " NO NEED TO REGENERATE COLORCODING! " ; this->ResetFiberOpacity(); this->SetColorCoding(COLORCODING_ORIENTATION_BASED); return; } /* Finally, execute color calculation */ vtkPoints* extrPoints = NULL; extrPoints = m_FiberPolyData->GetPoints(); int numOfPoints = 0; if (extrPoints!=NULL) numOfPoints = extrPoints->GetNumberOfPoints(); //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; // int componentSize = sizeof(rgba); int componentSize = 4; vtkSmartPointer colorsT = vtkSmartPointer::New(); colorsT->Allocate(numOfPoints * componentSize); colorsT->SetNumberOfComponents(componentSize); colorsT->SetName(COLORCODING_ORIENTATION_BASED); /* checkpoint: does polydata contain any fibers */ int numOfFibers = m_FiberPolyData->GetNumberOfLines(); if (numOfFibers < 1) { MITK_DEBUG << "\n ========= Number of Fibers is 0 and below ========= \n"; return; } /* extract single fibers of fiberBundle */ vtkCellArray* fiberList = m_FiberPolyData->GetLines(); fiberList->InitTraversal(); for (int fi=0; fiGetNextCell(pointsPerFiber, idList); // MITK_DEBUG << "Fib#: " << fi << " of " << numOfFibers << " pnts in fiber: " << pointsPerFiber ; /* single fiber checkpoints: is number of points valid */ if (pointsPerFiber > 1) { /* operate on points of single fiber */ for (int i=0; i 0) { /* The color value of the current point is influenced by the previous point and next point. */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]); vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]); vnl_vector_fixed< double, 3 > diff1; diff1 = currentPntvtk - nextPntvtk; vnl_vector_fixed< double, 3 > diff2; diff2 = currentPntvtk - prevPntvtk; vnl_vector_fixed< double, 3 > diff; diff = (diff1 - diff2) / 2.0; diff.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff[2])); rgba[3] = (unsigned char) (255.0); } else if (i==0) { /* First point has no previous point, therefore only diff1 is taken */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]); vnl_vector_fixed< double, 3 > diff1; diff1 = currentPntvtk - nextPntvtk; diff1.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff1[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff1[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff1[2])); rgba[3] = (unsigned char) (255.0); } else if (i==pointsPerFiber-1) { /* Last point has no next point, therefore only diff2 is taken */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]); vnl_vector_fixed< double, 3 > diff2; diff2 = currentPntvtk - prevPntvtk; diff2.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff2[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff2[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff2[2])); rgba[3] = (unsigned char) (255.0); } colorsT->InsertTupleValue(idList[i], rgba); } //end for loop } else if (pointsPerFiber == 1) { /* a single point does not define a fiber (use vertex mechanisms instead */ continue; // colorsT->InsertTupleValue(0, rgba); } else { MITK_DEBUG << "Fiber with 0 points detected... please check your tractography algorithm!" ; continue; } }//end for loop m_FiberPolyData->GetPointData()->AddArray(colorsT); /*========================= - this is more relevant for renderer than for fiberbundleX datastructure - think about sourcing this to a explicit method which coordinates colorcoding */ this->SetColorCoding(COLORCODING_ORIENTATION_BASED); // =========================== //mini test, shall be ported to MITK TESTINGS! if (colorsT->GetSize() != numOfPoints*componentSize) MITK_DEBUG << "ALLOCATION ERROR IN INITIATING COLOR ARRAY"; } void mitk::FiberBundleX::DoColorCodingFaBased() { if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_FA_BASED) != 1 ) return; this->SetColorCoding(COLORCODING_FA_BASED); MITK_DEBUG << "FBX: done CC FA based"; this->GenerateFiberIds(); } void mitk::FiberBundleX::DoUseFaFiberOpacity() { if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_FA_BASED) != 1 ) return; if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_ORIENTATION_BASED) != 1 ) return; vtkDoubleArray* FAValArray = (vtkDoubleArray*) m_FiberPolyData->GetPointData()->GetArray(COLORCODING_FA_BASED); vtkUnsignedCharArray* ColorArray = dynamic_cast (m_FiberPolyData->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED)); for(long i=0; iGetNumberOfTuples(); i++) { double faValue = FAValArray->GetValue(i); faValue = faValue * 255.0; ColorArray->SetComponent(i,3, (unsigned char) faValue ); } this->SetColorCoding(COLORCODING_ORIENTATION_BASED); MITK_DEBUG << "FBX: done CC OPACITY"; this->GenerateFiberIds(); } void mitk::FiberBundleX::ResetFiberOpacity() { vtkUnsignedCharArray* ColorArray = dynamic_cast (m_FiberPolyData->GetPointData()->GetArray(COLORCODING_ORIENTATION_BASED)); if (ColorArray==NULL) return; for(long i=0; iGetNumberOfTuples(); i++) ColorArray->SetComponent(i,3, 255.0 ); } void mitk::FiberBundleX::SetFAMap(mitk::Image::Pointer FAimage) { mitkPixelTypeMultiplex1( SetFAMap, FAimage->GetPixelType(), FAimage ); } template void mitk::FiberBundleX::SetFAMap(const mitk::PixelType pixelType, mitk::Image::Pointer FAimage) { MITK_DEBUG << "SetFAMap"; vtkSmartPointer faValues = vtkSmartPointer::New(); faValues->SetName(COLORCODING_FA_BASED); faValues->Allocate(m_FiberPolyData->GetNumberOfPoints()); faValues->SetNumberOfValues(m_FiberPolyData->GetNumberOfPoints()); mitk::ImagePixelReadAccessor readFAimage (FAimage, FAimage->GetVolumeData(0)); vtkPoints* pointSet = m_FiberPolyData->GetPoints(); for(long i=0; iGetNumberOfPoints(); ++i) { Point3D px; px[0] = pointSet->GetPoint(i)[0]; px[1] = pointSet->GetPoint(i)[1]; px[2] = pointSet->GetPoint(i)[2]; double faPixelValue = 1-readFAimage.GetPixelByWorldCoordinates(px); faValues->InsertValue(i, faPixelValue); } m_FiberPolyData->GetPointData()->AddArray(faValues); this->GenerateFiberIds(); if(m_FiberPolyData->GetPointData()->HasArray(COLORCODING_FA_BASED)) MITK_DEBUG << "FA VALUE ARRAY SET"; } void mitk::FiberBundleX::GenerateFiberIds() { if (m_FiberPolyData == NULL) return; vtkSmartPointer idFiberFilter = vtkSmartPointer::New(); idFiberFilter->SetInputData(m_FiberPolyData); idFiberFilter->CellIdsOn(); // idFiberFilter->PointIdsOn(); // point id's are not needed idFiberFilter->SetIdsArrayName(FIBER_ID_ARRAY); idFiberFilter->FieldDataOn(); idFiberFilter->Update(); m_FiberIdDataSet = idFiberFilter->GetOutput(); MITK_DEBUG << "Generating Fiber Ids...[done] | " << m_FiberIdDataSet->GetNumberOfCells(); } mitk::FiberBundleX::Pointer mitk::FiberBundleX::ExtractFiberSubset(ItkUcharImgType* mask, bool anyPoint) { vtkSmartPointer polyData = m_FiberPolyData; if (anyPoint) { float minSpacing = 1; if(mask->GetSpacing()[0]GetSpacing()[1] && mask->GetSpacing()[0]GetSpacing()[2]) minSpacing = mask->GetSpacing()[0]; else if (mask->GetSpacing()[1] < mask->GetSpacing()[2]) minSpacing = mask->GetSpacing()[1]; else minSpacing = mask->GetSpacing()[2]; mitk::FiberBundleX::Pointer fibCopy = this->GetDeepCopy(); fibCopy->ResampleFibers(minSpacing/10); polyData = fibCopy->GetFiberPolyData(); } vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Extracting fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkCell* cellOriginal = m_FiberPolyData->GetCell(i); int numPointsOriginal = cellOriginal->GetNumberOfPoints(); vtkPoints* pointsOriginal = cellOriginal->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); if (numPoints>1 && numPointsOriginal) { if (anyPoint) { for (int j=0; jGetPoint(j); itk::Point itkP; itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; itk::Index<3> idx; mask->TransformPhysicalPointToIndex(itkP, idx); if ( mask->GetPixel(idx)>0 && mask->GetLargestPossibleRegion().IsInside(idx) ) { for (int k=0; kGetPoint(k); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } break; } } } else { double* start = pointsOriginal->GetPoint(0); itk::Point itkStart; itkStart[0] = start[0]; itkStart[1] = start[1]; itkStart[2] = start[2]; itk::Index<3> idxStart; mask->TransformPhysicalPointToIndex(itkStart, idxStart); double* end = pointsOriginal->GetPoint(numPointsOriginal-1); itk::Point itkEnd; itkEnd[0] = end[0]; itkEnd[1] = end[1]; itkEnd[2] = end[2]; itk::Index<3> idxEnd; mask->TransformPhysicalPointToIndex(itkEnd, idxEnd); if ( mask->GetPixel(idxStart)>0 && mask->GetPixel(idxEnd)>0 && mask->GetLargestPossibleRegion().IsInside(idxStart) && mask->GetLargestPossibleRegion().IsInside(idxEnd) ) { for (int j=0; jGetPoint(j); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } } } } vtkNewCells->InsertNextCell(container); } if (vtkNewCells->GetNumberOfCells()<=0) return NULL; vtkSmartPointer newPolyData = vtkSmartPointer::New(); newPolyData->SetPoints(vtkNewPoints); newPolyData->SetLines(vtkNewCells); return mitk::FiberBundleX::New(newPolyData); } mitk::FiberBundleX::Pointer mitk::FiberBundleX::RemoveFibersOutside(ItkUcharImgType* mask, bool invert) { float minSpacing = 1; if(mask->GetSpacing()[0]GetSpacing()[1] && mask->GetSpacing()[0]GetSpacing()[2]) minSpacing = mask->GetSpacing()[0]; else if (mask->GetSpacing()[1] < mask->GetSpacing()[2]) minSpacing = mask->GetSpacing()[1]; else minSpacing = mask->GetSpacing()[2]; mitk::FiberBundleX::Pointer fibCopy = this->GetDeepCopy(); fibCopy->ResampleFibers(minSpacing/10); vtkSmartPointer polyData =fibCopy->GetFiberPolyData(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Cutting fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); if (numPoints>1) { int newNumPoints = 0; for (int j=0; jGetPoint(j); itk::Point itkP; itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; itk::Index<3> idx; mask->TransformPhysicalPointToIndex(itkP, idx); if ( mask->GetPixel(idx)>0 && mask->GetLargestPossibleRegion().IsInside(idx) && !invert ) { vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); newNumPoints++; } else if ( (mask->GetPixel(idx)<=0 || !mask->GetLargestPossibleRegion().IsInside(idx)) && invert ) { vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); newNumPoints++; } else if (newNumPoints>0) { vtkNewCells->InsertNextCell(container); newNumPoints = 0; container = vtkSmartPointer::New(); } } if (newNumPoints>0) vtkNewCells->InsertNextCell(container); } } if (vtkNewCells->GetNumberOfCells()<=0) return NULL; vtkSmartPointer newPolyData = vtkSmartPointer::New(); newPolyData->SetPoints(vtkNewPoints); newPolyData->SetLines(vtkNewCells); mitk::FiberBundleX::Pointer newFib = mitk::FiberBundleX::New(newPolyData); newFib->ResampleFibers(minSpacing/2); return newFib; } mitk::FiberBundleX::Pointer mitk::FiberBundleX::ExtractFiberSubset(mitk::PlanarFigure* pf) { if (pf==NULL) return NULL; std::vector tmp = ExtractFiberIdSubset(pf); if (tmp.size()<=0) return mitk::FiberBundleX::New(); vtkSmartPointer pTmp = GeneratePolyDataByIds(tmp); return mitk::FiberBundleX::New(pTmp); } std::vector mitk::FiberBundleX::ExtractFiberIdSubset(mitk::PlanarFigure* pf) { MITK_DEBUG << "Extracting fibers!"; // vector which is returned, contains all extracted FiberIds std::vector FibersInROI; if (pf==NULL) return FibersInROI; /* Handle type of planarfigure */ // if incoming pf is a pfc mitk::PlanarFigureComposite::Pointer pfcomp= dynamic_cast(pf); if (!pfcomp.IsNull()) { // process requested boolean operation of PFC switch (pfcomp->getOperationType()) { case 0: { MITK_DEBUG << "AND PROCESSING"; //AND //temporarly store results of the child in this vector, we need that to accumulate the std::vector childResults = this->ExtractFiberIdSubset(pfcomp->getChildAt(0)); MITK_DEBUG << "first roi got fibers in ROI: " << childResults.size(); MITK_DEBUG << "sorting..."; std::sort(childResults.begin(), childResults.end()); MITK_DEBUG << "sorting done"; std::vector AND_Assamblage(childResults.size()); //std::vector AND_Assamblage; fill(AND_Assamblage.begin(), AND_Assamblage.end(), -1); //AND_Assamblage.reserve(childResults.size()); //max size AND can reach anyway std::vector::iterator it; for (int i=1; igetNumberOfChildren(); ++i) { std::vector tmpChild = this->ExtractFiberIdSubset(pfcomp->getChildAt(i)); MITK_DEBUG << "ROI " << i << " has fibers in ROI: " << tmpChild.size(); sort(tmpChild.begin(), tmpChild.end()); it = std::set_intersection(childResults.begin(), childResults.end(), tmpChild.begin(), tmpChild.end(), AND_Assamblage.begin() ); } MITK_DEBUG << "resize Vector"; - long i=0; + unsigned long i=0; while (i < AND_Assamblage.size() && AND_Assamblage[i] != -1){ //-1 represents a placeholder in the array ++i; } AND_Assamblage.resize(i); MITK_DEBUG << "returning AND vector, size: " << AND_Assamblage.size(); return AND_Assamblage; // break; } case 1: { //OR std::vector OR_Assamblage = this->ExtractFiberIdSubset(pfcomp->getChildAt(0)); std::vector::iterator it; MITK_DEBUG << OR_Assamblage.size(); for (int i=1; igetNumberOfChildren(); ++i) { it = OR_Assamblage.end(); std::vector tmpChild = this->ExtractFiberIdSubset(pfcomp->getChildAt(i)); OR_Assamblage.insert(it, tmpChild.begin(), tmpChild.end()); MITK_DEBUG << "ROI " << i << " has fibers in ROI: " << tmpChild.size() << " OR Assamblage: " << OR_Assamblage.size(); } sort(OR_Assamblage.begin(), OR_Assamblage.end()); it = unique(OR_Assamblage.begin(), OR_Assamblage.end()); OR_Assamblage.resize( it - OR_Assamblage.begin() ); MITK_DEBUG << "returning OR vector, size: " << OR_Assamblage.size(); return OR_Assamblage; } case 2: { //NOT //get IDs of all fibers std::vector childResults; childResults.reserve(this->GetNumFibers()); vtkSmartPointer idSet = m_FiberIdDataSet->GetCellData()->GetArray(FIBER_ID_ARRAY); MITK_DEBUG << "m_NumOfFib: " << this->GetNumFibers() << " cellIdNum: " << idSet->GetNumberOfTuples(); for(long i=0; iGetNumFibers(); i++) { MITK_DEBUG << "i: " << i << " idset: " << idSet->GetTuple(i)[0]; childResults.push_back(idSet->GetTuple(i)[0]); } std::sort(childResults.begin(), childResults.end()); std::vector NOT_Assamblage(childResults.size()); //fill it with -1, otherwise 0 will be stored and 0 can also be an ID of fiber! fill(NOT_Assamblage.begin(), NOT_Assamblage.end(), -1); std::vector::iterator it; for (long i=0; igetNumberOfChildren(); ++i) { std::vector tmpChild = ExtractFiberIdSubset(pfcomp->getChildAt(i)); sort(tmpChild.begin(), tmpChild.end()); it = std::set_difference(childResults.begin(), childResults.end(), tmpChild.begin(), tmpChild.end(), NOT_Assamblage.begin() ); } MITK_DEBUG << "resize Vector"; long i=0; while (NOT_Assamblage[i] != -1){ //-1 represents a placeholder in the array ++i; } NOT_Assamblage.resize(i); return NOT_Assamblage; } default: MITK_DEBUG << "we have an UNDEFINED composition... ERROR" ; break; } } else { mitk::Geometry2D::ConstPointer pfgeometry = pf->GetGeometry2D(); const mitk::PlaneGeometry* planeGeometry = dynamic_cast (pfgeometry.GetPointer()); Vector3D planeNormal = planeGeometry->GetNormal(); planeNormal.Normalize(); Point3D planeOrigin = planeGeometry->GetOrigin(); MITK_DEBUG << "planeOrigin: " << planeOrigin[0] << " | " << planeOrigin[1] << " | " << planeOrigin[2] << endl; MITK_DEBUG << "planeNormal: " << planeNormal[0] << " | " << planeNormal[1] << " | " << planeNormal[2] << endl; std::vector PointsOnPlane; // contains all pointIds which are crossing the cutting plane std::vector PointsInROI; // based on PointsOnPlane, all ROI relevant point IDs are stored here /* Define cutting plane by ROI (PlanarFigure) */ vtkSmartPointer plane = vtkSmartPointer::New(); plane->SetOrigin(planeOrigin[0],planeOrigin[1],planeOrigin[2]); plane->SetNormal(planeNormal[0],planeNormal[1],planeNormal[2]); /* get all points/fibers cutting the plane */ MITK_DEBUG << "start clipping"; vtkSmartPointer clipper = vtkSmartPointer::New(); clipper->SetInputData(m_FiberIdDataSet); clipper->SetClipFunction(plane); clipper->GenerateClipScalarsOn(); clipper->GenerateClippedOutputOn(); clipper->Update(); vtkSmartPointer clipperout = clipper->GetClippedOutput(); MITK_DEBUG << "end clipping"; MITK_DEBUG << "init and update clipperoutput"; // clipperout->GetPointData()->Initialize(); // clipperout->Update(); //VTK6_TODO MITK_DEBUG << "init and update clipperoutput completed"; MITK_DEBUG << "STEP 1: find all points which have distance 0 to the given plane"; /*======STEP 1====== * extract all points, which are crossing the plane */ // Scalar values describe the distance between each remaining point to the given plane. Values sorted by point index vtkSmartPointer distanceList = clipperout->GetPointData()->GetScalars(); vtkIdType sizeOfList = distanceList->GetNumberOfTuples(); PointsOnPlane.reserve(sizeOfList); /* use reserve for high-performant push_back, no hidden copy procedures are processed then! * size of list can be optimized by reducing allocation, but be aware of iterator and vector size*/ for (int i=0; iGetTuple(i); // check if point is on plane. // 0.01 due to some approximation errors when calculating distance if (distance[0] >= -0.01 && distance[0] <= 0.01) PointsOnPlane.push_back(i); } MITK_DEBUG << "Num Of points on plane: " << PointsOnPlane.size(); MITK_DEBUG << "Step 2: extract Interesting points with respect to given extraction planarFigure"; PointsInROI.reserve(PointsOnPlane.size()); /*=======STEP 2===== * extract ROI relevant pointIds */ mitk::PlanarCircle::Pointer circleName = mitk::PlanarCircle::New(); mitk::PlanarPolygon::Pointer polyName = mitk::PlanarPolygon::New(); if ( pf->GetNameOfClass() == circleName->GetNameOfClass() ) { //calculate circle radius mitk::Point3D V1w = pf->GetWorldControlPoint(0); //centerPoint mitk::Point3D V2w = pf->GetWorldControlPoint(1); //radiusPoint double distPF = V1w.EuclideanDistanceTo(V2w); - for (int i=0; iGetPoint(PointsOnPlane[i])[0] - V1w[0]) * (clipperout->GetPoint(PointsOnPlane[i])[0] - V1w[0]) + (clipperout->GetPoint(PointsOnPlane[i])[1] - V1w[1]) * (clipperout->GetPoint(PointsOnPlane[i])[1] - V1w[1]) + (clipperout->GetPoint(PointsOnPlane[i])[2] - V1w[2]) * (clipperout->GetPoint(PointsOnPlane[i])[2] - V1w[2])) ; if( XdistPnt <= distPF) PointsInROI.push_back(PointsOnPlane[i]); } } else if ( pf->GetNameOfClass() == polyName->GetNameOfClass() ) { //create vtkPolygon using controlpoints from planarFigure polygon vtkSmartPointer polygonVtk = vtkSmartPointer::New(); //get the control points from pf and insert them to vtkPolygon unsigned int nrCtrlPnts = pf->GetNumberOfControlPoints(); - for (int i=0; iGetPoints()->InsertNextPoint((double)pf->GetWorldControlPoint(i)[0], (double)pf->GetWorldControlPoint(i)[1], (double)pf->GetWorldControlPoint(i)[2] ); } //prepare everything for using pointInPolygon function double n[3]; polygonVtk->ComputeNormal(polygonVtk->GetPoints()->GetNumberOfPoints(), static_cast(polygonVtk->GetPoints()->GetData()->GetVoidPointer(0)), n); double bounds[6]; polygonVtk->GetPoints()->GetBounds(bounds); - for (int i=0; iGetPoint(PointsOnPlane[i])[0], clipperout->GetPoint(PointsOnPlane[i])[1], clipperout->GetPoint(PointsOnPlane[i])[2]}; int isInPolygon = polygonVtk->PointInPolygon(checkIn, polygonVtk->GetPoints()->GetNumberOfPoints() , static_cast(polygonVtk->GetPoints()->GetData()->GetVoidPointer(0)), bounds, n); if( isInPolygon ) PointsInROI.push_back(PointsOnPlane[i]); } } MITK_DEBUG << "Step3: Identify fibers"; // we need to access the fiberId Array, so make sure that this array is available if (!clipperout->GetCellData()->HasArray(FIBER_ID_ARRAY)) { MITK_DEBUG << "ERROR: FiberID array does not exist, no correlation between points and fiberIds possible! Make sure calling GenerateFiberIds()"; return FibersInROI; // FibersInRoi is empty then } if (PointsInROI.size()<=0) return FibersInROI; // prepare a structure where each point id is represented as an indexId. // vector looks like: | pntId | fiberIdx | std::vector< long > pointindexFiberMap; // walk through the whole subline section and create an vector sorted by point index vtkCellArray *clipperlines = clipperout->GetLines(); clipperlines->InitTraversal(); long numOfLineCells = clipperlines->GetNumberOfCells(); long numofClippedPoints = clipperout->GetNumberOfPoints(); pointindexFiberMap.resize(numofClippedPoints); //prepare resulting vector FibersInROI.reserve(PointsInROI.size()); MITK_DEBUG << "\n===== Pointindex based structure initialized ======\n"; // go through resulting "sub"lines which are stored as cells, "i" corresponds to current line id. for (int i=0, ic=0 ; iGetCell(ic, npts, pts); // go through point ids in hosting subline, "j" corresponds to current pointindex in current line i. eg. idx[0]=45; idx[1]=46 for (long j=0; jGetCellData()->GetArray(FIBER_ID_ARRAY)->GetTuple(i)[0] << " to pointId: " << pts[j]; pointindexFiberMap[ pts[j] ] = clipperout->GetCellData()->GetArray(FIBER_ID_ARRAY)->GetTuple(i)[0]; // MITK_DEBUG << "in array: " << pointindexFiberMap[ pts[j] ]; } } MITK_DEBUG << "\n===== Pointindex based structure finalized ======\n"; // get all Points in ROI with according fiberID - for (long k = 0; k < PointsInROI.size(); k++) + for (unsigned long k = 0; k < PointsInROI.size(); k++) { //MITK_DEBUG << "point " << PointsInROI[k] << " belongs to fiber " << pointindexFiberMap[ PointsInROI[k] ]; if (pointindexFiberMap[ PointsInROI[k] ]<=GetNumFibers() && pointindexFiberMap[ PointsInROI[k] ]>=0) FibersInROI.push_back(pointindexFiberMap[ PointsInROI[k] ]); else MITK_INFO << "ERROR in ExtractFiberIdSubset; impossible fiber id detected"; } m_PointsRoi = PointsInROI; } // detecting fiberId duplicates MITK_DEBUG << "check for duplicates"; sort(FibersInROI.begin(), FibersInROI.end()); bool hasDuplicats = false; - for(long i=0; i::iterator it; it = unique (FibersInROI.begin(), FibersInROI.end()); FibersInROI.resize( it - FibersInROI.begin() ); } return FibersInROI; } void mitk::FiberBundleX::UpdateFiberGeometry() { vtkSmartPointer cleaner = vtkSmartPointer::New(); cleaner->SetInputData(m_FiberPolyData); cleaner->PointMergingOff(); cleaner->Update(); m_FiberPolyData = cleaner->GetOutput(); m_FiberLengths.clear(); m_MeanFiberLength = 0; m_MedianFiberLength = 0; m_LengthStDev = 0; m_NumFibers = m_FiberPolyData->GetNumberOfCells(); if (m_NumFibers<=0) // no fibers present; apply default geometry { m_MinFiberLength = 0; m_MaxFiberLength = 0; mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetImageGeometry(true); float b[] = {0, 1, 0, 1, 0, 1}; geometry->SetFloatBounds(b); SetGeometry(geometry); return; } float min = itk::NumericTraits::NonpositiveMin(); float max = itk::NumericTraits::max(); float b[] = {max, min, max, min, max, min}; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int p = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); float length = 0; for (int j=0; jGetPoint(j, p1); if (p1[0]b[1]) b[1]=p1[0]; if (p1[1]b[3]) b[3]=p1[1]; if (p1[2]b[5]) b[5]=p1[2]; // calculate statistics if (jGetPoint(j+1, p2); float dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); length += dist; } } m_FiberLengths.push_back(length); m_MeanFiberLength += length; if (i==0) { m_MinFiberLength = length; m_MaxFiberLength = length; } else { if (lengthm_MaxFiberLength) m_MaxFiberLength = length; } } m_MeanFiberLength /= m_NumFibers; std::vector< float > sortedLengths = m_FiberLengths; std::sort(sortedLengths.begin(), sortedLengths.end()); for (int i=0; i1) m_LengthStDev /= (m_NumFibers-1); else m_LengthStDev = 0; m_LengthStDev = std::sqrt(m_LengthStDev); m_MedianFiberLength = sortedLengths.at(m_NumFibers/2); // provide some border margin for(int i=0; i<=4; i+=2) b[i] -=10; for(int i=1; i<=5; i+=2) b[i] +=10; mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetFloatBounds(b); this->SetGeometry(geometry); } std::vector mitk::FiberBundleX::GetAvailableColorCodings() { std::vector availableColorCodings; int numColors = m_FiberPolyData->GetPointData()->GetNumberOfArrays(); for(int i=0; iGetPointData()->GetArrayName(i)); } //this controlstructure shall be implemented by the calling method if (availableColorCodings.empty()) MITK_DEBUG << "no colorcodings available in fiberbundleX"; return availableColorCodings; } char* mitk::FiberBundleX::GetCurrentColorCoding() { return m_CurrentColorCoding; } void mitk::FiberBundleX::SetColorCoding(const char* requestedColorCoding) { if (requestedColorCoding==NULL) return; MITK_DEBUG << "SetColorCoding:" << requestedColorCoding; if( strcmp (COLORCODING_ORIENTATION_BASED,requestedColorCoding) == 0 ) { this->m_CurrentColorCoding = (char*) COLORCODING_ORIENTATION_BASED; } else if( strcmp (COLORCODING_FA_BASED,requestedColorCoding) == 0 ) { this->m_CurrentColorCoding = (char*) COLORCODING_FA_BASED; } else if( strcmp (COLORCODING_CUSTOM,requestedColorCoding) == 0 ) { this->m_CurrentColorCoding = (char*) COLORCODING_CUSTOM; } else { MITK_DEBUG << "FIBERBUNDLE X: UNKNOWN COLORCODING in FIBERBUNDLEX Datastructure"; this->m_CurrentColorCoding = (char*) COLORCODING_CUSTOM; //will cause blank colorcoding of fibers } } itk::Matrix< double, 3, 3 > mitk::FiberBundleX::TransformMatrix(itk::Matrix< double, 3, 3 > m, double rx, double ry, double rz) { rx = rx*M_PI/180; ry = ry*M_PI/180; rz = rz*M_PI/180; itk::Matrix< double, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; itk::Matrix< double, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; itk::Matrix< double, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< double, 3, 3 > rot = rotZ*rotY*rotX; m = rot*m; return m; } itk::Point mitk::FiberBundleX::TransformPoint(vnl_vector_fixed< double, 3 > point, double rx, double ry, double rz, double tx, double ty, double tz) { rx = rx*M_PI/180; ry = ry*M_PI/180; rz = rz*M_PI/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; vnl_matrix_fixed< double, 3, 3 > rot = rotZ*rotY*rotX; mitk::Geometry3D::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); point[0] -= center[0]; point[1] -= center[1]; point[2] -= center[2]; point = rot*point; point[0] += center[0]+tx; point[1] += center[1]+ty; point[2] += center[2]+tz; itk::Point out; out[0] = point[0]; out[1] = point[1]; out[2] = point[2]; return out; } void mitk::FiberBundleX::TransformFibers(double rx, double ry, double rz, double tx, double ty, double tz) { rx = rx*M_PI/180; ry = ry*M_PI/180; rz = rz*M_PI/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; vnl_matrix_fixed< double, 3, 3 > rot = rotZ*rotY*rotX; mitk::Geometry3D::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vnl_vector_fixed< double, 3 > dir; dir[0] = p[0]-center[0]; dir[1] = p[1]-center[1]; dir[2] = p[2]-center[2]; dir = rot*dir; dir[0] += center[0]+tx; dir[1] += center[1]+ty; dir[2] += center[2]+tz; vtkIdType id = vtkNewPoints->InsertNextPoint(dir.data_block()); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); } void mitk::FiberBundleX::RotateAroundAxis(double x, double y, double z) { x = x*M_PI/180; y = y*M_PI/180; z = z*M_PI/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; mitk::Geometry3D::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vnl_vector_fixed< double, 3 > dir; dir[0] = p[0]-center[0]; dir[1] = p[1]-center[1]; dir[2] = p[2]-center[2]; dir = rotZ*rotY*rotX*dir; dir[0] += center[0]; dir[1] += center[1]; dir[2] += center[2]; vtkIdType id = vtkNewPoints->InsertNextPoint(dir.data_block()); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); } void mitk::FiberBundleX::ScaleFibers(double x, double y, double z) { MITK_INFO << "Scaling fibers"; boost::progress_display disp(m_NumFibers); mitk::Geometry3D* geom = this->GetGeometry(); mitk::Point3D c = geom->GetCenter(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); p[0] -= c[0]; p[1] -= c[1]; p[2] -= c[2]; p[0] *= x; p[1] *= y; p[2] *= z; p[0] += c[0]; p[1] += c[1]; p[2] += c[2]; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); } void mitk::FiberBundleX::TranslateFibers(double x, double y, double z) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); p[0] += x; p[1] += y; p[2] += z; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); } void mitk::FiberBundleX::MirrorFibers(unsigned int axis) { if (axis>2) return; MITK_INFO << "Mirroring fibers"; boost::progress_display disp(m_NumFibers); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); p[axis] = -p[axis]; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); } bool mitk::FiberBundleX::ApplyCurvatureThreshold(float minRadius, bool deleteFibers) { if (minRadius<0) return true; vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Applying curvature threshold"; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); for (int i=0; iGetNumberOfCells(); i++) { ++disp ; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); // calculate curvatures vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p1); double p2[3]; points->GetPoint(j+1, p2); double p3[3]; points->GetPoint(j+2, p3); vnl_vector_fixed< float, 3 > v1, v2, v3; v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; v2[0] = p3[0]-p2[0]; v2[1] = p3[1]-p2[1]; v2[2] = p3[2]-p2[2]; v3[0] = p1[0]-p3[0]; v3[1] = p1[1]-p3[1]; v3[2] = p1[2]-p3[2]; float a = v1.magnitude(); float b = v2.magnitude(); float c = v3.magnitude(); float r = a*b*c/std::sqrt((a+b+c)*(a+b-c)*(b+c-a)*(a-b+c)); // radius of triangle via Heron's formula (area of triangle) vtkIdType id = vtkNewPoints->InsertNextPoint(p1); container->GetPointIds()->InsertNextId(id); if (deleteFibers && rInsertNextCell(container); container = vtkSmartPointer::New(); } else if (j==numPoints-3) { id = vtkNewPoints->InsertNextPoint(p2); container->GetPointIds()->InsertNextId(id); id = vtkNewPoints->InsertNextPoint(p3); container->GetPointIds()->InsertNextId(id); vtkNewCells->InsertNextCell(container); } } } if (vtkNewCells->GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); return true; } bool mitk::FiberBundleX::RemoveShortFibers(float lengthInMM) { MITK_INFO << "Removing short fibers"; if (lengthInMM<=0 || lengthInMMm_MaxFiberLength) // can't remove all fibers { MITK_WARN << "Process aborted. No fibers would be left!"; return false; } vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); float min = m_MaxFiberLength; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (m_FiberLengths.at(i)>=lengthInMM) { vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); if (m_FiberLengths.at(i)GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); return true; } bool mitk::FiberBundleX::RemoveLongFibers(float lengthInMM) { if (lengthInMM<=0 || lengthInMM>m_MaxFiberLength) return true; if (lengthInMM vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Removing long fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (m_FiberLengths.at(i)<=lengthInMM) { vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } } if (vtkNewCells->GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); UpdateColorCoding(); UpdateFiberGeometry(); return true; } void mitk::FiberBundleX::DoFiberSmoothing(float pointDistance, double tension, double continuity, double bias ) { if (pointDistance<=0) return; vtkSmartPointer vtkSmoothPoints = vtkSmartPointer::New(); //in smoothpoints the interpolated points representing a fiber are stored. //in vtkcells all polylines are stored, actually all id's of them are stored vtkSmartPointer vtkSmoothCells = vtkSmartPointer::New(); //cellcontainer for smoothed lines vtkIdType pointHelperCnt = 0; MITK_INFO << "Smoothing fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer newPoints = vtkSmartPointer::New(); for (int j=0; jInsertNextPoint(points->GetPoint(j)); float length = m_FiberLengths.at(i); int sampling = std::ceil(length/pointDistance); vtkSmartPointer xSpline = vtkSmartPointer::New(); vtkSmartPointer ySpline = vtkSmartPointer::New(); vtkSmartPointer zSpline = vtkSmartPointer::New(); xSpline->SetDefaultBias(bias); xSpline->SetDefaultTension(tension); xSpline->SetDefaultContinuity(continuity); ySpline->SetDefaultBias(bias); ySpline->SetDefaultTension(tension); ySpline->SetDefaultContinuity(continuity); zSpline->SetDefaultBias(bias); zSpline->SetDefaultTension(tension); zSpline->SetDefaultContinuity(continuity); vtkSmartPointer spline = vtkSmartPointer::New(); spline->SetXSpline(xSpline); spline->SetYSpline(ySpline); spline->SetZSpline(zSpline); spline->SetPoints(newPoints); vtkSmartPointer functionSource = vtkSmartPointer::New(); functionSource->SetParametricFunction(spline); functionSource->SetUResolution(sampling); functionSource->SetVResolution(sampling); functionSource->SetWResolution(sampling); functionSource->Update(); vtkPolyData* outputFunction = functionSource->GetOutput(); vtkPoints* tmpSmoothPnts = outputFunction->GetPoints(); //smoothPoints of current fiber vtkSmartPointer smoothLine = vtkSmartPointer::New(); smoothLine->GetPointIds()->SetNumberOfIds(tmpSmoothPnts->GetNumberOfPoints()); for (int j=0; jGetNumberOfPoints(); j++) { smoothLine->GetPointIds()->SetId(j, j+pointHelperCnt); vtkSmoothPoints->InsertNextPoint(tmpSmoothPnts->GetPoint(j)); } vtkSmoothCells->InsertNextCell(smoothLine); pointHelperCnt += tmpSmoothPnts->GetNumberOfPoints(); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkSmoothPoints); m_FiberPolyData->SetLines(vtkSmoothCells); UpdateColorCoding(); UpdateFiberGeometry(); m_FiberSampling = 10/pointDistance; } void mitk::FiberBundleX::DoFiberSmoothing(float pointDistance) { DoFiberSmoothing(pointDistance, 0, 0, 0 ); } // Resample fiber to get equidistant points void mitk::FiberBundleX::ResampleFibers(float pointDistance) { if (pointDistance<=0.00001) return; vtkSmartPointer newPoly = vtkSmartPointer::New(); vtkSmartPointer newCellArray = vtkSmartPointer::New(); vtkSmartPointer newPoints = vtkSmartPointer::New(); int numberOfLines = m_NumFibers; MITK_INFO << "Resampling fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); double* point = points->GetPoint(0); vtkIdType pointId = newPoints->InsertNextPoint(point); container->GetPointIds()->InsertNextId(pointId); float dtau = 0; int cur_p = 1; itk::Vector dR; float normdR = 0; for (;;) { while (dtau <= pointDistance && cur_p < numPoints) { itk::Vector v1; point = points->GetPoint(cur_p-1); v1[0] = point[0]; v1[1] = point[1]; v1[2] = point[2]; itk::Vector v2; point = points->GetPoint(cur_p); v2[0] = point[0]; v2[1] = point[1]; v2[2] = point[2]; dR = v2 - v1; normdR = std::sqrt(dR.GetSquaredNorm()); dtau += normdR; cur_p++; } if (dtau >= pointDistance) { itk::Vector v1; point = points->GetPoint(cur_p-1); v1[0] = point[0]; v1[1] = point[1]; v1[2] = point[2]; itk::Vector v2 = v1 - dR*( (dtau-pointDistance)/normdR ); pointId = newPoints->InsertNextPoint(v2.GetDataPointer()); container->GetPointIds()->InsertNextId(pointId); } else { point = points->GetPoint(numPoints-1); pointId = newPoints->InsertNextPoint(point); container->GetPointIds()->InsertNextId(pointId); break; } dtau = dtau-pointDistance; } newCellArray->InsertNextCell(container); } newPoly->SetPoints(newPoints); newPoly->SetLines(newCellArray); m_FiberPolyData = newPoly; UpdateFiberGeometry(); UpdateColorCoding(); m_FiberSampling = 10/pointDistance; } // reapply selected colorcoding in case polydata structure has changed void mitk::FiberBundleX::UpdateColorCoding() { char* cc = GetCurrentColorCoding(); if( strcmp (COLORCODING_ORIENTATION_BASED,cc) == 0 ) DoColorCodingOrientationBased(); else if( strcmp (COLORCODING_FA_BASED,cc) == 0 ) DoColorCodingFaBased(); } // reapply selected colorcoding in case polydata structure has changed bool mitk::FiberBundleX::Equals(mitk::FiberBundleX* fib, double eps) { if (fib==NULL) { MITK_INFO << "Reference bundle is NULL!"; return false; } if (m_NumFibers!=fib->GetNumFibers()) { MITK_INFO << "Unequal number of fibers!"; MITK_INFO << m_NumFibers << " vs. " << fib->GetNumFibers(); return false; } for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkCell* cell2 = fib->GetFiberPolyData()->GetCell(i); int numPoints2 = cell2->GetNumberOfPoints(); vtkPoints* points2 = cell2->GetPoints(); if (numPoints2!=numPoints) { MITK_INFO << "Unequal number of points in fiber " << i << "!"; MITK_INFO << numPoints2 << " vs. " << numPoints; return false; } for (int j=0; jGetPoint(j); double* p2 = points2->GetPoint(j); if (fabs(p1[0]-p2[0])>eps || fabs(p1[1]-p2[1])>eps || fabs(p1[2]-p2[2])>eps) { MITK_INFO << "Unequal points in fiber " << i << " at position " << j << "!"; MITK_INFO << "p1: " << p1[0] << ", " << p1[1] << ", " << p1[2]; MITK_INFO << "p2: " << p2[0] << ", " << p2[1] << ", " << p2[2]; return false; } } } return true; } /* ESSENTIAL IMPLEMENTATION OF SUPERCLASS METHODS */ void mitk::FiberBundleX::UpdateOutputInformation() { } void mitk::FiberBundleX::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::FiberBundleX::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::FiberBundleX::VerifyRequestedRegion() { return true; } void mitk::FiberBundleX::SetRequestedRegion(const itk::DataObject *data ) { } diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleXReader.cpp b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleXReader.cpp index fc2f358815..527341766a 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleXReader.cpp +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundleX/mitkFiberBundleXReader.cpp @@ -1,302 +1,302 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkFiberBundleXReader.h" #include #include #include #include #include #include #include #include #include #include #include namespace mitk { void FiberBundleXReader ::GenerateData() { if ( ( ! m_OutputCache ) ) { Superclass::SetNumberOfRequiredOutputs(0); this->GenerateOutputInformation(); } if (!m_OutputCache) { itkWarningMacro("Output cache is empty!"); } Superclass::SetNumberOfRequiredOutputs(1); Superclass::SetNthOutput(0, m_OutputCache.GetPointer()); } void FiberBundleXReader::GenerateOutputInformation() { try { const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, NULL ); setlocale(LC_ALL, locale.c_str()); std::string ext = itksys::SystemTools::GetFilenameLastExtension(m_FileName); ext = itksys::SystemTools::LowerCase(ext); if (ext==".trk") { MITK_INFO << "Importing fiber bundle from TrackVis ..."; m_OutputCache = OutputType::New(); TrackVis trk; trk.open(m_FileName); trk.read(m_OutputCache); MITK_INFO << "... done"; return; } vtkSmartPointer chooser=vtkSmartPointer::New(); chooser->SetFileName(m_FileName.c_str() ); if( chooser->IsFilePolyData()) { MITK_INFO << "Reading vtk fiber bundle"; vtkSmartPointer reader = vtkSmartPointer::New(); reader->SetFileName( m_FileName.c_str() ); reader->Update(); if ( reader->GetOutput() != NULL ) { vtkSmartPointer fiberPolyData = reader->GetOutput(); m_OutputCache = OutputType::New(fiberPolyData); } } else // try to read deprecated fiber bundle file format { MITK_INFO << "Reading xml fiber bundle"; vtkSmartPointer fiberPolyData = vtkSmartPointer::New(); vtkSmartPointer cellArray = vtkSmartPointer::New(); vtkSmartPointer points = vtkSmartPointer::New(); TiXmlDocument doc( m_FileName ); if(doc.LoadFile()) { TiXmlHandle hDoc(&doc); TiXmlElement* pElem; TiXmlHandle hRoot(0); pElem = hDoc.FirstChildElement().Element(); // save this for later hRoot = TiXmlHandle(pElem); pElem = hRoot.FirstChildElement("geometry").Element(); // read geometry mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); // read origin mitk::Point3D origin; double temp = 0; pElem->Attribute("origin_x", &temp); origin[0] = temp; pElem->Attribute("origin_y", &temp); origin[1] = temp; pElem->Attribute("origin_z", &temp); origin[2] = temp; geometry->SetOrigin(origin); // read spacing ScalarType spacing[3]; pElem->Attribute("spacing_x", &temp); spacing[0] = temp; pElem->Attribute("spacing_y", &temp); spacing[1] = temp; pElem->Attribute("spacing_z", &temp); spacing[2] = temp; geometry->SetSpacing(spacing); // read transform vtkMatrix4x4* m = vtkMatrix4x4::New(); pElem->Attribute("xx", &temp); m->SetElement(0,0,temp); pElem->Attribute("xy", &temp); m->SetElement(1,0,temp); pElem->Attribute("xz", &temp); m->SetElement(2,0,temp); pElem->Attribute("yx", &temp); m->SetElement(0,1,temp); pElem->Attribute("yy", &temp); m->SetElement(1,1,temp); pElem->Attribute("yz", &temp); m->SetElement(2,1,temp); pElem->Attribute("zx", &temp); m->SetElement(0,2,temp); pElem->Attribute("zy", &temp); m->SetElement(1,2,temp); pElem->Attribute("zz", &temp); m->SetElement(2,2,temp); m->SetElement(0,3,origin[0]); m->SetElement(1,3,origin[1]); m->SetElement(2,3,origin[2]); m->SetElement(3,3,1); geometry->SetIndexToWorldTransformByVtkMatrix(m); // read bounds float bounds[] = {0, 0, 0, 0, 0, 0}; pElem->Attribute("size_x", &temp); bounds[1] = temp; pElem->Attribute("size_y", &temp); bounds[3] = temp; pElem->Attribute("size_z", &temp); bounds[5] = temp; geometry->SetFloatBounds(bounds); geometry->SetImageGeometry(true); pElem = hRoot.FirstChildElement("fiber_bundle").FirstChild().Element(); - for( pElem; pElem; pElem=pElem->NextSiblingElement()) + for( ; pElem ; pElem=pElem->NextSiblingElement()) { TiXmlElement* pElem2 = pElem->FirstChildElement(); vtkSmartPointer container = vtkSmartPointer::New(); - for( pElem2; pElem2; pElem2=pElem2->NextSiblingElement()) + for( ; pElem2; pElem2=pElem2->NextSiblingElement()) { Point3D point; pElem2->Attribute("pos_x", &temp); point[0] = temp; pElem2->Attribute("pos_y", &temp); point[1] = temp; pElem2->Attribute("pos_z", &temp); point[2] = temp; geometry->IndexToWorld(point, point); vtkIdType id = points->InsertNextPoint(point.GetDataPointer()); container->GetPointIds()->InsertNextId(id); } cellArray->InsertNextCell(container); } fiberPolyData->SetPoints(points); fiberPolyData->SetLines(cellArray); vtkSmartPointer cleaner = vtkSmartPointer::New(); cleaner->SetInputData(fiberPolyData); cleaner->Update(); fiberPolyData = cleaner->GetOutput(); m_OutputCache = OutputType::New(fiberPolyData); } else { MITK_INFO << "could not open xml file"; throw "could not open xml file"; } } setlocale(LC_ALL, currLocale.c_str()); MITK_INFO << "Fiber bundle read"; } catch(...) { throw; } } void FiberBundleXReader::Update() { this->GenerateData(); } const char* FiberBundleXReader ::GetFileName() const { return m_FileName.c_str(); } void FiberBundleXReader ::SetFileName(const char* aFileName) { m_FileName = aFileName; } const char* FiberBundleXReader ::GetFilePrefix() const { return m_FilePrefix.c_str(); } void FiberBundleXReader ::SetFilePrefix(const char* aFilePrefix) { m_FilePrefix = aFilePrefix; } const char* FiberBundleXReader ::GetFilePattern() const { return m_FilePattern.c_str(); } void FiberBundleXReader ::SetFilePattern(const char* aFilePattern) { m_FilePattern = aFilePattern; } bool FiberBundleXReader ::CanReadFile(const std::string filename, const std::string /*filePrefix*/, const std::string /*filePattern*/) { // First check the extension if( filename == "" ) { return false; } std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename); ext = itksys::SystemTools::LowerCase(ext); if (ext == ".fib" || ext == ".trk") { return true; } return false; } BaseDataSource::DataObjectPointer FiberBundleXReader::MakeOutput(const DataObjectIdentifierType &name) { itkDebugMacro("MakeOutput(" << name << ")"); if( this->IsIndexedOutputName(name) ) { return this->MakeOutput( this->MakeIndexFromOutputName(name) ); } return static_cast(OutputType::New().GetPointer()); } BaseDataSource::DataObjectPointer FiberBundleXReader::MakeOutput(DataObjectPointerArraySizeType /*idx*/) { return OutputType::New().GetPointer(); } } //namespace MITK diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.cpp b/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.cpp index 425c2b9952..735fa45f7f 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.cpp +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.cpp @@ -1,121 +1,121 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include using namespace mitk; FiberfoxParameters::FiberfoxParameters() - : m_AddGibbsRinging(false) - , m_ArtifactModelString("") - , m_AxonRadius(0) + : m_NumGradients(6) , m_Bvalue(1000) - , m_Comp3Weight(1) - , m_Comp4Weight(0) - , m_DoAddMotion(false) - , m_DoDisablePartialVolume(false) - , m_DoSimulateEddyCurrents(false) - , m_DoSimulateRelaxation(true) - , m_EddyStrength(0) - , m_InterpolationShrink(0) - , m_KspaceLineOffset(0) - , m_NumGradients(6) - , m_OutputPath("") - , m_RandomMotion(true) , m_Repetitions(1) - , m_SignalModelString("") , m_SignalScale(100) - , m_SpikeAmplitude(1) - , m_Spikes(0) , m_tEcho(100) - , m_tInhom(50) , m_tLine(1) + , m_tInhom(50) + , m_AxonRadius(0) + , m_InterpolationShrink(0) + , m_KspaceLineOffset(0) + , m_AddGibbsRinging(false) + , m_EddyStrength(0) + , m_Comp3Weight(1) + , m_Comp4Weight(0) + , m_Spikes(0) + , m_SpikeAmplitude(1) , m_Wrap(1) - , m_MaskImage(NULL) - , m_FrequencyMap(NULL) + , m_DoSimulateRelaxation(true) + , m_DoSimulateEddyCurrents(false) + , m_DoDisablePartialVolume(false) + , m_DoAddMotion(false) + , m_RandomMotion(true) , m_NoiseModel(NULL) , m_NoiseModelShort(NULL) + , m_FrequencyMap(NULL) + , m_MaskImage(NULL) + , m_SignalModelString("") + , m_ArtifactModelString("") + , m_OutputPath("") { m_ImageDirection.SetIdentity(); m_ImageOrigin.Fill(0.0); m_ImageRegion.SetSize(0, 11); m_ImageRegion.SetSize(1, 11); m_ImageRegion.SetSize(2, 3); m_ImageSpacing.Fill(2.0); m_Translation.Fill(0.0); m_Rotation.Fill(0.0); m_ResultNode = mitk::DataNode::New(); m_ParentNode = NULL; } FiberfoxParameters::~FiberfoxParameters() { // if (m_NoiseModel!=NULL) // delete m_NoiseModel; // if (m_NoiseModelShort!=NULL) // delete m_NoiseModelShort; } void FiberfoxParameters::PrintSelf() { MITK_INFO << m_ImageRegion; MITK_INFO << m_ImageSpacing; MITK_INFO << m_ImageOrigin; MITK_INFO << m_ImageDirection; MITK_INFO << m_NumGradients; MITK_INFO << m_Bvalue; MITK_INFO << m_Repetitions; MITK_INFO << m_SignalScale; MITK_INFO << m_tEcho; MITK_INFO << m_tLine; MITK_INFO << m_tInhom; MITK_INFO << m_AxonRadius; MITK_INFO << m_InterpolationShrink; MITK_INFO << m_KspaceLineOffset; MITK_INFO << m_AddGibbsRinging; MITK_INFO << m_EddyStrength; MITK_INFO << m_Comp3Weight; MITK_INFO << m_Comp4Weight; MITK_INFO << m_Spikes; MITK_INFO << m_SpikeAmplitude; MITK_INFO << m_Wrap; MITK_INFO << m_Translation; MITK_INFO << m_Rotation; MITK_INFO << m_DoSimulateRelaxation; MITK_INFO << m_DoSimulateEddyCurrents; MITK_INFO << m_DoDisablePartialVolume; MITK_INFO << m_DoAddMotion; MITK_INFO << "m_RandomMotion " << m_RandomMotion; MITK_INFO << m_NoiseModel; MITK_INFO << m_NoiseModelShort; // MITK_INFO << m_GradientDirections; // MITK_INFO << m_FiberModelList; // MITK_INFO << m_NonFiberModelList; if (m_FrequencyMap.IsNotNull()) MITK_INFO << "m_FrequencyMap " << m_FrequencyMap; if (m_MaskImage.IsNotNull()) MITK_INFO << "m_MaskImage " << m_MaskImage; if (m_ResultNode.IsNotNull()) MITK_INFO << "m_ResultNode " << m_ResultNode; if (m_ParentNode.IsNotNull()) MITK_INFO << "m_ParentNode " << m_ParentNode; MITK_INFO << m_SignalModelString; MITK_INFO << m_ArtifactModelString; MITK_INFO << m_OutputPath; } diff --git a/Modules/DiffusionImaging/FiberTracking/Interactions/mitkFiberBundleInteractor.cpp b/Modules/DiffusionImaging/FiberTracking/Interactions/mitkFiberBundleInteractor.cpp index 7ed8619e19..29096f44b0 100644 --- a/Modules/DiffusionImaging/FiberTracking/Interactions/mitkFiberBundleInteractor.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Interactions/mitkFiberBundleInteractor.cpp @@ -1,274 +1,240 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkFiberBundleInteractor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkBaseRenderer.h" #include #include #include #include #include #include // #include mitk::FiberBundleInteractor::FiberBundleInteractor(const char * type, DataNode* dataNode) : Interactor(type, dataNode), m_LastPosition(0) { m_LastPoint.Fill(0); } mitk::FiberBundleInteractor::~FiberBundleInteractor() {} void mitk::FiberBundleInteractor::SelectFiber(int position) { MITK_INFO << "mitk::FiberBundleInteractor::SelectFiber " << position; mitk::PointSet* pointSet = dynamic_cast(m_DataNode->GetData()); if (pointSet == NULL) return; if (pointSet->GetSize()<=0)//if List is empty, then no select of a point can be done! return; mitk::Point3D noPoint;//dummyPoint... not needed anyway noPoint.Fill(0); mitk::PointOperation* doOp = new mitk::PointOperation(OpSELECTPOINT, noPoint, position); if (m_UndoEnabled) { mitk::PointOperation* undoOp = new mitk::PointOperation(OpDESELECTPOINT, noPoint, position); OperationEvent *operationEvent = new OperationEvent(pointSet, doOp, undoOp); m_UndoController->SetOperationEvent(operationEvent); } pointSet->ExecuteOperation(doOp); } void mitk::FiberBundleInteractor::DeselectAllFibers() { MITK_INFO << "mitk::FiberBundleInteractor::DeselectAllFibers "; mitk::PointSet* pointSet = dynamic_cast(m_DataNode->GetData()); if (pointSet == NULL) return; mitk::PointSet::DataType *itkPointSet = pointSet->GetPointSet(); mitk::PointSet::PointsContainer::Iterator it, end; end = itkPointSet->GetPoints()->End(); for (it = itkPointSet->GetPoints()->Begin(); it != end; it++) { int position = it->Index(); PointSet::PointDataType pointData = {0, false, PTUNDEFINED}; itkPointSet->GetPointData(position, &pointData); if ( pointData.selected )//then declare an operation which unselects this point; UndoOperation as well! { mitk::Point3D noPoint; noPoint.Fill(0); mitk::PointOperation* doOp = new mitk::PointOperation(OpDESELECTPOINT, noPoint, position); if (m_UndoEnabled) { mitk::PointOperation* undoOp = new mitk::PointOperation(OpSELECTPOINT, noPoint, position); OperationEvent *operationEvent = new OperationEvent(pointSet, doOp, undoOp); m_UndoController->SetOperationEvent(operationEvent); } pointSet->ExecuteOperation(doOp); } } } float mitk::FiberBundleInteractor::CanHandleEvent(StateEvent const* stateEvent) const //go through all points and check, if the given Point lies near a line { - float returnValue = 0; mitk::PositionEvent const *posEvent = dynamic_cast (stateEvent->GetEvent()); //checking if a keyevent can be handled: if (posEvent == NULL) { //check, if the current state has a transition waiting for that key event. if (this->GetCurrentState()->GetTransition(stateEvent->GetId())!=NULL) { return 0.5; } else { return 0; } } //Mouse event handling: //on MouseMove do nothing! reimplement if needed differently if (stateEvent->GetEvent()->GetType() == mitk::Type_MouseMove) { return 0; } - //if the event can be understood and if there is a transition waiting for that event - if (this->GetCurrentState()->GetTransition(stateEvent->GetId())!=NULL) - { - returnValue = 0.5;//it can be understood - } - //check on the right data-type mitk::FiberBundleX* bundle = dynamic_cast(m_DataNode->GetData()); if (bundle == NULL) return 0; return 0.5; } bool mitk::FiberBundleInteractor::ExecuteAction( Action* action, mitk::StateEvent const* stateEvent ) { bool ok = false;//for return type bool //checking corresponding Data; has to be a PointSet or a subclass mitk::FiberBundleX* bundle = dynamic_cast(m_DataNode->GetData()); if (bundle == NULL) return false; // Get Event and extract renderer - const Event *event = stateEvent->GetEvent(); - BaseRenderer *renderer = NULL; - vtkRenderWindow *renderWindow = NULL; vtkRenderWindowInteractor *renderWindowInteractor = NULL; - vtkRenderer *currentVtkRenderer = NULL; - vtkCamera *camera = NULL; - - if ( event != NULL ) - { - renderer = event->GetSender(); - if ( renderer != NULL ) - { - renderWindow = renderer->GetRenderWindow(); - if ( renderWindow != NULL ) - { - renderWindowInteractor = renderWindow->GetInteractor(); - if ( renderWindowInteractor != NULL ) - { - currentVtkRenderer = renderWindowInteractor - ->GetInteractorStyle()->GetCurrentRenderer(); - if ( currentVtkRenderer != NULL ) - { - camera = currentVtkRenderer->GetActiveCamera(); - } - } - } - } - } /*Each case must watch the type of the event!*/ switch (action->GetActionId()) { case AcCHECKHOVERING: { // QApplication::restoreOverrideCursor(); // Re-enable VTK interactor (may have been disabled previously) if ( renderWindowInteractor != NULL ) { renderWindowInteractor->Enable(); } const DisplayPositionEvent *dpe = dynamic_cast< const DisplayPositionEvent * >( stateEvent->GetEvent() ); // Check if we have a DisplayPositionEvent if ( dpe != NULL ) { // Check if an object is present at the current mouse position DataNode *pickedNode = dpe->GetPickedObjectNode(); if ( pickedNode != m_DataNode ) { // if(pickedNode == 0) // MITK_INFO << "picked node is NULL, no hovering"; // else // MITK_INFO << "wrong node: " << pickedNode; this->HandleEvent( new StateEvent( EIDNOFIGUREHOVER ) ); ok = true; break; } m_CurrentPickedPoint = dpe->GetWorldPosition(); m_CurrentPickedDisplayPoint = dpe->GetDisplayPosition(); // QApplication::setOverrideCursor(Qt::UpArrowCursor); this->HandleEvent( new StateEvent( EIDFIGUREHOVER ) ); } ok = true; break; } break; // case AcSELECTPICKEDOBJECT: // MITK_INFO << "FiberBundleInteractor AcSELECTPICKEDOBJECT"; // break; // case AcDESELECTALL: // MITK_INFO << "FiberBundleInteractor AcDESELECTALL"; // break; case AcREMOVE: { MITK_INFO << "picking fiber at " << m_CurrentPickedPoint; // QmitkStdMultiWidgetEditor::Pointer multiWidgetEditor; // multiWidgetEditor->GetStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetSliceNavigationController()->SelectSliceByPoint( // m_CurrentPickedPoint); BaseRenderer* renderer = mitk::BaseRenderer::GetByName("stdmulti.widget1"); renderer->GetSliceNavigationController()->SelectSliceByPoint( m_CurrentPickedPoint); renderer = mitk::BaseRenderer::GetByName("stdmulti.widget2"); renderer->GetSliceNavigationController()->SelectSliceByPoint( m_CurrentPickedPoint); renderer = mitk::BaseRenderer::GetByName("stdmulti.widget3"); renderer->GetSliceNavigationController()->SelectSliceByPoint( m_CurrentPickedPoint); // mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } break; default: return Superclass::ExecuteAction( action, stateEvent ); } return ok; } diff --git a/Modules/DiffusionImaging/FiberTracking/Rendering/mitkFiberBundleXMapper3D.cpp b/Modules/DiffusionImaging/FiberTracking/Rendering/mitkFiberBundleXMapper3D.cpp index 8dae9ba932..2ab7ecdbf0 100644 --- a/Modules/DiffusionImaging/FiberTracking/Rendering/mitkFiberBundleXMapper3D.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Rendering/mitkFiberBundleXMapper3D.cpp @@ -1,191 +1,186 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkFiberBundleXMapper3D.h" #include //#include //#include #include #include #include #include //not essential for mapper // #include mitk::FiberBundleXMapper3D::FiberBundleXMapper3D() { m_lut = vtkLookupTable::New(); m_lut->Build(); } mitk::FiberBundleXMapper3D::~FiberBundleXMapper3D() { } const mitk::FiberBundleX* mitk::FiberBundleXMapper3D::GetInput() { return static_cast ( GetDataNode()->GetData() ); } /* This method is called once the mapper gets new input, for UI rotation or changes in colorcoding this method is NOT called */ -void mitk::FiberBundleXMapper3D::GenerateData(mitk::BaseRenderer *renderer) +void mitk::FiberBundleXMapper3D::InternalGenerateData(mitk::BaseRenderer *renderer) { mitk::FiberBundleX* FBX = dynamic_cast (GetDataNode()->GetData()); if (FBX == NULL) return; vtkSmartPointer FiberData = FBX->GetFiberPolyData(); if (FiberData == NULL) return; FBXLocalStorage3D *localStorage = m_LSH.GetLocalStorage(renderer); localStorage->m_FiberMapper->SetInputData(FiberData); if ( FiberData->GetPointData()->GetNumberOfArrays() > 0 ) localStorage->m_FiberMapper->SelectColorArray( FBX->GetCurrentColorCoding() ); localStorage->m_FiberMapper->ScalarVisibilityOn(); localStorage->m_FiberMapper->SetScalarModeToUsePointFieldData(); localStorage->m_FiberActor->SetMapper(localStorage->m_FiberMapper); localStorage->m_FiberMapper->SetLookupTable(m_lut); // set Opacity float tmpopa; this->GetDataNode()->GetOpacity(tmpopa, NULL); localStorage->m_FiberActor->GetProperty()->SetOpacity((double) tmpopa); int lineWidth = 1; this->GetDataNode()->GetIntProperty("LineWidth",lineWidth); localStorage->m_FiberActor->GetProperty()->SetLineWidth(lineWidth); // set color if (FBX->GetCurrentColorCoding() != NULL){ // localStorage->m_FiberMapper->SelectColorArray(""); localStorage->m_FiberMapper->SelectColorArray(FBX->GetCurrentColorCoding()); MITK_DEBUG << "MapperFBX: " << FBX->GetCurrentColorCoding(); if(FBX->GetCurrentColorCoding() == FBX->COLORCODING_CUSTOM) { float temprgb[3]; this->GetDataNode()->GetColor( temprgb, NULL ); double trgb[3] = { (double) temprgb[0], (double) temprgb[1], (double) temprgb[2] }; localStorage->m_FiberActor->GetProperty()->SetColor(trgb); } } localStorage->m_FiberAssembly->AddPart(localStorage->m_FiberActor); localStorage->m_LastUpdateTime.Modified(); //since this method is called after generating all necessary data for fiber visualization, all modifications are represented so far. } void mitk::FiberBundleXMapper3D::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if ( !visible ) return; // Calculate time step of the input data for the specified renderer (integer value) // this method is implemented in mitkMapper this->CalculateTimeStep( renderer ); //check if updates occured in the node or on the display FBXLocalStorage3D *localStorage = m_LSH.GetLocalStorage(renderer); const DataNode *node = this->GetDataNode(); if ( (localStorage->m_LastUpdateTime < node->GetMTime()) || (localStorage->m_LastUpdateTime < node->GetPropertyList()->GetMTime()) //was a property modified? || (localStorage->m_LastUpdateTime < node->GetPropertyList(renderer)->GetMTime()) ) { MITK_DEBUG << "UPDATE NEEDED FOR _ " << renderer->GetName(); - this->GenerateData(renderer); + this->InternalGenerateData(renderer); } } void mitk::FiberBundleXMapper3D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { // MITK_INFO << "FiberBundleXxXXMapper3D()SetDefaultProperties"; //MITK_INFO << "FiberBundleMapperX3D SetDefault Properties(...)"; // node->AddProperty( "DisplayChannel", mitk::IntProperty::New( true ), renderer, overwrite ); node->AddProperty( "LineWidth", mitk::IntProperty::New( true ), renderer, overwrite ); node->AddProperty( "opacity", mitk::FloatProperty::New( 1.0 ), renderer, overwrite); // node->AddProperty( "VertexOpacity_1", mitk::BoolProperty::New( false ), renderer, overwrite); // node->AddProperty( "Set_FA_VertexAlpha", mitk::BoolProperty::New( false ), renderer, overwrite); // node->AddProperty( "pointSize", mitk::FloatProperty::New(0.5), renderer, overwrite); // node->AddProperty( "setShading", mitk::IntProperty::New(1), renderer, overwrite); // node->AddProperty( "Xmove", mitk::IntProperty::New( 0 ), renderer, overwrite); // node->AddProperty( "Ymove", mitk::IntProperty::New( 0 ), renderer, overwrite); // node->AddProperty( "Zmove", mitk::IntProperty::New( 0 ), renderer, overwrite); // node->AddProperty( "RepPoints", mitk::BoolProperty::New( false ), renderer, overwrite); // node->AddProperty( "TubeSides", mitk::IntProperty::New( 8 ), renderer, overwrite); // node->AddProperty( "TubeRadius", mitk::FloatProperty::New( 0.15 ), renderer, overwrite); // node->AddProperty( "TubeOpacity", mitk::FloatProperty::New( 1.0 ), renderer, overwrite); node->AddProperty( "pickable", mitk::BoolProperty::New( true ), renderer, overwrite); Superclass::SetDefaultProperties(node, renderer, overwrite); } vtkProp* mitk::FiberBundleXMapper3D::GetVtkProp(mitk::BaseRenderer *renderer) { //MITK_INFO << "FiberBundleXxXXMapper3D()GetVTKProp"; //this->GenerateData(); return m_LSH.GetLocalStorage(renderer)->m_FiberAssembly; } -void mitk::FiberBundleXMapper3D::ApplyProperties(mitk::BaseRenderer* renderer) -{ - -} - void mitk::FiberBundleXMapper3D::UpdateVtkObjects() { } void mitk::FiberBundleXMapper3D::SetVtkMapperImmediateModeRendering(vtkMapper *) { } mitk::FiberBundleXMapper3D::FBXLocalStorage3D::FBXLocalStorage3D() { m_FiberActor = vtkSmartPointer::New(); m_FiberMapper = vtkSmartPointer::New(); m_FiberAssembly = vtkSmartPointer::New(); } diff --git a/Modules/DiffusionImaging/FiberTracking/Rendering/mitkFiberBundleXMapper3D.h b/Modules/DiffusionImaging/FiberTracking/Rendering/mitkFiberBundleXMapper3D.h index d6e2f3ce34..ecda4bde47 100644 --- a/Modules/DiffusionImaging/FiberTracking/Rendering/mitkFiberBundleXMapper3D.h +++ b/Modules/DiffusionImaging/FiberTracking/Rendering/mitkFiberBundleXMapper3D.h @@ -1,104 +1,103 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef FiberBundleXMapper3D_H_HEADER_INCLUDED #define FiberBundleXMapper3D_H_HEADER_INCLUDED //#include //?? necessary #include #include #include #include #include #include #include class vtkPropAssembly; namespace mitk { //##Documentation //## @brief Mapper for FiberBundleX //## @ingroup Mapper class FiberTracking_EXPORT FiberBundleXMapper3D : public VtkMapper { public: mitkClassMacro(FiberBundleXMapper3D, VtkMapper); itkNewMacro(Self); //========== essential implementation for 3D mapper ======== const FiberBundleX* GetInput(); virtual vtkProp *GetVtkProp(mitk::BaseRenderer *renderer); //looks like depricated.. should be replaced bz GetViewProp() static void SetDefaultProperties(DataNode* node, BaseRenderer* renderer = NULL, bool overwrite = false ); - virtual void ApplyProperties(mitk::BaseRenderer* renderer); static void SetVtkMapperImmediateModeRendering(vtkMapper *mapper); virtual void GenerateDataForRenderer(mitk::BaseRenderer* renderer); //========================================================= - virtual void GenerateData(mitk::BaseRenderer *renderer); class FBXLocalStorage3D : public mitk::Mapper::BaseLocalStorage { public: /** \brief Point Actor of a 3D render window. */ vtkSmartPointer m_FiberActor; /** \brief Point Mapper of a 3D render window. */ vtkSmartPointer m_FiberMapper; vtkSmartPointer m_FiberAssembly; /** \brief Timestamp of last update of stored data. */ itk::TimeStamp m_LastUpdateTime; /** \brief Constructor of the local storage. Do as much actions as possible in here to avoid double executions. */ FBXLocalStorage3D(); //if u copy&paste from this 2Dmapper, be aware that the implementation of this constructor is in the cpp file ~FBXLocalStorage3D() { } }; /** \brief This member holds all three LocalStorages for the 3D render window(s). */ mitk::LocalStorageHandler m_LSH; protected: FiberBundleXMapper3D(); virtual ~FiberBundleXMapper3D(); + void InternalGenerateData(mitk::BaseRenderer *renderer); void UpdateVtkObjects(); //?? private: vtkSmartPointer m_lut; }; } // end namespace mitk #endif /* FiberBundleXMapper3D_H_HEADER_INCLUDED */ diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkAstroStickModel.cpp b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkAstroStickModel.cpp index bc8b240567..44ec36ff13 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkAstroStickModel.cpp +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkAstroStickModel.cpp @@ -1,132 +1,132 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include using namespace mitk; template< class ScalarType > AstroStickModel< ScalarType >::AstroStickModel() - : m_Diffusivity(0.001) - , m_BValue(1000) + : m_BValue(1000) + , m_Diffusivity(0.001) , m_NumSticks(42) , m_RandomizeSticks(false) { m_RandGen = ItkRandGenType::New(); vnl_matrix_fixed* sticks = itk::PointShell<42, vnl_matrix_fixed >::DistributePointShell(); for (unsigned int i=0; iget(0,i); stick[1] = sticks->get(1,i); stick[2] = sticks->get(2,i); stick.Normalize(); m_Sticks.push_back(stick); } } template< class ScalarType > AstroStickModel< ScalarType >::~AstroStickModel() { } template< class ScalarType > void AstroStickModel< ScalarType >::SetSeed(int s) { m_RandGen->SetSeed(s); } template< class ScalarType > -ScalarType AstroStickModel< ScalarType >::SimulateMeasurement(int dir) +ScalarType AstroStickModel< ScalarType >::SimulateMeasurement(unsigned int dir) { ScalarType signal = 0; if (dir>=this->m_GradientList.size()) return signal; ScalarType b = -m_BValue*m_Diffusivity; if (m_RandomizeSticks) m_NumSticks = 30 + m_RandGen->GetIntegerVariate()%31; GradientType g = this->m_GradientList[dir]; ScalarType bVal = g.GetNorm(); bVal *= bVal; if (bVal>0.0001) { - for (int j=0; j typename AstroStickModel< ScalarType >::GradientType AstroStickModel< ScalarType >::GetRandomDirection() { GradientType vec; vec[0] = m_RandGen->GetNormalVariate(); vec[1] = m_RandGen->GetNormalVariate(); vec[2] = m_RandGen->GetNormalVariate(); vec.Normalize(); return vec; } template< class ScalarType > typename AstroStickModel< ScalarType >::PixelType AstroStickModel< ScalarType >::SimulateMeasurement() { PixelType signal; signal.SetSize(this->m_GradientList.size()); ScalarType b = -m_BValue*m_Diffusivity; if (m_RandomizeSticks) m_NumSticks = 30 + m_RandGen->GetIntegerVariate()%31; for( unsigned int i=0; im_GradientList.size(); i++) { GradientType g = this->m_GradientList[i]; ScalarType bVal = g.GetNorm(); bVal *= bVal; if (bVal>0.0001) { - for (int j=0; j #include namespace mitk { /** * \brief Generates the diffusion signal using an idealised cylinder with zero radius: e^(-bd(ng)²) * */ template< class ScalarType > class AstroStickModel : public DiffusionSignalModel< ScalarType > { public: AstroStickModel(); ~AstroStickModel(); typedef typename DiffusionSignalModel< ScalarType >::PixelType PixelType; typedef typename DiffusionSignalModel< ScalarType >::GradientType GradientType; typedef typename DiffusionSignalModel< ScalarType >::GradientListType GradientListType; typedef itk::Statistics::MersenneTwisterRandomVariateGenerator ItkRandGenType; /** Actual signal generation **/ PixelType SimulateMeasurement(); - ScalarType SimulateMeasurement(int dir); + ScalarType SimulateMeasurement(unsigned int dir); void SetSeed(int s); ///< set seed for random generator that creates the stick orientations void SetRandomizeSticks(bool randomize=true){ m_RandomizeSticks=randomize; } void SetBvalue(ScalarType bValue) { m_BValue = bValue; } ///< b-value used to generate the artificial signal void SetDiffusivity(ScalarType diffusivity) { m_Diffusivity = diffusivity; } ///< Scalar diffusion constant void SetNumSticks(unsigned int order) { vnl_matrix sticks; switch (order) { case 1: m_NumSticks = 12; sticks = itk::PointShell<12, vnl_matrix_fixed >::DistributePointShell()->as_matrix(); break; case 2: m_NumSticks = 42; sticks = itk::PointShell<42, vnl_matrix_fixed >::DistributePointShell()->as_matrix(); break; case 3: m_NumSticks = 92; sticks = itk::PointShell<92, vnl_matrix_fixed >::DistributePointShell()->as_matrix(); break; case 4: m_NumSticks = 162; sticks = itk::PointShell<162, vnl_matrix_fixed >::DistributePointShell()->as_matrix(); break; case 5: m_NumSticks = 252; sticks = itk::PointShell<252, vnl_matrix_fixed >::DistributePointShell()->as_matrix(); break; default: m_NumSticks = 42; sticks = itk::PointShell<42, vnl_matrix_fixed >::DistributePointShell()->as_matrix(); break; } for (int i=0; i #include #include using namespace mitk; template< class ScalarType > BallModel< ScalarType >::BallModel() : m_Diffusivity(0.001) , m_BValue(1000) { } template< class ScalarType > BallModel< ScalarType >::~BallModel() { } template< class ScalarType > -ScalarType BallModel< ScalarType >::SimulateMeasurement(int dir) +ScalarType BallModel< ScalarType >::SimulateMeasurement(unsigned int dir) { ScalarType signal = 0; if (dir>=this->m_GradientList.size()) return signal; GradientType g = this->m_GradientList[dir]; ScalarType bVal = g.GetNorm(); bVal *= bVal; if (bVal>0.0001) signal = exp( -m_BValue * bVal * m_Diffusivity ); else signal = 1; return signal; } template< class ScalarType > typename BallModel< ScalarType >::PixelType BallModel< ScalarType >::SimulateMeasurement() { PixelType signal; signal.SetSize(this->m_GradientList.size()); for( unsigned int i=0; im_GradientList.size(); i++) { GradientType g = this->m_GradientList[i]; ScalarType bVal = g.GetNorm(); bVal *= bVal; if (bVal>0.0001) signal[i] = exp( -m_BValue * bVal * m_Diffusivity ); else signal[i] = 1; } return signal; } diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkBallModel.h b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkBallModel.h index 37d8c21e6e..a6862d9aaf 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkBallModel.h +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkBallModel.h @@ -1,59 +1,59 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_BallModel_H #define _MITK_BallModel_H #include namespace mitk { /** * \brief Generates direction independent diffusion measurement employing a scalar diffusion constant d: e^(-bd) * */ template< class ScalarType > class BallModel : public DiffusionSignalModel< ScalarType > { public: BallModel(); ~BallModel(); typedef typename DiffusionSignalModel< ScalarType >::PixelType PixelType; typedef typename DiffusionSignalModel< ScalarType >::GradientType GradientType; /** Actual signal generation **/ PixelType SimulateMeasurement(); - ScalarType SimulateMeasurement(int dir); + ScalarType SimulateMeasurement(unsigned int dir); void SetDiffusivity(ScalarType D) { m_Diffusivity = D; } void SetBvalue(ScalarType bValue) { m_BValue = bValue; } protected: ScalarType m_Diffusivity; ///< Scalar diffusion constant ScalarType m_BValue; ///< b-value used to generate the artificial signal }; } #include "mitkBallModel.cpp" #endif diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDiffusionNoiseModel.h b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDiffusionNoiseModel.h index a3b046bc3a..6b140c7c65 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDiffusionNoiseModel.h +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDiffusionNoiseModel.h @@ -1,56 +1,56 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_DiffusionNoiseModel_H #define _MITK_DiffusionNoiseModel_H #include #include #include #include #include namespace mitk { /** * \brief Abstract class for diffusion noise models * */ template< class ScalarType > class DiffusionNoiseModel { public: DiffusionNoiseModel(){} - ~DiffusionNoiseModel(){} + virtual ~DiffusionNoiseModel(){} typedef itk::VariableLengthVector< ScalarType > PixelType; /** Adds noise according to model to the input pixel. Has to be implemented in subclass. **/ virtual void AddNoise(PixelType& pixel) = 0; /** Seed random generator. Has to be implemented in subclass. **/ virtual void SetSeed(int seed) = 0; protected: }; } #endif diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDiffusionSignalModel.h b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDiffusionSignalModel.h index 7fbdcf119f..f585803339 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDiffusionSignalModel.h +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDiffusionSignalModel.h @@ -1,93 +1,93 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_DiffusionSignalModel_H #define _MITK_DiffusionSignalModel_H #include #include #include #include namespace mitk { /** * \brief Abstract class for diffusion signal models * */ template< class ScalarType > class DiffusionSignalModel { public: DiffusionSignalModel() : m_T2(100) , m_Weight(1) {} ~DiffusionSignalModel(){} typedef itk::VariableLengthVector< ScalarType > PixelType; typedef itk::Vector GradientType; typedef std::vector GradientListType; /** Realizes actual signal generation. Has to be implemented in subclass. **/ virtual PixelType SimulateMeasurement() = 0; - virtual ScalarType SimulateMeasurement(int dir) = 0; + virtual ScalarType SimulateMeasurement(unsigned int dir) = 0; GradientType GetGradientDirection(int i) { return m_GradientList.at(i); } void SetFiberDirection(GradientType fiberDirection){ m_FiberDirection = fiberDirection; } void SetGradientList(GradientListType gradientList) { m_GradientList = gradientList; } void SetT2(double T2) { m_T2 = T2; } void SetWeight(double Weight) { m_Weight = Weight; } double GetWeight() { return m_Weight; } double GetT2() { return m_T2; } int GetNumGradients(){ return m_GradientList.size(); } std::vector< int > GetBaselineIndices() { std::vector< int > result; for( unsigned int i=0; im_GradientList.size(); i++) if (m_GradientList.at(i).GetNorm()<0.0001) result.push_back(i); return result; } int GetFirstBaselineIndex() { for( unsigned int i=0; im_GradientList.size(); i++) if (m_GradientList.at(i).GetNorm()<0.0001) return i; return -1; } - bool IsBaselineIndex(int idx) + bool IsBaselineIndex(unsigned int idx) { if (m_GradientList.size()>idx && m_GradientList.at(idx).GetNorm()<0.0001) return true; return false; } protected: GradientType m_FiberDirection; ///< Needed to generate anisotropc signal to determin direction of anisotropy GradientListType m_GradientList; ///< Diffusion gradient direction container double m_T2; ///< Tissue specific relaxation time double m_Weight; }; } #endif diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDotModel.cpp b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDotModel.cpp index fba855b986..7d91147d48 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDotModel.cpp +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDotModel.cpp @@ -1,47 +1,47 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include using namespace mitk; template< class ScalarType > DotModel< ScalarType >::DotModel() { } template< class ScalarType > DotModel< ScalarType >::~DotModel() { } template< class ScalarType > -ScalarType DotModel< ScalarType >::SimulateMeasurement(int dir) +ScalarType DotModel< ScalarType >::SimulateMeasurement(unsigned int /*dir*/) { return 1; } template< class ScalarType > typename DotModel< ScalarType >::PixelType DotModel< ScalarType >::SimulateMeasurement() { PixelType signal; signal.SetSize(this->m_GradientList.size()); signal.Fill(1); return signal; } diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDotModel.h b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDotModel.h index 7b05c51f60..fb644f4cdc 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDotModel.h +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDotModel.h @@ -1,53 +1,53 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_DotModel_H #define _MITK_DotModel_H #include namespace mitk { /** * \brief Generates direction independent diffusion measurement employing a scalar diffusion constant d: e^(-bd) * */ template< class ScalarType > class DotModel : public DiffusionSignalModel< ScalarType > { public: DotModel(); ~DotModel(); typedef typename DiffusionSignalModel< ScalarType >::PixelType PixelType; typedef typename DiffusionSignalModel< ScalarType >::GradientType GradientType; /** Actual signal generation **/ PixelType SimulateMeasurement(); - ScalarType SimulateMeasurement(int dir); + ScalarType SimulateMeasurement(unsigned int dir); protected: }; } #include "mitkDotModel.cpp" #endif diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkStickModel.cpp b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkStickModel.cpp index f77d56cfa6..eed95eece6 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkStickModel.cpp +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkStickModel.cpp @@ -1,82 +1,82 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include using namespace mitk; template< class ScalarType > StickModel< ScalarType >::StickModel() : m_Diffusivity(0.001) , m_BValue(1000) { } template< class ScalarType > StickModel< ScalarType >::~StickModel() { } template< class ScalarType > -ScalarType StickModel< ScalarType >::SimulateMeasurement(int dir) +ScalarType StickModel< ScalarType >::SimulateMeasurement(unsigned int dir) { ScalarType signal = 0; if (dir>=this->m_GradientList.size()) return signal; this->m_FiberDirection.Normalize(); GradientType g = this->m_GradientList[dir]; ScalarType bVal = g.GetNorm(); bVal *= bVal; if (bVal>0.0001) { ScalarType dot = this->m_FiberDirection*g; signal = exp( -m_BValue * bVal * m_Diffusivity*dot*dot ); } else signal = 1; return signal; } template< class ScalarType > typename StickModel< ScalarType >::PixelType StickModel< ScalarType >::SimulateMeasurement() { this->m_FiberDirection.Normalize(); PixelType signal; signal.SetSize(this->m_GradientList.size()); for( unsigned int i=0; im_GradientList.size(); i++) { GradientType g = this->m_GradientList[i]; ScalarType bVal = g.GetNorm(); bVal *= bVal; if (bVal>0.0001) { ScalarType dot = this->m_FiberDirection*g; signal[i] = exp( -m_BValue * bVal * m_Diffusivity*dot*dot ); } else signal[i] = 1; } return signal; } diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkStickModel.h b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkStickModel.h index 72625e03c4..d2c4de06f1 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkStickModel.h +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkStickModel.h @@ -1,58 +1,58 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_StickModel_H #define _MITK_StickModel_H #include namespace mitk { /** * \brief Generates the diffusion signal using an idealised cylinder with zero radius: e^(-bd(ng)²) * */ template< class ScalarType > class StickModel : public DiffusionSignalModel< ScalarType > { public: StickModel(); ~StickModel(); typedef typename DiffusionSignalModel< ScalarType >::PixelType PixelType; typedef typename DiffusionSignalModel< ScalarType >::GradientType GradientType; /** Actual signal generation **/ PixelType SimulateMeasurement(); - ScalarType SimulateMeasurement(int dir); + ScalarType SimulateMeasurement(unsigned int dir); void SetBvalue(ScalarType bValue) { m_BValue = bValue; } ///< b-value used to generate the artificial signal void SetDiffusivity(ScalarType diffusivity) { m_Diffusivity = diffusivity; } ///< Scalar diffusion constant protected: - ScalarType m_BValue; ///< b-value used to generate the artificial signal ScalarType m_Diffusivity; ///< Scalar diffusion constant + ScalarType m_BValue; ///< b-value used to generate the artificial signal }; } #include "mitkStickModel.cpp" #endif diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkTensorModel.cpp b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkTensorModel.cpp index 79bb88115b..1f83de5380 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkTensorModel.cpp +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkTensorModel.cpp @@ -1,129 +1,129 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include using namespace mitk; template< class ScalarType > TensorModel< ScalarType >::TensorModel() : m_BValue(1000) { m_KernelDirection[0]=1; m_KernelDirection[1]=0; m_KernelDirection[2]=0; m_KernelTensorMatrix.fill(0.0); m_KernelTensorMatrix[0][0] = 0.002; m_KernelTensorMatrix[1][1] = 0.0005; m_KernelTensorMatrix[2][2] = 0.0005; } template< class ScalarType > TensorModel< ScalarType >::~TensorModel() { } template< class ScalarType > -ScalarType TensorModel< ScalarType >::SimulateMeasurement(int dir) +ScalarType TensorModel< ScalarType >::SimulateMeasurement(unsigned int dir) { ScalarType signal = 0; if (dir>=this->m_GradientList.size()) return signal; ItkTensorType tensor; tensor.Fill(0.0); this->m_FiberDirection.Normalize(); vnl_vector_fixed axis = itk::CrossProduct(m_KernelDirection, this->m_FiberDirection).GetVnlVector(); axis.normalize(); vnl_quaternion rotation(axis, acos(m_KernelDirection*this->m_FiberDirection)); rotation.normalize(); vnl_matrix_fixed matrix = rotation.rotation_matrix_transpose(); vnl_matrix_fixed tensorMatrix = matrix.transpose()*m_KernelTensorMatrix*matrix; tensor[0] = tensorMatrix[0][0]; tensor[1] = tensorMatrix[0][1]; tensor[2] = tensorMatrix[0][2]; tensor[3] = tensorMatrix[1][1]; tensor[4] = tensorMatrix[1][2]; tensor[5] = tensorMatrix[2][2]; GradientType g = this->m_GradientList[dir]; ScalarType bVal = g.GetNorm(); bVal *= bVal; if (bVal>0.0001) { itk::DiffusionTensor3D< ScalarType > S; S[0] = g[0]*g[0]; S[1] = g[1]*g[0]; S[2] = g[2]*g[0]; S[3] = g[1]*g[1]; S[4] = g[2]*g[1]; S[5] = g[2]*g[2]; ScalarType D = tensor[0]*S[0] + tensor[1]*S[1] + tensor[2]*S[2] + tensor[1]*S[1] + tensor[3]*S[3] + tensor[4]*S[4] + tensor[2]*S[2] + tensor[4]*S[4] + tensor[5]*S[5]; // check for corrupted tensor and generate signal if (D>=0) signal = exp ( -m_BValue * bVal * D ); } else signal = 1; return signal; } template< class ScalarType > typename TensorModel< ScalarType >::PixelType TensorModel< ScalarType >::SimulateMeasurement() { PixelType signal; signal.SetSize(this->m_GradientList.size()); signal.Fill(0.0); ItkTensorType tensor; tensor.Fill(0.0); this->m_FiberDirection.Normalize(); vnl_vector_fixed axis = itk::CrossProduct(m_KernelDirection, this->m_FiberDirection).GetVnlVector(); axis.normalize(); vnl_quaternion rotation(axis, acos(m_KernelDirection*this->m_FiberDirection)); rotation.normalize(); vnl_matrix_fixed matrix = rotation.rotation_matrix_transpose(); vnl_matrix_fixed tensorMatrix = matrix.transpose()*m_KernelTensorMatrix*matrix; tensor[0] = tensorMatrix[0][0]; tensor[1] = tensorMatrix[0][1]; tensor[2] = tensorMatrix[0][2]; tensor[3] = tensorMatrix[1][1]; tensor[4] = tensorMatrix[1][2]; tensor[5] = tensorMatrix[2][2]; for( unsigned int i=0; im_GradientList.size(); i++) { GradientType g = this->m_GradientList[i]; ScalarType bVal = g.GetNorm(); bVal *= bVal; if (bVal>0.0001) { itk::DiffusionTensor3D< ScalarType > S; S[0] = g[0]*g[0]; S[1] = g[1]*g[0]; S[2] = g[2]*g[0]; S[3] = g[1]*g[1]; S[4] = g[2]*g[1]; S[5] = g[2]*g[2]; ScalarType D = tensor[0]*S[0] + tensor[1]*S[1] + tensor[2]*S[2] + tensor[1]*S[1] + tensor[3]*S[3] + tensor[4]*S[4] + tensor[2]*S[2] + tensor[4]*S[4] + tensor[5]*S[5]; // check for corrupted tensor and generate signal if (D>=0) signal[i] = exp ( -m_BValue * bVal * D ); } else signal[i] = 1; } return signal; } diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkTensorModel.h b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkTensorModel.h index 000dcdddaf..57fd1c2d92 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkTensorModel.h +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkTensorModel.h @@ -1,65 +1,65 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_TensorModel_H #define _MITK_TensorModel_H #include #include namespace mitk { /** * \brief Generates diffusion measurement employing a second rank tensor model: e^(-bg^TDg) * */ template< class ScalarType > class TensorModel : public DiffusionSignalModel< ScalarType > { public: TensorModel(); ~TensorModel(); typedef typename DiffusionSignalModel< ScalarType >::PixelType PixelType; typedef itk::DiffusionTensor3D< ScalarType > ItkTensorType; typedef typename DiffusionSignalModel< ScalarType >::GradientType GradientType; /** Actual signal generation **/ PixelType SimulateMeasurement(); - ScalarType SimulateMeasurement(int dir); + ScalarType SimulateMeasurement(unsigned int dir); void SetBvalue(ScalarType bValue) { m_BValue = bValue; } void SetDiffusivity1(ScalarType d1){ m_KernelTensorMatrix[0][0] = d1; } void SetDiffusivity2(ScalarType d2){ m_KernelTensorMatrix[1][1] = d2; } void SetDiffusivity3(ScalarType d3){ m_KernelTensorMatrix[2][2] = d3; } protected: /** Calculates tensor matrix from FA and ADC **/ void UpdateKernelTensor(); GradientType m_KernelDirection; ///< Direction of the kernel tensors principal eigenvector vnl_matrix_fixed m_KernelTensorMatrix; ///< 3x3 matrix containing the kernel tensor values ScalarType m_BValue; ///< b-value used to generate the artificial signal }; } #include "mitkTensorModel.cpp" #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp b/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp index 357eed14ca..8961ab78c5 100755 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp @@ -1,163 +1,163 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define _USE_MATH_DEFINES #include using namespace std; int mitkLocalFiberPlausibilityTest(int argc, char* argv[]) { MITK_TEST_BEGIN("mitkLocalFiberPlausibilityTest"); MITK_TEST_CONDITION_REQUIRED(argc==8,"check for input data") string fibFile = argv[1]; vector< string > referenceImages; referenceImages.push_back(argv[2]); referenceImages.push_back(argv[3]); string LDFP_ERROR_IMAGE = argv[4]; string LDFP_NUM_DIRECTIONS = argv[5]; string LDFP_VECTOR_FIELD = argv[6]; string LDFP_ERROR_IMAGE_IGNORE = argv[7]; float angularThreshold = 25; try { RegisterDiffusionCoreObjectFactory(); RegisterFiberTrackingObjectFactory(); typedef itk::Image ItkUcharImgType; typedef itk::Image< itk::Vector< float, 3>, 3 > ItkDirectionImage3DType; - typedef itk::VectorContainer< int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType; + typedef itk::VectorContainer< unsigned int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType; typedef itk::EvaluateDirectionImagesFilter< float > EvaluationFilterType; // load fiber bundle mitk::FiberBundleX::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::LoadDataNode(fibFile)->GetData()); // load reference directions ItkDirectionImageContainerType::Pointer referenceImageContainer = ItkDirectionImageContainerType::New(); - for (int i=0; i(mitk::IOUtil::LoadDataNode(referenceImages.at(i))->GetData()); typedef mitk::ImageToItk< ItkDirectionImage3DType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); ItkDirectionImage3DType::Pointer itkImg = caster->GetOutput(); referenceImageContainer->InsertElement(referenceImageContainer->Size(),itkImg); } catch(...){ MITK_INFO << "could not load: " << referenceImages.at(i); } } ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); ItkDirectionImage3DType::Pointer dirImg = referenceImageContainer->GetElement(0); itkMaskImage->SetSpacing( dirImg->GetSpacing() ); itkMaskImage->SetOrigin( dirImg->GetOrigin() ); itkMaskImage->SetDirection( dirImg->GetDirection() ); itkMaskImage->SetLargestPossibleRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->SetBufferedRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->SetRequestedRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->Allocate(); itkMaskImage->FillBuffer(1); // extract directions from fiber bundle itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); fOdfFilter->SetFiberBundle(inputTractogram); fOdfFilter->SetMaskImage(itkMaskImage); fOdfFilter->SetAngularThreshold(cos(angularThreshold*M_PI/180)); fOdfFilter->SetNormalizeVectors(true); fOdfFilter->SetUseWorkingCopy(false); fOdfFilter->SetNumberOfThreads(1); fOdfFilter->Update(); ItkDirectionImageContainerType::Pointer directionImageContainer = fOdfFilter->GetDirectionImageContainer(); // Get directions and num directions image ItkUcharImgType::Pointer numDirImage = fOdfFilter->GetNumDirectionsImage(); mitk::Image::Pointer mitkNumDirImage = mitk::Image::New(); mitkNumDirImage->InitializeByItk( numDirImage.GetPointer() ); mitkNumDirImage->SetVolume( numDirImage->GetBufferPointer() ); mitk::FiberBundleX::Pointer testDirections = fOdfFilter->GetOutputFiberBundle(); // evaluate directions with missing directions EvaluationFilterType::Pointer evaluationFilter = EvaluationFilterType::New(); evaluationFilter->SetImageSet(directionImageContainer); evaluationFilter->SetReferenceImageSet(referenceImageContainer); evaluationFilter->SetMaskImage(itkMaskImage); evaluationFilter->SetIgnoreMissingDirections(false); evaluationFilter->Update(); EvaluationFilterType::OutputImageType::Pointer angularErrorImage = evaluationFilter->GetOutput(0); mitk::Image::Pointer mitkAngularErrorImage = mitk::Image::New(); mitkAngularErrorImage->InitializeByItk( angularErrorImage.GetPointer() ); mitkAngularErrorImage->SetVolume( angularErrorImage->GetBufferPointer() ); // evaluate directions without missing directions evaluationFilter->SetIgnoreMissingDirections(true); evaluationFilter->Update(); EvaluationFilterType::OutputImageType::Pointer angularErrorImageIgnore = evaluationFilter->GetOutput(0); mitk::Image::Pointer mitkAngularErrorImageIgnore = mitk::Image::New(); mitkAngularErrorImageIgnore->InitializeByItk( angularErrorImageIgnore.GetPointer() ); mitkAngularErrorImageIgnore->SetVolume( angularErrorImageIgnore->GetBufferPointer() ); mitk::Image::Pointer gtAngularErrorImageIgnore = dynamic_cast(mitk::IOUtil::LoadDataNode(LDFP_ERROR_IMAGE_IGNORE)->GetData()); mitk::Image::Pointer gtAngularErrorImage = dynamic_cast(mitk::IOUtil::LoadDataNode(LDFP_ERROR_IMAGE)->GetData()); mitk::Image::Pointer gtNumTestDirImage = dynamic_cast(mitk::IOUtil::LoadDataNode(LDFP_NUM_DIRECTIONS)->GetData()); mitk::FiberBundleX::Pointer gtTestDirections = dynamic_cast(mitk::IOUtil::LoadDataNode(LDFP_VECTOR_FIELD)->GetData()); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(gtAngularErrorImageIgnore, mitkAngularErrorImageIgnore, 0.0001, true), "Check if error images are equal (ignored missing directions)."); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(gtAngularErrorImage, mitkAngularErrorImage, 0.0001, true), "Check if error images are equal."); MITK_TEST_CONDITION_REQUIRED(testDirections->Equals(gtTestDirections), "Check if vector fields are equal."); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(gtNumTestDirImage, mitkNumDirImage, 0.0001, true), "Check if num direction images are equal."); } catch (itk::ExceptionObject e) { MITK_INFO << e; return EXIT_FAILURE; } catch (std::exception e) { MITK_INFO << e.what(); return EXIT_FAILURE; } catch (...) { MITK_INFO << "ERROR!?!"; return EXIT_FAILURE; } MITK_TEST_END(); } diff --git a/Modules/DiffusionImaging/MiniApps/FiberDirectionExtraction.cpp b/Modules/DiffusionImaging/MiniApps/FiberDirectionExtraction.cpp index f7f97cb4c9..cee66de1b1 100755 --- a/Modules/DiffusionImaging/MiniApps/FiberDirectionExtraction.cpp +++ b/Modules/DiffusionImaging/MiniApps/FiberDirectionExtraction.cpp @@ -1,167 +1,167 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "MiniAppManager.h" #include #include #include #include #include #include #include #include "ctkCommandLineParser.h" #include #include #include #include #include #include #define _USE_MATH_DEFINES #include int FiberDirectionExtraction(int argc, char* argv[]) { ctkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", ctkCommandLineParser::String, "input tractogram (.fib, vtk ascii file format)", us::Any(), false); parser.addArgument("out", "o", ctkCommandLineParser::String, "output root", us::Any(), false); parser.addArgument("mask", "m", ctkCommandLineParser::String, "mask image"); parser.addArgument("athresh", "a", ctkCommandLineParser::Float, "angular threshold in degrees. closer fiber directions are regarded as one direction and clustered together.", 25, true); parser.addArgument("verbose", "v", ctkCommandLineParser::Bool, "output optional and intermediate calculation results"); map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; string fibFile = us::any_cast(parsedArgs["input"]); string maskImage(""); if (parsedArgs.count("mask")) maskImage = us::any_cast(parsedArgs["mask"]); float angularThreshold = 25; if (parsedArgs.count("athresh")) angularThreshold = us::any_cast(parsedArgs["athresh"]); string outRoot = us::any_cast(parsedArgs["out"]); bool verbose = false; if (parsedArgs.count("verbose")) verbose = us::any_cast(parsedArgs["verbose"]); try { RegisterDiffusionCoreObjectFactory(); RegisterFiberTrackingObjectFactory(); typedef itk::Image ItkUcharImgType; typedef itk::Image< itk::Vector< float, 3>, 3 > ItkDirectionImage3DType; - typedef itk::VectorContainer< int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType; + typedef itk::VectorContainer< unsigned int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType; // load fiber bundle mitk::FiberBundleX::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::LoadDataNode(fibFile)->GetData()); // load/create mask image ItkUcharImgType::Pointer itkMaskImage = NULL; if (maskImage.compare("")!=0) { MITK_INFO << "Using mask image"; itkMaskImage = ItkUcharImgType::New(); mitk::Image::Pointer mitkMaskImage = dynamic_cast(mitk::IOUtil::LoadDataNode(maskImage)->GetData()); mitk::CastToItkImage(mitkMaskImage, itkMaskImage); } // extract directions from fiber bundle itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); fOdfFilter->SetFiberBundle(inputTractogram); fOdfFilter->SetMaskImage(itkMaskImage); fOdfFilter->SetAngularThreshold(cos(angularThreshold*M_PI/180)); fOdfFilter->SetNormalizeVectors(true); fOdfFilter->SetUseWorkingCopy(false); fOdfFilter->Update(); ItkDirectionImageContainerType::Pointer directionImageContainer = fOdfFilter->GetDirectionImageContainer(); // write direction images for (int i=0; iSize(); i++) { itk::TractsToVectorImageFilter::ItkDirectionImageType::Pointer itkImg = directionImageContainer->GetElement(i); typedef itk::ImageFileWriter< itk::TractsToVectorImageFilter::ItkDirectionImageType > WriterType; WriterType::Pointer writer = WriterType::New(); string outfilename = outRoot; outfilename.append("_DIRECTION_"); outfilename.append(boost::lexical_cast(i)); outfilename.append(".nrrd"); MITK_INFO << "writing " << outfilename; writer->SetFileName(outfilename.c_str()); writer->SetInput(itkImg); writer->Update(); } if (verbose) { // write vector field mitk::FiberBundleX::Pointer directions = fOdfFilter->GetOutputFiberBundle(); mitk::CoreObjectFactory::FileWriterList fileWriters = mitk::CoreObjectFactory::GetInstance()->GetFileWriters(); for (mitk::CoreObjectFactory::FileWriterList::iterator it = fileWriters.begin() ; it != fileWriters.end() ; ++it) { if ( (*it)->CanWriteBaseDataType(directions.GetPointer()) ) { string outfilename = outRoot; outfilename.append("_VECTOR_FIELD.fib"); (*it)->SetFileName( outfilename.c_str() ); (*it)->DoWrite( directions.GetPointer() ); } } // write num direction image { ItkUcharImgType::Pointer numDirImage = fOdfFilter->GetNumDirectionsImage(); typedef itk::ImageFileWriter< ItkUcharImgType > WriterType; WriterType::Pointer writer = WriterType::New(); string outfilename = outRoot; outfilename.append("_NUM_DIRECTIONS.nrrd"); MITK_INFO << "writing " << outfilename; writer->SetFileName(outfilename.c_str()); writer->SetInput(numDirImage); writer->Update(); } } MITK_INFO << "DONE"; } catch (itk::ExceptionObject e) { MITK_INFO << e; return EXIT_FAILURE; } catch (std::exception e) { MITK_INFO << e.what(); return EXIT_FAILURE; } catch (...) { MITK_INFO << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } RegisterDiffusionMiniApp(FiberDirectionExtraction); diff --git a/Modules/DiffusionImaging/MiniApps/LocalDirectionalFiberPlausibility.cpp b/Modules/DiffusionImaging/MiniApps/LocalDirectionalFiberPlausibility.cpp index e444ed3349..3729f127c5 100755 --- a/Modules/DiffusionImaging/MiniApps/LocalDirectionalFiberPlausibility.cpp +++ b/Modules/DiffusionImaging/MiniApps/LocalDirectionalFiberPlausibility.cpp @@ -1,302 +1,302 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "MiniAppManager.h" #include #include #include #include #include #include #include #include #include "ctkCommandLineParser.h" #include #include #include #include #include #include #include #include #define _USE_MATH_DEFINES #include int LocalDirectionalFiberPlausibility(int argc, char* argv[]) { ctkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", ctkCommandLineParser::String, "input tractogram (.fib, vtk ascii file format)", us::Any(), false); parser.addArgument("reference", "r", ctkCommandLineParser::StringList, "reference direction images", us::Any(), false); parser.addArgument("out", "o", ctkCommandLineParser::String, "output root", us::Any(), false); parser.addArgument("mask", "m", ctkCommandLineParser::StringList, "mask images"); parser.addArgument("athresh", "a", ctkCommandLineParser::Float, "angular threshold in degrees. closer fiber directions are regarded as one direction and clustered together.", 25, true); parser.addArgument("verbose", "v", ctkCommandLineParser::Bool, "output optional and intermediate calculation results"); parser.addArgument("ignore", "n", ctkCommandLineParser::Bool, "don't increase error for missing or too many directions"); map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; ctkCommandLineParser::StringContainerType referenceImages = us::any_cast(parsedArgs["reference"]); ctkCommandLineParser::StringContainerType maskImages; if (parsedArgs.count("mask")) maskImages = us::any_cast(parsedArgs["mask"]); string fibFile = us::any_cast(parsedArgs["input"]); float angularThreshold = 25; if (parsedArgs.count("athresh")) angularThreshold = us::any_cast(parsedArgs["athresh"]); string outRoot = us::any_cast(parsedArgs["out"]); bool verbose = false; if (parsedArgs.count("verbose")) verbose = us::any_cast(parsedArgs["verbose"]); bool ignore = false; if (parsedArgs.count("ignore")) ignore = us::any_cast(parsedArgs["ignore"]); try { RegisterDiffusionCoreObjectFactory(); RegisterFiberTrackingObjectFactory(); typedef itk::Image ItkUcharImgType; typedef itk::Image< itk::Vector< float, 3>, 3 > ItkDirectionImage3DType; - typedef itk::VectorContainer< int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType; + typedef itk::VectorContainer< unsigned int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType; typedef itk::EvaluateDirectionImagesFilter< float > EvaluationFilterType; // load fiber bundle mitk::FiberBundleX::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::LoadDataNode(fibFile)->GetData()); // load reference directions ItkDirectionImageContainerType::Pointer referenceImageContainer = ItkDirectionImageContainerType::New(); for (int i=0; i(mitk::IOUtil::LoadDataNode(referenceImages.at(i))->GetData()); typedef mitk::ImageToItk< ItkDirectionImage3DType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); ItkDirectionImage3DType::Pointer itkImg = caster->GetOutput(); referenceImageContainer->InsertElement(referenceImageContainer->Size(),itkImg); } catch(...){ MITK_INFO << "could not load: " << referenceImages.at(i); } } ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); ItkDirectionImage3DType::Pointer dirImg = referenceImageContainer->GetElement(0); itkMaskImage->SetSpacing( dirImg->GetSpacing() ); itkMaskImage->SetOrigin( dirImg->GetOrigin() ); itkMaskImage->SetDirection( dirImg->GetDirection() ); itkMaskImage->SetLargestPossibleRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->SetBufferedRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->SetRequestedRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->Allocate(); itkMaskImage->FillBuffer(1); // extract directions from fiber bundle itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); fOdfFilter->SetFiberBundle(inputTractogram); fOdfFilter->SetMaskImage(itkMaskImage); fOdfFilter->SetAngularThreshold(cos(angularThreshold*M_PI/180)); fOdfFilter->SetNormalizeVectors(true); fOdfFilter->SetUseWorkingCopy(false); fOdfFilter->Update(); ItkDirectionImageContainerType::Pointer directionImageContainer = fOdfFilter->GetDirectionImageContainer(); if (verbose) { // write vector field mitk::FiberBundleX::Pointer directions = fOdfFilter->GetOutputFiberBundle(); mitk::CoreObjectFactory::FileWriterList fileWriters = mitk::CoreObjectFactory::GetInstance()->GetFileWriters(); for (mitk::CoreObjectFactory::FileWriterList::iterator it = fileWriters.begin() ; it != fileWriters.end() ; ++it) { if ( (*it)->CanWriteBaseDataType(directions.GetPointer()) ) { string outfilename = outRoot; outfilename.append("_VECTOR_FIELD.fib"); (*it)->SetFileName( outfilename.c_str() ); (*it)->DoWrite( directions.GetPointer() ); } } // write direction images for (int i=0; iSize(); i++) { itk::TractsToVectorImageFilter::ItkDirectionImageType::Pointer itkImg = directionImageContainer->GetElement(i); typedef itk::ImageFileWriter< itk::TractsToVectorImageFilter::ItkDirectionImageType > WriterType; WriterType::Pointer writer = WriterType::New(); string outfilename = outRoot; outfilename.append("_DIRECTION_"); outfilename.append(boost::lexical_cast(i)); outfilename.append(".nrrd"); MITK_INFO << "writing " << outfilename; writer->SetFileName(outfilename.c_str()); writer->SetInput(itkImg); writer->Update(); } // write num direction image { ItkUcharImgType::Pointer numDirImage = fOdfFilter->GetNumDirectionsImage(); typedef itk::ImageFileWriter< ItkUcharImgType > WriterType; WriterType::Pointer writer = WriterType::New(); string outfilename = outRoot; outfilename.append("_NUM_DIRECTIONS.nrrd"); MITK_INFO << "writing " << outfilename; writer->SetFileName(outfilename.c_str()); writer->SetInput(numDirImage); writer->Update(); } } string logFile = outRoot; logFile.append("_ANGULAR_ERROR.csv"); ofstream file; file.open (logFile.c_str()); if (maskImages.size()>0) { for (int i=0; i(mitk::IOUtil::LoadDataNode(maskImages.at(i))->GetData()); mitk::CastToItkImage(mitkMaskImage, itkMaskImage); // evaluate directions EvaluationFilterType::Pointer evaluationFilter = EvaluationFilterType::New(); evaluationFilter->SetImageSet(directionImageContainer); evaluationFilter->SetReferenceImageSet(referenceImageContainer); evaluationFilter->SetMaskImage(itkMaskImage); evaluationFilter->SetIgnoreMissingDirections(ignore); evaluationFilter->Update(); if (verbose) { EvaluationFilterType::OutputImageType::Pointer angularErrorImage = evaluationFilter->GetOutput(0); typedef itk::ImageFileWriter< EvaluationFilterType::OutputImageType > WriterType; WriterType::Pointer writer = WriterType::New(); string outfilename = outRoot; outfilename.append("_ERROR_IMAGE.nrrd"); MITK_INFO << "writing " << outfilename; writer->SetFileName(outfilename.c_str()); writer->SetInput(angularErrorImage); writer->Update(); } string sens = itksys::SystemTools::GetFilenameWithoutExtension(itksys::SystemTools::GetFilenameName(fibFile)); sens.append(","); sens.append(itksys::SystemTools::GetFilenameWithoutExtension(itksys::SystemTools::GetFilenameName(maskImages.at(i)))); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMeanAngularError())); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMedianAngularError())); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMaxAngularError())); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMinAngularError())); sens.append(","); sens.append(boost::lexical_cast(std::sqrt(evaluationFilter->GetVarAngularError()))); sens.append(";\n"); file << sens; } } else { // evaluate directions EvaluationFilterType::Pointer evaluationFilter = EvaluationFilterType::New(); evaluationFilter->SetImageSet(directionImageContainer); evaluationFilter->SetReferenceImageSet(referenceImageContainer); evaluationFilter->SetMaskImage(itkMaskImage); evaluationFilter->SetIgnoreMissingDirections(ignore); evaluationFilter->Update(); if (verbose) { EvaluationFilterType::OutputImageType::Pointer angularErrorImage = evaluationFilter->GetOutput(0); typedef itk::ImageFileWriter< EvaluationFilterType::OutputImageType > WriterType; WriterType::Pointer writer = WriterType::New(); string outfilename = outRoot; outfilename.append("_ERROR_IMAGE.nrrd"); MITK_INFO << "writing " << outfilename; writer->SetFileName(outfilename.c_str()); writer->SetInput(angularErrorImage); writer->Update(); } string sens = itksys::SystemTools::GetFilenameWithoutExtension(itksys::SystemTools::GetFilenameName(fibFile)); sens.append(","); sens.append("FULL"); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMeanAngularError())); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMedianAngularError())); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMaxAngularError())); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMinAngularError())); sens.append(","); sens.append(boost::lexical_cast(std::sqrt(evaluationFilter->GetVarAngularError()))); sens.append(";\n"); file << sens; } file.close(); MITK_INFO << "DONE"; } catch (itk::ExceptionObject e) { MITK_INFO << e; return EXIT_FAILURE; } catch (std::exception e) { MITK_INFO << e.what(); return EXIT_FAILURE; } catch (...) { MITK_INFO << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } RegisterDiffusionMiniApp(LocalDirectionalFiberPlausibility); diff --git a/Modules/DiffusionImaging/MiniApps/PeaksAngularError.cpp b/Modules/DiffusionImaging/MiniApps/PeaksAngularError.cpp index f7c4f5ea01..cb5714bb3f 100755 --- a/Modules/DiffusionImaging/MiniApps/PeaksAngularError.cpp +++ b/Modules/DiffusionImaging/MiniApps/PeaksAngularError.cpp @@ -1,210 +1,210 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "MiniAppManager.h" #include #include #include #include #include #include #include #include #include "ctkCommandLineParser.h" #include #include #include #include #include #include #include #define _USE_MATH_DEFINES #include int PeaksAngularError(int argc, char* argv[]) { ctkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); parser.addArgument("test", "t", ctkCommandLineParser::StringList, "test direction images", us::Any(), false); parser.addArgument("reference", "r", ctkCommandLineParser::StringList, "reference direction images", us::Any(), false); parser.addArgument("out", "o", ctkCommandLineParser::String, "output root", us::Any(), false); parser.addArgument("mask", "m", ctkCommandLineParser::String, "mask image"); parser.addArgument("verbose", "v", ctkCommandLineParser::Bool, "output optional and intermediate calculation results"); parser.addArgument("ignore", "i", ctkCommandLineParser::Bool, "don't increase error for missing or too many directions"); map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; ctkCommandLineParser::StringContainerType testImages = us::any_cast(parsedArgs["test"]); ctkCommandLineParser::StringContainerType referenceImages = us::any_cast(parsedArgs["reference"]); string maskImage(""); if (parsedArgs.count("mask")) maskImage = us::any_cast(parsedArgs["mask"]); string outRoot = us::any_cast(parsedArgs["out"]); bool verbose = false; if (parsedArgs.count("verbose")) verbose = us::any_cast(parsedArgs["verbose"]); bool ignore = false; if (parsedArgs.count("ignore")) ignore = us::any_cast(parsedArgs["ignore"]); try { RegisterDiffusionCoreObjectFactory(); RegisterFiberTrackingObjectFactory(); typedef itk::Image ItkUcharImgType; typedef itk::Image< itk::Vector< float, 3>, 3 > ItkDirectionImage3DType; - typedef itk::VectorContainer< int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType; + typedef itk::VectorContainer< unsigned int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType; typedef itk::EvaluateDirectionImagesFilter< float > EvaluationFilterType; ItkDirectionImageContainerType::Pointer directionImageContainer = ItkDirectionImageContainerType::New(); for (int i=0; i(mitk::IOUtil::LoadDataNode(testImages.at(i))->GetData()); typedef mitk::ImageToItk< ItkDirectionImage3DType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); ItkDirectionImage3DType::Pointer itkImg = caster->GetOutput(); directionImageContainer->InsertElement(directionImageContainer->Size(),itkImg); } catch(...){ MITK_INFO << "could not load: " << referenceImages.at(i); } } // load reference directions ItkDirectionImageContainerType::Pointer referenceImageContainer = ItkDirectionImageContainerType::New(); for (int i=0; i(mitk::IOUtil::LoadDataNode(referenceImages.at(i))->GetData()); typedef mitk::ImageToItk< ItkDirectionImage3DType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); ItkDirectionImage3DType::Pointer itkImg = caster->GetOutput(); referenceImageContainer->InsertElement(referenceImageContainer->Size(),itkImg); } catch(...){ MITK_INFO << "could not load: " << referenceImages.at(i); } } // load/create mask image ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); if (maskImage.compare("")==0) { ItkDirectionImage3DType::Pointer dirImg = referenceImageContainer->GetElement(0); itkMaskImage->SetSpacing( dirImg->GetSpacing() ); itkMaskImage->SetOrigin( dirImg->GetOrigin() ); itkMaskImage->SetDirection( dirImg->GetDirection() ); itkMaskImage->SetLargestPossibleRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->SetBufferedRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->SetRequestedRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->Allocate(); itkMaskImage->FillBuffer(1); } else { mitk::Image::Pointer mitkMaskImage = dynamic_cast(mitk::IOUtil::LoadDataNode(maskImage)->GetData()); mitk::CastToItkImage(mitkMaskImage, itkMaskImage); } // evaluate directions EvaluationFilterType::Pointer evaluationFilter = EvaluationFilterType::New(); evaluationFilter->SetImageSet(directionImageContainer); evaluationFilter->SetReferenceImageSet(referenceImageContainer); evaluationFilter->SetMaskImage(itkMaskImage); evaluationFilter->SetIgnoreMissingDirections(ignore); evaluationFilter->Update(); if (verbose) { EvaluationFilterType::OutputImageType::Pointer angularErrorImage = evaluationFilter->GetOutput(0); typedef itk::ImageFileWriter< EvaluationFilterType::OutputImageType > WriterType; WriterType::Pointer writer = WriterType::New(); string outfilename = outRoot; outfilename.append("_ERROR_IMAGE.nrrd"); MITK_INFO << "writing " << outfilename; writer->SetFileName(outfilename.c_str()); writer->SetInput(angularErrorImage); writer->Update(); } string logFile = outRoot; logFile.append("_ANGULAR_ERROR.csv"); ofstream file; file.open (logFile.c_str()); string sens = "Mean:"; sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMeanAngularError())); sens.append(";\n"); sens.append("Median:"); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMedianAngularError())); sens.append(";\n"); sens.append("Maximum:"); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMaxAngularError())); sens.append(";\n"); sens.append("Minimum:"); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMinAngularError())); sens.append(";\n"); sens.append("STDEV:"); sens.append(","); sens.append(boost::lexical_cast(std::sqrt(evaluationFilter->GetVarAngularError()))); sens.append(";\n"); file << sens; file.close(); MITK_INFO << "DONE"; } catch (itk::ExceptionObject e) { MITK_INFO << e; return EXIT_FAILURE; } catch (std::exception e) { MITK_INFO << e.what(); return EXIT_FAILURE; } catch (...) { MITK_INFO << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } RegisterDiffusionMiniApp(PeaksAngularError); diff --git a/Modules/DiffusionImaging/Quantification/Algorithms/itkSkeletonizationFilter.txx b/Modules/DiffusionImaging/Quantification/Algorithms/itkSkeletonizationFilter.txx index f42a3bcaf8..ead0836376 100644 --- a/Modules/DiffusionImaging/Quantification/Algorithms/itkSkeletonizationFilter.txx +++ b/Modules/DiffusionImaging/Quantification/Algorithms/itkSkeletonizationFilter.txx @@ -1,306 +1,306 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _itkSkeletonizationFilter_txx #define _itkSkeletonizationFilter_txx #include "itkSkeletonizationFilter.h" #include "mitkProgressBar.h" #include #include namespace itk { template< class TInputImage, class TOutputImage > SkeletonizationFilter::SkeletonizationFilter() { m_DirectionImage = VectorImageType::New(); } template< class TInputImage, class TOutputImage > SkeletonizationFilter::~SkeletonizationFilter() { } template< class TInputImage, class TOutputImage > void SkeletonizationFilter::GenerateData() { //----------------------------------------------------------------------// // Progress bar // //----------------------------------------------------------------------// mitk::ProgressBar::GetInstance()->AddStepsToDo( 3 ); std::cout << "Skeletonize" << std::endl; const InputImageType* faImage = this->GetInput(); typename InputImageType::SizeType size = faImage->GetRequestedRegion().GetSize(); //typename RealImageType::SizeType size = m_FaImage->GetRequestedRegion().GetSize(); m_DirectionImage->SetRegions(faImage->GetRequestedRegion()); m_DirectionImage->SetDirection(faImage->GetDirection()); m_DirectionImage->SetSpacing(faImage->GetSpacing()); m_DirectionImage->SetOrigin(faImage->GetOrigin()); m_DirectionImage->Allocate(); m_DirectionImage->FillBuffer(0.0); - for(int z=1; zGetPixel(ix); if(theval != 0) { /* Calculate point of gravity. We will consider each 3x3x3 neighbourhood as a unit cube. The center * point of each voxel will be a multiplicative of 1/6. The center of the unit cube is 3/6 = 1/2/ */ float cogX = 0.0; float cogY = 0.0; float cogZ = 0.0; float sum = 0.0; float l; int vecX = 0; int vecY = 0; int vecZ = 0; for(int dz=-1; dz<=1; dz++) for(int dy=-1; dy<=1; dy++) for(int dx=-1; dx<=1;dx++) { typename InputImageType::IndexType p; p[0] = x+dx; p[1] = y+dy; p[2] = z+dz; float mass = faImage->GetPixel(p); sum += mass; cogX += (float)dx*mass; cogY += (float)dy*mass; cogZ += (float)dz*mass; } cogX /= sum; cogY /= sum; cogZ /= sum; l = sqrt(cogX*cogX + cogY*cogY + cogZ*cogZ); if (l > 0.1) /* is CofG far enough away from centre voxel? */ { vecX = std::max(std::min(round(cogX/l),1),-1); vecY = std::max(std::min(round(cogY/l),1),-1); vecZ = std::max(std::min(round(cogZ/l),1),-1); } else // Find direction of max curvature { float maxcost=0, centreval=2*theval; for(int zz=0; zz<=1; zz++) // note - starts at zero as we're only searching half the voxels { for(int yy=-1; yy<=1; yy++) { for(int xx=-1; xx<=1; xx++) { if ( (zz==1) || (yy==1) || ((yy==0)&&(xx==1)) ) { float weighting = pow( (float)(xx*xx+yy*yy+zz*zz) , (float)-0.7 ); // power is arbitrary: maybe test other functions here typename InputImageType::IndexType i,j; i[0] = x+xx; i[1] = y+yy; i[2] = z+zz; j[0] = x-xx; j[1] = y-yy; j[2] = z-zz; float cost = weighting * ( centreval - (float)faImage->GetPixel(i) - (float)faImage->GetPixel(j)); if (cost>maxcost) { maxcost=cost; vecX=xx; vecY=yy; vecZ=zz; } } } } } } VectorType vec; vec[0] = vecX; vec[1] = vecY; vec[2]=vecZ; m_DirectionImage->SetPixel(ix, vec); } } mitk::ProgressBar::GetInstance()->Progress(); // Smooth m_DirectionImage and store in directionSmoothed by finding the // mode in a 3*3 neighbourhoud VectorImageType::Pointer directionSmoothed = VectorImageType::New(); directionSmoothed->SetRegions(faImage->GetRequestedRegion()); directionSmoothed->SetDirection(faImage->GetDirection()); directionSmoothed->SetSpacing(faImage->GetSpacing()); directionSmoothed->SetOrigin(faImage->GetOrigin()); directionSmoothed->Allocate(); VectorImageType::PixelType p; p[0]=0; p[1]=0; p[2]=0; directionSmoothed->FillBuffer(p); - for(int z=1; zGetPixel(i); xxx = v[0]; yyy = v[1]; zzz = v[2]; localsum[(1+zzz)*9+(1+yyy)*3+1+xxx]++; localsum[(1-zzz)*9+(1-yyy)*3+1-xxx]++; } for(int zz=-1; zz<=1; zz++) for(int yy=-1; yy<=1; yy++) for(int xx=-1; xx<=1; xx++) { if (localsum[(1+zz)*9+(1+yy)*3+1+xx]>localmax) { localmax=localsum[(1+zz)*9+(1+yy)*3+1+xx]; VectorType v; v[0] = xx; v[1] = yy; v[2] = zz; directionSmoothed->SetPixel(ix, v); } } delete localsum; } m_DirectionImage = directionSmoothed; mitk::ProgressBar::GetInstance()->Progress(); // Do non-max-suppression in the direction of perp and set as output of the filter typename OutputImageType::Pointer outputImg = OutputImageType::New(); outputImg->SetRegions(faImage->GetRequestedRegion()); outputImg->SetDirection(faImage->GetDirection()); outputImg->SetSpacing(faImage->GetSpacing()); outputImg->SetOrigin(faImage->GetOrigin()); outputImg->Allocate(); outputImg->FillBuffer(0.0); - for(int z=1; zGetPixel(ix); VectorType v = directionSmoothed->GetPixel(ix); typename VectorImageType::IndexType i; i[0] = x-v[0]; i[1] = y-v[1]; i[2] = z-v[2]; float min = faImage->GetPixel(i); i[0] = x+v[0]; i[1] = y+v[1]; i[2] = z+v[2]; float plus = faImage->GetPixel(i); i[0] = x-2*v[0]; i[1] = y-2*v[1]; i[2] = z-2*v[2]; float minmin = faImage->GetPixel(i); i[0] = x+2*v[0]; i[1] = y+2*v[1]; i[2] = z+2*v[2]; float plusplus = faImage->GetPixel(i); if( ((v[0]!=0) || (v[1]!=0) || (v[2]!=0)) && theval >= plus && theval > min && theval >= plusplus && theval > minmin ) { outputImg->SetPixel(ix, theval); } } Superclass::SetNthOutput( 0, outputImg ); mitk::ProgressBar::GetInstance()->Progress(); } // Can provide a vector image to visualize the gradient image used in the search for local maxima. template< class TInputImage, class TOutputImage > itk::VectorImage::Pointer SkeletonizationFilter::GetGradientImage() { GradientImageType::Pointer gradImg = GradientImageType::New(); if(m_DirectionImage.IsNotNull()) { gradImg->SetSpacing(m_DirectionImage->GetSpacing()); gradImg->SetOrigin(m_DirectionImage->GetOrigin()); gradImg->SetDirection(m_DirectionImage->GetDirection()); gradImg->SetRegions(m_DirectionImage->GetLargestPossibleRegion().GetSize()); gradImg->SetVectorLength(3); gradImg->Allocate(); VectorImageType::SizeType size = m_DirectionImage->GetLargestPossibleRegion().GetSize(); for(int i=0; i ix; ix[0] = i; ix[1] = j; ix[2] = k; VectorType vec = m_DirectionImage->GetPixel(ix); itk::VariableLengthVector pixel; pixel.SetSize(3); pixel.SetElement(0, vec.GetElement(0)); pixel.SetElement(1, vec.GetElement(1)); pixel.SetElement(2, vec.GetElement(2)); gradImg->SetPixel(ix, pixel); } } } } return gradImg; } } #endif // _itkSkeletonizationFilter_txx diff --git a/Modules/DiffusionImaging/Quantification/Algorithms/mitkTractAnalyzer.cpp b/Modules/DiffusionImaging/Quantification/Algorithms/mitkTractAnalyzer.cpp index 31655bab3d..cfca629dca 100644 --- a/Modules/DiffusionImaging/Quantification/Algorithms/mitkTractAnalyzer.cpp +++ b/Modules/DiffusionImaging/Quantification/Algorithms/mitkTractAnalyzer.cpp @@ -1,226 +1,227 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkTractAnalyzer_cpp #define __mitkTractAnalyzer_cpp #include #include #include #include #include #include #include #include #include using namespace std; namespace mitk { TractAnalyzer::TractAnalyzer() { } void TractAnalyzer::MakeRoi() { m_CostSum = 0.0; int n = 0; if(m_PointSetNode.IsNotNull()) { n = m_PointSetNode->GetSize(); if(n==0) { QMessageBox msgBox; msgBox.setText("No points have been set yet."); msgBox.exec(); } } else{ QMessageBox msgBox; msgBox.setText("No points have been set yet."); msgBox.exec(); } std::string pathDescription = ""; std::vector< itk::Index<3> > totalPath; if(n>0) { for(int i=0; iProgress(); mitk::Point3D p = m_PointSetNode->GetPoint(i); mitk::Point3D p2 = m_PointSetNode->GetPoint(i+1); itk::Index<3> startPoint; itk::Index<3> endPoint; m_InputImage->GetGeometry()->WorldToIndex(p,startPoint); m_InputImage->GetGeometry()->WorldToIndex(p2,endPoint); MITK_INFO << "create roi"; std::vector< itk::Index<3> > path = CreateSegment(startPoint, endPoint); for(std::vector< itk::Index<3> >::iterator it = path.begin(); it != path.end(); it++) { itk::Index<3> ix = *it; if (!(ix==endPoint)) { mitk::ProgressBar::GetInstance()->Progress(); totalPath.push_back(ix); std::stringstream ss; ss << ix[0] << " " << ix[1] << " " << ix[2] << "\n"; pathDescription += ss.str(); } else { // Only when dealing with the last segment the last point should be added. This one will not occur // as the first point of the next roi segment. if(i == (n-2)) { totalPath.push_back(endPoint); std::stringstream ss; ss << endPoint[0] << " " << endPoint[1] << " " << endPoint[2] << "\n"; pathDescription += ss.str(); } } } } // save pathDescription to m_PathDescription m_PathDescription = pathDescription; FloatImageType::Pointer itkImg = FloatImageType::New(); mitk::CastToItkImage(m_InputImage, itkImg); CharImageType::Pointer roiImg = CharImageType::New(); roiImg->SetRegions(itkImg->GetLargestPossibleRegion().GetSize()); roiImg->SetOrigin(itkImg->GetOrigin()); roiImg->SetSpacing(itkImg->GetSpacing()); roiImg->SetDirection(itkImg->GetDirection()); roiImg->Allocate(); roiImg->FillBuffer(0); std::vector< itk::Index<3> > roi; std::vector< itk::Index<3> >::iterator it; for(it = totalPath.begin(); it != totalPath.end(); it++) { itk::Index<3> ix = *it; roiImg->SetPixel(ix, 1); roi.push_back(ix); } m_TbssRoi = mitk::TbssRoiImage::New(); m_TbssRoi->SetRoi(roi); m_TbssRoi->SetImage(roiImg); m_TbssRoi->InitializeFromImage(); } } std::vector< itk::Index<3> > TractAnalyzer::CreateSegment(itk::Index<3> startPoint, itk::Index<3> endPoint) { typedef itk::ShortestPathImageFilter ShortestPathFilterType; typedef itk::ShortestPathCostFunctionTbss CostFunctionType; FloatImageType::Pointer meanSkeleton; mitk::CastToItkImage(m_InputImage, meanSkeleton); // Only use the mitk image if(meanSkeleton) { CostFunctionType::Pointer costFunction = CostFunctionType::New(); costFunction->SetImage(meanSkeleton); costFunction->SetStartIndex(startPoint); costFunction->SetEndIndex(endPoint); costFunction->SetThreshold(m_Threshold); ShortestPathFilterType::Pointer pathFinder = ShortestPathFilterType::New(); pathFinder->SetCostFunction(costFunction); pathFinder->SetFullNeighborsMode(true); pathFinder->SetGraph_fullNeighbors(true); //pathFinder->SetCalcMode(ShortestPathFilterType::A_STAR); pathFinder->SetInput(meanSkeleton); pathFinder->SetStartIndex(startPoint); pathFinder->SetEndIndex(endPoint); pathFinder->Update(); double segmentCost = 0.0; std::vector< itk::Index<3> > path = pathFinder->GetVectorPath(); - for(int i=0; i ix1 = path[i]; itk::Index<3> ix2 = path[i+1]; segmentCost += costFunction->GetCost(ix1, ix2); } m_CostSum += segmentCost; return pathFinder->GetVectorPath(); } + return std::vector< itk::Index<3> >(); } } #endif diff --git a/Modules/DiffusionImaging/Quantification/CMakeLists.txt b/Modules/DiffusionImaging/Quantification/CMakeLists.txt index 1b5239a874..592bd30d07 100644 --- a/Modules/DiffusionImaging/Quantification/CMakeLists.txt +++ b/Modules/DiffusionImaging/Quantification/CMakeLists.txt @@ -1,9 +1,10 @@ #DiffusionImaging/Quantification MITK_CREATE_MODULE( Quantification SUBPROJECTS MITK-DTI INCLUDE_DIRS Algorithms IODataStructures IODataStructures/TbssImages Rendering ${CMAKE_CURRENT_BINARY_DIR} DEPENDS DiffusionCore FiberTracking MitkGraphAlgorithms QmitkExt + WARNINGS_AS_ERRORS ) add_subdirectory(Testing) diff --git a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssImageReader.cpp b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssImageReader.cpp index 39d0507e70..7225607d0f 100644 --- a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssImageReader.cpp +++ b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssImageReader.cpp @@ -1,295 +1,295 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkNrrdTbssImageReader_cpp #define __mitkNrrdTbssImageReader_cpp #include "mitkNrrdTbssImageReader.h" #include "itkImageFileReader.h" #include "itkMetaDataObject.h" #include "itkNrrdImageIO.h" #include "itkNiftiImageIO.h" #include #include #include #include "itksys/SystemTools.hxx" namespace mitk { void NrrdTbssImageReader ::GenerateData() { // Since everything is completely read in GenerateOutputInformation() it is stored // in a cache variable. A timestamp is associated. // If the timestamp of the cache variable is newer than the MTime, we only need to // assign the cache variable to the DataObject. // Otherwise, the tree must be read again from the file and OuputInformation must // be updated! if ( ( ! m_OutputCache ) || ( this->GetMTime( ) > m_CacheTime.GetMTime( ) ) ) { this->GenerateOutputInformation(); itkWarningMacro("Cache regenerated!"); } if (!m_OutputCache) { itkWarningMacro("Tree cache is empty!") } static_cast(this->GetPrimaryOutput()) ->SetImage(m_OutputCache->GetImage()); static_cast(this->GetPrimaryOutput()) ->SetGroupInfo(m_OutputCache->GetGroupInfo()); static_cast(this->GetPrimaryOutput()) ->InitializeFromVectorImage(); } void NrrdTbssImageReader ::GenerateOutputInformation() { OutputType::Pointer outputForCache = OutputType::New(); if ( m_FileName == "") { throw itk::ImageFileReaderException(__FILE__, __LINE__, "Sorry, the filename to be read is empty!"); } else { try { const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, NULL ); if ( locale.compare(currLocale)!=0 ) { try { MITK_INFO << " ** Changing locale from " << setlocale(LC_ALL, NULL) << " to '" << locale << "'"; setlocale(LC_ALL, locale.c_str()); } catch(...) { MITK_INFO << "Could not set locale " << locale; } } MITK_INFO << "NrrdTbssImageReader READING IMAGE INFORMATION"; ImageType::Pointer img; std::string ext = itksys::SystemTools::GetFilenameLastExtension(m_FileName); ext = itksys::SystemTools::LowerCase(ext); if (ext == ".tbss") { typedef itk::ImageFileReader FileReaderType; FileReaderType::Pointer reader = FileReaderType::New(); reader->SetFileName(this->m_FileName); itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); reader->SetImageIO(io); reader->Update(); img = reader->GetOutput(); MITK_INFO << "NrrdTbssImageReader READING HEADER INFORMATION"; itk::MetaDataDictionary imgMetaDictionary = img->GetMetaDataDictionary(); std::vector imgMetaKeys = imgMetaDictionary.GetKeys(); std::vector::const_iterator itKey = imgMetaKeys.begin(); std::string metaString; std::string measurementInfo; std::vector< std::pair > groups; for (; itKey != imgMetaKeys.end(); itKey ++) { itk::ExposeMetaData (imgMetaDictionary, *itKey, metaString); MITK_INFO << *itKey << " ---> " << metaString; if (itKey->find("Group_index") != std::string::npos) { std::vector tokens; this->Tokenize(metaString, tokens, " "); std::pair< std::string, int > p; p.first=""; - for (int i=0; ifind("Measurement info") != std::string::npos) { measurementInfo = metaString; } } outputForCache->SetGroupInfo(groups); outputForCache->SetMeasurementInfo(measurementInfo); } // This call updates the output information of the associated VesselTreeData outputForCache->SetImage(img); // Since we have already read the tree, we can store it in a cache variable // so that it can be assigned to the DataObject in GenerateData(); m_OutputCache = outputForCache; m_CacheTime.Modified(); try { MITK_INFO << " ** Changing locale back from " << setlocale(LC_ALL, NULL) << " to '" << currLocale << "'"; setlocale(LC_ALL, currLocale.c_str()); } catch(...) { MITK_INFO << "Could not reset locale " << currLocale; } } catch(std::exception& e) { MITK_INFO << "Std::Exception while reading file!!"; MITK_INFO << e.what(); throw itk::ImageFileReaderException(__FILE__, __LINE__, e.what()); } catch(...) { MITK_INFO << "Exception while reading file!!"; throw itk::ImageFileReaderException(__FILE__, __LINE__, "Sorry, an error occurred while reading the requested vessel tree file!"); } } } const char* NrrdTbssImageReader ::GetFileName() const { return m_FileName.c_str(); } void NrrdTbssImageReader ::SetFileName(const char* aFileName) { m_FileName = aFileName; } const char* NrrdTbssImageReader ::GetFilePrefix() const { return m_FilePrefix.c_str(); } void NrrdTbssImageReader ::SetFilePrefix(const char* aFilePrefix) { m_FilePrefix = aFilePrefix; } const char* NrrdTbssImageReader ::GetFilePattern() const { return m_FilePattern.c_str(); } void NrrdTbssImageReader ::SetFilePattern(const char* aFilePattern) { m_FilePattern = aFilePattern; } bool NrrdTbssImageReader ::CanReadFile(const std::string filename, const std::string filePrefix, const std::string filePattern) { // First check the extension if( filename == "" ) return false; // check if image is serie if( filePattern != "" && filePrefix != "" ) return false; std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename); ext = itksys::SystemTools::LowerCase(ext); if (ext == ".tbss") { itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); typedef itk::ImageFileReader FileReaderType; FileReaderType::Pointer reader = FileReaderType::New(); reader->SetImageIO(io); reader->SetFileName(filename); try { reader->Update(); } catch(itk::ExceptionObject e) { MITK_INFO << e.GetDescription(); return false; } return true; } return false; } } //namespace MITK #endif diff --git a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssImageWriter.h b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssImageWriter.h index 9d285c094b..b128c6a05d 100644 --- a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssImageWriter.h +++ b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssImageWriter.h @@ -1,140 +1,141 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_NRRDTBSSVOL_WRITER__H_ #define _MITK_NRRDTBSSVOL_WRITER__H_ #include #include #include #include #include "QuantificationExports.h" namespace mitk { /** * Writes diffusion volumes to a file * @ingroup Process */ class Quantification_EXPORT NrrdTbssImageWriter : public mitk::FileWriterWithInformation { public: mitkClassMacro( NrrdTbssImageWriter, mitk::FileWriterWithInformation ) mitkWriterMacro itkNewMacro( Self ) typedef mitk::TbssImage InputType; /** * Sets the filename of the file to write. * @param FileName the nameInputType of the file to write. */ itkSetStringMacro( FileName ) /** * @returns the name of the file to be written to disk. */ itkGetStringMacro( FileName ) /** * @warning multiple write not (yet) supported */ itkSetStringMacro( FilePrefix ) /** * @warning multiple write not (yet) supported */ itkGetStringMacro( FilePrefix ) /** * @warning multiple write not (yet) supported */ itkSetStringMacro( FilePattern ) /** * @warning multiple write not (yet) supported */ itkGetStringMacro( FilePattern ) /**image * Sets the input object for the filter. * @param input the diffusion volumes to write to file. */ + using ProcessObject::SetInput; void SetInput( InputType* input ); /**itk::VectorImage * @returns the 0'th input object of the filter. */ InputType* GetInput(); /** * Returns false if an error happened during writing */ itkGetMacro( Success, bool ) /** * @return possible file extensions for the data type associated with the writer */ virtual std::vector GetPossibleFileExtensions(); // FileWriterWithInformation methods virtual const char * GetDefaultFilename() { return "TbssImage.tbss"; } virtual const char * GetFileDialogPattern() { return "Tbss Images (*.tbss)"; } virtual const char * GetDefaultExtension() { return ".tbss"; } virtual bool CanWriteBaseDataType(BaseData::Pointer data) { return (dynamic_cast(data.GetPointer()) != NULL); } virtual void DoWrite(BaseData::Pointer data) { if (CanWriteBaseDataType(data)) { this->SetInput(dynamic_cast(data.GetPointer())); this->Update(); } } protected: NrrdTbssImageWriter(); virtual ~NrrdTbssImageWriter(); virtual void GenerateData(); std::string m_FileName; std::string m_FilePrefix; std::string m_FilePattern; bool m_Success; }; } // end of namespace mitk #endif diff --git a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssRoiImageWriter.cpp b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssRoiImageWriter.cpp index 0f0f480842..7373f98e3c 100644 --- a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssRoiImageWriter.cpp +++ b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssRoiImageWriter.cpp @@ -1,142 +1,142 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkNrrdTbssRoiImageWriter__cpp #define __mitkNrrdTbssRoiImageWriter__cpp #include "mitkNrrdTbssRoiImageWriter.h" #include "itkMetaDataDictionary.h" #include "itkMetaDataObject.h" #include "itkNrrdImageIO.h" //#include "itkNiftiImageIO.h" #include "itkImageFileWriter.h" #include "itksys/SystemTools.hxx" #include #include mitk::NrrdTbssRoiImageWriter::NrrdTbssRoiImageWriter() : m_FileName(""), m_FilePrefix(""), m_FilePattern(""), m_Success(false) { this->SetNumberOfRequiredInputs( 1 ); } mitk::NrrdTbssRoiImageWriter::~NrrdTbssRoiImageWriter() {} void mitk::NrrdTbssRoiImageWriter::GenerateData() { m_Success = false; InputType* input = this->GetInput(); if (input == NULL) { itkWarningMacro(<<"Sorry, input to NrrdTbssImageWriter is NULL!") return; } if ( m_FileName == "" ) { itkWarningMacro( << "Sorry, filename has not been set!" ) return ; } char keybuffer[512]; char valbuffer[512]; std::vector< itk::Index<3> > roi = input->GetRoi(); std::vector< itk::Index<3> >::iterator it = roi.begin(); int i=0; while(it != roi.end()) { itk::Index<3> ix = *it; sprintf( keybuffer, "ROI_index_%04d", i ); - sprintf( valbuffer, "%1d %1d %1d", ix[0],ix[1],ix[2]); + sprintf( valbuffer, "%ld %ld %ld", ix[0],ix[1],ix[2]); std::cout << valbuffer << std::endl; //input->GetImage()->GetMetaDataDictionary(); itk::EncapsulateMetaData< std::string >(input->GetImage()->GetMetaDataDictionary(), std::string(keybuffer), std::string(valbuffer)); it++; ++i; } std::string structure = input->GetStructure(); itk::EncapsulateMetaData< std::string >(input->GetImage()->GetMetaDataDictionary(), "structure", structure); typedef itk::Image ImageType; ImageType::Pointer img = input->GetImage(); itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); io->SetFileType( itk::ImageIOBase::Binary ); io->UseCompressionOn(); typedef itk::ImageFileWriter WriterType; WriterType::Pointer nrrdWriter = WriterType::New(); nrrdWriter->UseInputMetaDataDictionaryOn(); nrrdWriter->SetInput( img ); nrrdWriter->SetImageIO(io); nrrdWriter->SetFileName(m_FileName); // nrrdWriter->UseCompressionOn(); nrrdWriter->SetImageIO(io); try { nrrdWriter->Update(); } catch (itk::ExceptionObject e) { std::cout << e << std::endl; } m_Success = true; } void mitk::NrrdTbssRoiImageWriter::SetInput( InputType* tbssVol ) { this->ProcessObject::SetNthInput( 0, tbssVol ); } mitk::TbssRoiImage* mitk::NrrdTbssRoiImageWriter::GetInput() { if ( this->GetNumberOfInputs() < 1 ) { return NULL; } else { return dynamic_cast ( this->ProcessObject::GetInput( 0 ) ); } } std::vector mitk::NrrdTbssRoiImageWriter::GetPossibleFileExtensions() { std::vector possibleFileExtensions; possibleFileExtensions.push_back(".roi"); return possibleFileExtensions; } #endif //__mitkNrrdTbssRoiImageWriter__cpp diff --git a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssRoiImageWriter.h b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssRoiImageWriter.h index 7f461ae60b..2e27d09ea0 100644 --- a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssRoiImageWriter.h +++ b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssRoiImageWriter.h @@ -1,138 +1,139 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_NRRDTBSSROIVOL_WRITER__H_ #define _MITK_NRRDTBSSROIVOL_WRITER__H_ #include #include #include #include #include "QuantificationExports.h" namespace mitk { /** * Writes diffusion volumes to a file * @ingroup Process */ class Quantification_EXPORT NrrdTbssRoiImageWriter : public mitk::FileWriterWithInformation { public: typedef itk::Image ImageType; mitkClassMacro( NrrdTbssRoiImageWriter, mitk::FileWriterWithInformation ) mitkWriterMacro itkNewMacro( Self ) typedef mitk::TbssRoiImage InputType; /** * Sets the filename of the file to write. * @param FileName the nameInputType of the file to write. */ itkSetStringMacro( FileName ); /** * @returns the name of the file to be written to disk. */ itkGetStringMacro( FileName ); /** * @warning multiple write not (yet) supported */ itkSetStringMacro( FilePrefix ); /** * @warning multiple write not (yet) supported */ itkGetStringMacro( FilePrefix ); /** * @warning multiple write not (yet) supported */ itkSetStringMacro( FilePattern ); /** * @warning multiple write not (yet) supported */ itkGetStringMacro( FilePattern ); /**image * Sets the input object for the filter. * @param input the diffusion volumes to write to file. */ + using ProcessObject::SetInput; void SetInput( InputType* input ); /** * @returns the 0'th input object of the filter. */ InputType* GetInput(); /** * Returns false if an error happened during writing */ itkGetMacro( Success, bool ); /** * @return possible file extensions for the data type associated with the writer */ virtual std::vector GetPossibleFileExtensions(); // FileWriterWithInformation methods virtual const char * GetDefaultFilename() { return "TbssRoiImage.roi"; } virtual const char * GetFileDialogPattern() { return "Tbss Roi Images (*.roi)"; } virtual const char * GetDefaultExtension() { return ".roi"; } virtual bool CanWriteBaseDataType(BaseData::Pointer data) { return (dynamic_cast(data.GetPointer()) != NULL); } virtual void DoWrite(BaseData::Pointer data) { if (CanWriteBaseDataType(data)) { this->SetInput(dynamic_cast(data.GetPointer())); this->Update(); } } protected: NrrdTbssRoiImageWriter(); virtual ~NrrdTbssRoiImageWriter(); virtual void GenerateData(); std::string m_FileName; std::string m_FilePrefix; std::string m_FilePattern; bool m_Success; }; } // end of namespace mitk #endif diff --git a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssImage.cpp b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssImage.cpp index 4f96937c6d..5b7788800e 100644 --- a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssImage.cpp +++ b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssImage.cpp @@ -1,114 +1,114 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkTbssImage__cpp #define __mitkTbssImage__cpp #include "mitkTbssImage.h" #include "itkImageRegionIterator.h" #include "itkImageRegionConstIterator.h" #include "mitkImageCast.h" mitk::TbssImage::TbssImage() { } void mitk::TbssImage::InitializeFromVectorImage() { if(!m_Image) { MITK_INFO << "TBSS Image could not be initialized. Set all members first!" << std::endl; return; } typedef itk::Image ImgType; ImgType::Pointer img = ImgType::New(); img->SetSpacing( m_Image->GetSpacing() ); // Set the image spacing img->SetOrigin( m_Image->GetOrigin() ); // Set the image origin img->SetDirection( m_Image->GetDirection() ); // Set the image direction img->SetLargestPossibleRegion( m_Image->GetLargestPossibleRegion()); img->SetBufferedRegion( m_Image->GetLargestPossibleRegion() ); img->Allocate(); int vecLength = m_Image->GetVectorLength(); InitializeByItk( img.GetPointer(), 1, vecLength ); //for(int i=0; i itw (img, img->GetLargestPossibleRegion() ); - itw = itw.Begin(); + itw.GoToBegin(); itk::ImageRegionConstIterator itr (m_Image, m_Image->GetLargestPossibleRegion() ); - itr = itr.Begin(); + itr.GoToBegin(); while(!itr.IsAtEnd()) { itw.Set(itr.Get().GetElement(0)); ++itr; ++itw; } // init SetImportVolume(img->GetBufferPointer());//, 0, 0, CopyMemory); //SetVolume( img->GetBufferPointer(), i ); //}:: m_DisplayIndex = 0; MITK_INFO << "Tbss-Image successfully initialized."; } void mitk::TbssImage::SetDisplayIndexForRendering(int displayIndex) { MITK_INFO << "displayindex: " << displayIndex; int index = displayIndex; int vecLength = m_Image->GetVectorLength(); index = index > vecLength-1 ? vecLength-1 : index; if( m_DisplayIndex != index ) { typedef itk::Image ImgType; ImgType::Pointer img = ImgType::New(); CastToItkImage(this, img); itk::ImageRegionIterator itw (img, img->GetLargestPossibleRegion() ); - itw = itw.Begin(); + itw.GoToBegin(); itk::ImageRegionConstIterator itr (m_Image, m_Image->GetLargestPossibleRegion() ); - itr = itr.Begin(); + itr.GoToBegin(); while(!itr.IsAtEnd()) { itw.Set(itr.Get().GetElement(index)); ++itr; ++itw; } } m_DisplayIndex = index; } #endif /* __mitkTbssImage__cpp */ diff --git a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssImageSource.cpp b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssImageSource.cpp index c37424b81a..c428943138 100644 --- a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssImageSource.cpp +++ b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssImageSource.cpp @@ -1,51 +1,61 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __MITK_NRRD_TBSS_VOULMES_IO_FACTORY_CPP__ #define __MITK_NRRD_TBSS_VOULMES_IO_FACTORY_CPP__ #include "mitkTbssImageSource.h" #include "mitkTbssImage.h" mitk::TbssImageSource::TbssImageSource() { // Create the output. We use static_cast<> here because we know the default // output must be of type DiffusionImage mitk::TbssImage::Pointer output = static_cast(this->MakeOutput(0).GetPointer()); Superclass::SetNumberOfRequiredOutputs(1); Superclass::SetNthOutput(0, output.GetPointer()); } +itk::DataObject::Pointer mitk::TbssImageSource::MakeOutput ( DataObjectPointerArraySizeType /*idx*/ ) +{ + return OutputType::New().GetPointer(); +} + -itk::DataObject::Pointer mitk::TbssImageSource::MakeOutput( DataObjectPointerArraySizeType /*idx*/ ) +itk::DataObject::Pointer mitk::TbssImageSource::MakeOutput( const DataObjectIdentifierType & name ) { - return static_cast(mitk::TbssImage::New().GetPointer()); + itkDebugMacro("MakeOutput(" << name << ")"); + if( this->IsIndexedOutputName(name) ) + { + return this->MakeOutput( this->MakeIndexFromOutputName(name) ); + } + return static_cast(OutputType::New().GetPointer()); } mitk::TbssImageSource::OutputType* mitk::TbssImageSource::GetOutput(unsigned int idx) { return static_cast (this->ProcessObject::GetOutput(idx)); } #endif //__MITK_NRRD_TBSS_VOULMES_IO_FACTORY_CPP__ diff --git a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssImageSource.h b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssImageSource.h index bc717e2ca2..70adeb9a06 100644 --- a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssImageSource.h +++ b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssImageSource.h @@ -1,79 +1,93 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_TBSS_IMAGE_DATA_SOURCE_H_HEADER_ #define _MITK_TBSS_IMAGE_DATA_SOURCE_H_HEADER_ // Should be changed in a new type for TBSS #include "mitkImageSource.h" #include "QuantificationExports.h" namespace mitk { class TbssImage; //##Documentation //## @brief Superclass of all classes generating diffusion volumes (instances //## of class DiffusionImage) as output. //## //## @ingroup Process class Quantification_EXPORT TbssImageSource : public ImageSource { public: - mitkClassMacro(TbssImageSource, BaseProcess) + mitkClassMacro(TbssImageSource, BaseDataSource) itkNewMacro(Self) typedef TbssImage OutputType; typedef itk::DataObject::Pointer DataObjectPointer; - virtual DataObjectPointer MakeOutput(DataObjectPointerArraySizeType idx); + /** + * Allocates a new output object and returns it. Currently the + * index idx is not evaluated. + * @param idx the index of the output for which an object should be created + * @returns the new object + */ + virtual itk::DataObject::Pointer MakeOutput ( DataObjectPointerArraySizeType idx ); + + /** + * This is a default implementation to make sure we have something. + * Once all the subclasses of ProcessObject provide an appopriate + * MakeOutput(), then ProcessObject::MakeOutput() can be made pure + * virtual. + */ + virtual itk::DataObject::Pointer MakeOutput(const DataObjectIdentifierType &name); OutputType* GetOutput() { return itkDynamicCastInDebugMode( this->GetPrimaryOutput() ); } //OutputType * GetOutput(unsigned int idx); //void SetOutput(OutputType* output); //{return Superclass::GetOutput();} OutputType* GetOutput(unsigned int idx); //virtual void GraftOutput(OutputType* graft); //virtual void GraftNthOutput(unsigned int idx, OutputType *graft); protected: TbssImageSource(); virtual ~TbssImageSource(){} }; } // namespace mitk //#include "mitkTbssImageSource.cpp" #endif /* _MITK_DIFFUSION_IMAGE_DATA_SOURCE_H_HEADER_ */ diff --git a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssImporter.cpp b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssImporter.cpp index 7cd312ad65..e9d970dc83 100644 --- a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssImporter.cpp +++ b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssImporter.cpp @@ -1,137 +1,137 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkTbssImporter_cpp #define __mitkTbssImporter_cpp #include "mitkTbssImporter.h" #include #include "mitkImagePixelReadAccessor.h" namespace mitk { TbssImage::Pointer TbssImporter::Import() { mitk::TbssImage::Pointer tbssImg = mitk::TbssImage::New(); mitkPixelTypeMultiplex1( Import, m_InputVolume->GetPixelType(), tbssImg); return tbssImg; } template void TbssImporter::Import(const mitk::PixelType , mitk::TbssImage::Pointer tbssImg) { // read all images with all_*.nii.gz MITK_INFO << "called import ..."; m_Data = DataImageType::New(); mitk::Geometry3D* geo = m_InputVolume->GetGeometry(); mitk::Vector3D spacing = geo->GetSpacing(); mitk::Point3D origin = geo->GetOrigin(); //Size size DataImageType::SizeType dataSize; dataSize[0] = m_InputVolume->GetDimension(0); dataSize[1] = m_InputVolume->GetDimension(1); dataSize[2] = m_InputVolume->GetDimension(2); m_Data->SetRegions(dataSize); // Set spacing DataImageType::SpacingType dataSpacing; dataSpacing[0] = spacing[0]; dataSpacing[1] = spacing[1]; dataSpacing[2] = spacing[2]; m_Data->SetSpacing(dataSpacing); DataImageType::PointType dataOrigin; dataOrigin[0] = origin[0]; dataOrigin[1] = origin[1]; dataOrigin[2] = origin[2]; m_Data->SetOrigin(dataOrigin); //Direction must be set DataImageType::DirectionType dir; const itk::Transform* transform3D = geo->GetParametricTransform(); itk::Transform::ParametersType p = transform3D->GetParameters(); int t=0; for(int i=0; i<3; i++) { for(int j=0; j<3; j++) { dir[i][j] = p[t]; // row-major order (where the column index varies the fastest) t++; } } m_Data->SetDirection(dir); // Set the length to one because otherwise allocate fails. Should be changed when groups/measurements are added m_Data->SetVectorLength(m_InputVolume->GetDimension(3)); m_Data->Allocate(); // Determine vector size of m_Data int vecSize = m_Data->GetVectorLength(); MITK_INFO << "vecsize " < readTbss( m_InputVolume ); - for(int i=0; i pixel; itk::Index<3> id; itk::Index<4> ix; ix[0] = id[0] = i; ix[1] = id[1] = j; ix[2] = id[2] = k; pixel = m_Data->GetPixel(id); for(int z=0; zSetPixel(id, pixel); } } } } catch ( mitk::Exception& e ) { MITK_ERROR << "TbssImporter::Import: No read access to tbss image: " << e.what() ; } tbssImg->SetGroupInfo(m_Groups); tbssImg->SetMeasurementInfo(m_MeasurementInfo); tbssImg->SetImage(m_Data); tbssImg->InitializeFromVectorImage(); } } #endif // __mitkTbssImporter_cpp diff --git a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssRoiImageSource.cpp b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssRoiImageSource.cpp index 7822a3de94..1b16532217 100644 --- a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssRoiImageSource.cpp +++ b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssRoiImageSource.cpp @@ -1,49 +1,60 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __MITK_NRRD_TBSSROI_VOLUMES_IO_FACTORY_CPP__ #define __MITK_NRRD_TBSSROI_VOLUMES_IO_FACTORY_CPP__ #include "mitkTbssRoiImageSource.h" #include "mitkTbssRoiImage.h" mitk::TbssRoiImageSource::TbssRoiImageSource() { // Create the output. We use static_cast<> here because we know the default // output must be of type DiffusionImage mitk::TbssRoiImage::Pointer output = static_cast(this->MakeOutput(0).GetPointer()); Superclass::SetNumberOfRequiredOutputs(1); Superclass::SetNthOutput(0, output.GetPointer()); } -itk::DataObject::Pointer mitk::TbssRoiImageSource::MakeOutput( itk::ProcessObject::DataObjectPointerArraySizeType /*idx*/ ) +itk::DataObject::Pointer mitk::TbssRoiImageSource::MakeOutput ( DataObjectPointerArraySizeType /*idx*/ ) { - return static_cast(mitk::TbssRoiImage::New().GetPointer()); + return OutputType::New().GetPointer(); +} + + +itk::DataObject::Pointer mitk::TbssRoiImageSource::MakeOutput( const DataObjectIdentifierType & name ) +{ + itkDebugMacro("MakeOutput(" << name << ")"); + if( this->IsIndexedOutputName(name) ) + { + return this->MakeOutput( this->MakeIndexFromOutputName(name) ); + } + return static_cast(OutputType::New().GetPointer()); } mitk::TbssRoiImageSource::OutputType* mitk::TbssRoiImageSource::GetOutput(unsigned int idx) { return static_cast (this->ProcessObject::GetOutput(idx)); } #endif //__MITK_NRRD_TBSS_VOULMES_IO_FACTORY_CPP__ diff --git a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssRoiImageSource.h b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssRoiImageSource.h index 4570c69165..91289188f1 100644 --- a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssRoiImageSource.h +++ b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkTbssRoiImageSource.h @@ -1,62 +1,76 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_TBSS_ROI_IMAGE_DATA_SOURCE_H_HEADER_ #define _MITK_TBSS_ROI_IMAGE_DATA_SOURCE_H_HEADER_ // Should be changed in a new type for TBSS #include "mitkImageSource.h" #include "QuantificationExports.h" namespace mitk { class TbssRoiImage; //##Documentation //## @brief Superclass of all classes generating diffusion volumes (instances //## of class DiffusionImage) as output. //## //## @ingroup Process class Quantification_EXPORT TbssRoiImageSource : public ImageSource { public: - mitkClassMacro(TbssRoiImageSource, BaseProcess) + mitkClassMacro(TbssRoiImageSource, BaseDataSource) itkNewMacro(Self) typedef TbssRoiImage OutputType; typedef itk::DataObject::Pointer DataObjectPointer; - virtual DataObjectPointer MakeOutput(DataObjectPointerArraySizeType idx); + /** + * Allocates a new output object and returns it. Currently the + * index idx is not evaluated. + * @param idx the index of the output for which an object should be created + * @returns the new object + */ + virtual itk::DataObject::Pointer MakeOutput ( DataObjectPointerArraySizeType idx ); + + /** + * This is a default implementation to make sure we have something. + * Once all the subclasses of ProcessObject provide an appopriate + * MakeOutput(), then ProcessObject::MakeOutput() can be made pure + * virtual. + */ + virtual itk::DataObject::Pointer MakeOutput(const DataObjectIdentifierType &name); OutputType* GetOutput(unsigned int idx); protected: TbssRoiImageSource(); virtual ~TbssRoiImageSource(){} }; } // namespace mitk #endif /* _MITK_DIFFUSION_IMAGE_DATA_SOURCE_H_HEADER_ */ diff --git a/Modules/DiffusionImaging/Quantification/Testing/mitkTractAnalyzerTest.cpp b/Modules/DiffusionImaging/Quantification/Testing/mitkTractAnalyzerTest.cpp index a41c88aa87..e2b9600047 100644 --- a/Modules/DiffusionImaging/Quantification/Testing/mitkTractAnalyzerTest.cpp +++ b/Modules/DiffusionImaging/Quantification/Testing/mitkTractAnalyzerTest.cpp @@ -1,92 +1,92 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include /**Documentation * test for the class "mitkTractAnalyzer". */ int mitkTractAnalyzerTest(int argc , char* argv[]) { MITK_TEST_BEGIN("TractAnalyzer"); // Load image typedef itk::Image FloatImageType; typedef itk::ImageFileReader ImageReaderType; ImageReaderType::Pointer reader = ImageReaderType::New(); reader->SetFileName(argv[1]); reader->Update(); FloatImageType::Pointer itkImage = reader->GetOutput(); mitk::Image::Pointer mitkImage = mitk::Image::New(); mitk::CastToMitkImage(itkImage, mitkImage); // load point set mitk::PointSetReader::Pointer pointSetReader = mitk::PointSetReader::New(); pointSetReader->SetFileName(argv[2]); pointSetReader->Update(); mitk::PointSet::Pointer pointSet = pointSetReader->GetOutput(); mitk::TractAnalyzer analyzer; analyzer.SetInputImage(mitkImage); analyzer.SetThreshold(0.2); analyzer.SetPointSet(pointSet); analyzer.MakeRoi(); mitk::TbssRoiImage::Pointer tbssRoi = analyzer.GetRoiImage(); std::vector< itk::Index<3> > roi = tbssRoi->GetRoi(); // Output roi for debug purposes std::cout << "ROI\n"; - for(int t=0; t ix = roi.at(t); std::cout << ix[0] << ", " << ix[1] << ", " << ix[2] << "\n"; } std::cout << std::endl; // check the cost of the roi double cost = analyzer.GetCostSum(); std::cout << "Cost: " << cost << std::endl; bool equal = mitk::Equal(cost, 5162.854, 0.001); MITK_TEST_CONDITION(equal, "Checking cost of found ROI"); MITK_TEST_END(); } diff --git a/Modules/GraphAlgorithms/itkShortestPathCostFunctionTbss.txx b/Modules/GraphAlgorithms/itkShortestPathCostFunctionTbss.txx index 655801bbf2..ad3e33657c 100644 --- a/Modules/GraphAlgorithms/itkShortestPathCostFunctionTbss.txx +++ b/Modules/GraphAlgorithms/itkShortestPathCostFunctionTbss.txx @@ -1,83 +1,81 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkShortestPathCostFunctionTbss_cpp #define __itkShortestPathCostFunctionTbss_cpp #include namespace itk { // Constructor template ShortestPathCostFunctionTbss ::ShortestPathCostFunctionTbss() { } template double ShortestPathCostFunctionTbss ::GetCost(IndexType p1 ,IndexType p2) { // Cost function for tbss tract definition double c; if(this->m_Image->GetPixel(p2) < m_Threshold) { c = std::numeric_limits::max( ); } else { - typename TInputImageType::SpacingType spacing = this->m_Image->GetSpacing(); - double dxSqt = (p1[0]-p2[0]) * (p1[0]-p2[0]);// * (p1[0]-p2[0]); double dySqt = (p1[1]-p2[1]) * (p1[1]-p2[1]); double dzSqt = (p1[2]-p2[2]) * (p1[2]-p2[2]); double weight = this->m_Image->GetPixel(p2); c = sqrt(dxSqt + dySqt + dzSqt) + 1000 * (1-weight); } return c; } template void ShortestPathCostFunctionTbss ::Initialize() { } template double ShortestPathCostFunctionTbss ::GetMinCost() { return 1; } } // end namespace itk #endif // __itkShortestPathCostFunctionSimple_txx diff --git a/Modules/GraphAlgorithms/itkShortestPathImageFilter.h b/Modules/GraphAlgorithms/itkShortestPathImageFilter.h index 368185ca0d..673ca62ced 100644 --- a/Modules/GraphAlgorithms/itkShortestPathImageFilter.h +++ b/Modules/GraphAlgorithms/itkShortestPathImageFilter.h @@ -1,236 +1,236 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkShortestPathImageFilter_h #define __itkShortestPathImageFilter_h #include "itkImageToImageFilter.h" #include "itkShortestPathCostFunction.h" #include "itkShortestPathNode.h" #include #include // ------- INFORMATION ---------- /// SET FUNCTIONS //void SetInput( ItkImage ) // Compulsory //void SetStartIndex (const IndexType & StartIndex); // Compulsory //void SetEndIndex(const IndexType & EndIndex); // Compulsory //void SetFullNeighborsMode(bool) // Optional (default=false), if false N4, if true N26 //void SetActivateTimeOut(bool) // Optional (default=false), for debug issues: after 30s algorithms terminates. You can have a look at the VectorOrderImage to see how far it came //void SetMakeOutputImage(bool) // Optional (default=true), Generate an outputimage of the path. You can also get the path directoy with GetVectorPath() //void SetCalcAllDistances(bool) // Optional (default=false), Calculate Distances over the whole image. CAREFUL, algorithm time extends a lot. Necessary for GetDistanceImage //void SetStoreVectorOrder(bool) // Optional (default=false), Stores in which order the pixels were checked. Necessary for GetVectorOrderImage //void AddEndIndex(const IndexType & EndIndex) //Optional. By calling this function you can add several endpoints! The algorithm will look for several shortest Pathes. From Start to all Endpoints. // /// GET FUNCTIONS //std::vector< itk::Index<3> > GetVectorPath(); // returns the shortest path as vector //std::vector< std::vector< itk::Index<3> > GetMultipleVectorPathe(); // returns a vector of shortest Pathes (which are vectors of points) //GetDistanceImage // Returns the distance image //GetVectorOrderIMage // Returns the Vector Order image // // EXAMPLE USE // pleae see qmitkmitralvalvesegmentation4dtee bundle namespace itk { template class ShortestPathImageFilter : public ImageToImageFilter { public: //Standard Typedefs typedef ShortestPathImageFilter Self; typedef ImageToImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; // Typdefs for metric typedef ShortestPathCostFunction< TInputImageType > CostFunctionType; typedef typename CostFunctionType::Pointer CostFunctionTypePointer; // More typdefs for convenience typedef TInputImageType InputImageType; typedef typename TInputImageType::Pointer InputImagePointer; typedef typename TInputImageType::PixelType InputImagePixelType; typedef typename TInputImageType::SizeType InputImageSizeType; typedef typename TInputImageType::IndexType IndexType; typedef typename itk::ImageRegionIteratorWithIndex< InputImageType > InputImageIteratorType; typedef TOutputImageType OutputImageType; typedef typename TOutputImageType::Pointer OutputImagePointer; typedef typename TOutputImageType::PixelType OutputImagePixelType; typedef typename TOutputImageType::IndexType OutputImageIndexType; typedef ImageRegionIteratorWithIndex< OutputImageType > OutputImageIteratorType; typedef itk::ShapedNeighborhoodIterator< TInputImageType > itkShapedNeighborhoodIteratorType; // New Macro for smartpointer instantiation itkNewMacro(Self) // Run-time type information itkTypeMacro(ShortestPathImageFilter, ImageToImageFilter) // Display void PrintSelf( std::ostream& os, Indent indent ) const; // Compare function for A_STAR struct CompareNodeStar { bool operator()(ShortestPathNode *a, ShortestPathNode *b) { return (a->distAndEst > b->distAndEst); } }; // \brief Set Starpoint for ShortestPath Calculation void SetStartIndex (const IndexType & StartIndex); // \brief Adds Endpoint for multiple ShortestPath Calculation void AddEndIndex (const IndexType & index); // \brief Set Endpoint for ShortestPath Calculation void SetEndIndex(const IndexType & EndIndex); // \brief Set FullNeighborsMode. false = no diagonal neighbors, in 2D this means N4 Neigborhood. true = would be N8 in 2D itkSetMacro (FullNeighborsMode, bool); itkGetMacro (FullNeighborsMode, bool); // \brief Set Graph_fullNeighbors. false = no diagonal neighbors, in 2D this means N4 Neigborhood. true = would be N8 in 2D itkSetMacro (Graph_fullNeighbors,bool) // \brief (default=true), Produce output image, which shows the shortest path. But you can also get the shortest Path directly as vector with the function GetVectorPath itkSetMacro (MakeOutputImage, bool); itkGetMacro (MakeOutputImage, bool); // \brief (default=false), Store an Vector of Order, so you can call getVectorOrderImage after update itkSetMacro (StoreVectorOrder, bool); itkGetMacro (StoreVectorOrder, bool); // \brief (default=false), // Calculate all Distances to all pixels, so you can call getDistanceImage after update (warning algo will take a long time) itkSetMacro (CalcAllDistances, bool); itkGetMacro (CalcAllDistances, bool); // \brief (default=false), for debug issues: after 30s algorithms terminates. You can have a look at the VectorOrderImage to see how far it came itkSetMacro (ActivateTimeOut, bool); itkGetMacro (ActivateTimeOut, bool); // \brief returns shortest Path as vector std::vector< IndexType > GetVectorPath(); // \brief returns Multiple shortest Paths. You can call this function, when u performed a multiple shortest path search (one start, several ends) std::vector< std::vector< IndexType > > GetMultipleVectorPaths(); // \brief returns the vector order image. It shows in which order the pixels were checked. good for debugging. Be sure to have m_StoreVectorOrder=true OutputImagePointer GetVectorOrderImage(); // \brief returns the distance image. It shows the distances from the startpoint to all other pixels. Be sure to have m_CalcAllDistances=true OutputImagePointer GetDistanceImage(); // \brief Fill m_VectorPath void MakeShortestPathVector(); // \brief cleans up the filter void CleanUp(); itkSetObjectMacro( CostFunction, CostFunctionType ); // itkSetObjectMacro = set function that uses pointer as parameter itkGetObjectMacro( CostFunction, CostFunctionType ); protected: std::vector< IndexType > m_endPoints; // if you fill this vector, the algo will not rest until all endPoints have been reached std::vector< IndexType > m_endPointsClosed; ShortestPathNode* m_Nodes; // main list that contains all nodes NodeNumType m_Graph_NumberOfNodes; NodeNumType m_Graph_StartNode; NodeNumType m_Graph_EndNode; - int m_ImageDimensions; + unsigned int m_ImageDimensions; bool m_Graph_fullNeighbors; std::vector m_Graph_DiscoveredNodeList; ShortestPathImageFilter(Self&); // intentionally not implemented void operator=(const Self&); // intentionally not implemented const static int BACKGROUND = 0; const static int FOREGROUND = 255; bool m_FullNeighborsMode; bool m_MakeOutputImage; bool m_StoreVectorOrder; // Store an Vector of Order, so you can call getVectorOrderImage after update bool m_CalcAllDistances; // Calculate all Distances, so you can call getDistanceImage after update (warning algo will take a long time) bool multipleEndPoints; bool m_ActivateTimeOut; // if true, then i search max. 30 secs. then abort bool m_Initialized; CostFunctionTypePointer m_CostFunction; IndexType m_StartIndex, m_EndIndex; std::vector< IndexType > m_VectorPath; std::vector< std::vector< IndexType > > m_MultipleVectorPaths; std::vector< NodeNumType > m_VectorOrder; ShortestPathImageFilter(); ~ShortestPathImageFilter(); // \brief Create all the outputs void MakeOutputs(); // \brief Generate Data void GenerateData(); // \brief gets the estimate costs from pixel a to target. double getEstimatedCostsToTarget(const IndexType & a); typename InputImageType::Pointer m_magnitudeImage; // \brief Convert a indexnumber of a node in m_Nodes to image coordinates typename TInputImageType::IndexType NodeToCoord(NodeNumType); // \brief Convert image coordinate to a indexnumber of a node in m_Nodes unsigned int CoordToNode(IndexType); // \brief Returns the neighbors of a node std::vector GetNeighbors(NodeNumType nodeNum, bool FullNeighbors); // \brief Check if coords are in bounds of image bool CoordIsInBounds(IndexType); // \brief Initializes the graph void InitGraph(); // \brief Start ShortestPathSearch void StartShortestPathSearch(); }; } // end of namespace itk #include "itkShortestPathImageFilter.txx" #endif diff --git a/Modules/GraphAlgorithms/itkShortestPathImageFilter.txx b/Modules/GraphAlgorithms/itkShortestPathImageFilter.txx index 06c880b31b..de96309feb 100644 --- a/Modules/GraphAlgorithms/itkShortestPathImageFilter.txx +++ b/Modules/GraphAlgorithms/itkShortestPathImageFilter.txx @@ -1,953 +1,939 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkShortestPathImageFilter_txx #define __itkShortestPathImageFilter_txx #include "itkShortestPathImageFilter.h" #include "time.h" #include "mitkMemoryUtilities.h" #include #include #include namespace itk { // Constructor (initialize standard values) template ShortestPathImageFilter ::ShortestPathImageFilter() : + m_Nodes(0), + m_Graph_NumberOfNodes(0), m_FullNeighborsMode(false), m_MakeOutputImage(true), m_StoreVectorOrder(false), m_CalcAllDistances(false), - m_ActivateTimeOut(false), multipleEndPoints(false), - m_Initialized(false), - m_Nodes(0), - m_Graph_NumberOfNodes(0) + m_ActivateTimeOut(false), + m_Initialized(false) { m_endPoints.clear(); m_endPointsClosed.clear(); if (m_MakeOutputImage) { this->SetNumberOfRequiredOutputs(1); this->SetNthOutput( 0, OutputImageType::New() ); } } template ShortestPathImageFilter ::~ShortestPathImageFilter() { delete [] m_Nodes; } template inline typename ShortestPathImageFilter::IndexType ShortestPathImageFilter ::NodeToCoord (NodeNumType node) { const InputImageSizeType &size = this->GetInput()->GetRequestedRegion().GetSize(); int dim = InputImageType::ImageDimension; IndexType coord; if (dim == 2) { coord[1] = node / size[0]; coord[0] = node % size[0]; - if ((coord[0] >= size[0]) || (coord[1] >= size[1])) + if (((unsigned long)coord[0] >= size[0]) || ((unsigned long)coord[1] >= size[1])) { coord[0] = 0; coord[1] = 0; } } if (dim == 3) { coord[2] = node / (size[0]*size[1]); coord[1] = (node % (size[0]*size[1])) / size[0]; coord[0] = (node % (size[0]*size[1])) % size[0]; - if ((coord[0] >= size[0]) || (coord[1] >= size[1]) || (coord[2] >= size[2])) + if (((unsigned long)coord[0] >= size[0]) || ((unsigned long)coord[1] >= size[1]) || ((unsigned long)coord[2] >= size[2])) { coord[0] = 0; coord[1] = 0; coord[2] = 0; } } return coord; } template inline typename itk::NodeNumType ShortestPathImageFilter:: CoordToNode (IndexType coord) { const InputImageSizeType &size = this->GetInput()->GetRequestedRegion().GetSize(); int dim = InputImageType::ImageDimension; NodeNumType node = 0; if (dim == 2) { node = (coord[1]*size[0]) + coord[0]; } if (dim == 3) { node = (coord[2]*size[0]*size[1]) + (coord[1]*size[0]) + coord[0]; } if ((m_Graph_NumberOfNodes > 0) && (node >= m_Graph_NumberOfNodes)) { /*MITK_INFO << "WARNING! Coordinates outside image!"; MITK_INFO << "Coords = " << coord ; MITK_INFO << "ImageDim = " << dim ; MITK_INFO << "RequestedRegionSize = " << size ;*/ node = 0; } return node; } template inline bool ShortestPathImageFilter:: CoordIsInBounds (IndexType coord) { const InputImageSizeType &size = this->GetInput()->GetRequestedRegion().GetSize(); int dim = InputImageType::ImageDimension; if (dim == 2) { if ((coord[0] >= 0) - && (coord[0] < size[0]) + && ((unsigned long)coord[0] < size[0]) && (coord[1] >= 0 ) - && (coord[1] < size[1] )) + && ((unsigned long)coord[1] < size[1] )) { return true; } } if (dim == 3) { if ((coord[0] >= 0) - && (coord[0] < size[0]) + && ((unsigned long)coord[0] < size[0]) && (coord[1] >= 0 ) - && (coord[1] < size[1] ) + && ((unsigned long)coord[1] < size[1] ) && (coord[2] >= 0 ) - && (coord[2] < size[2] )) + && ((unsigned long)coord[2] < size[2] )) { return true; } } return false; } template inline std::vector< ShortestPathNode* > ShortestPathImageFilter:: GetNeighbors (unsigned int nodeNum, bool FullNeighbors) { // returns a vector of nodepointers.. these nodes are the neighbors int dim = InputImageType::ImageDimension; IndexType Coord = NodeToCoord(nodeNum); IndexType NeighborCoord; std::vector nodeList; int neighborDistance = 1; //if i increase that, i might not hit the endnote // maybe use itkNeighborhoodIterator here, might be faster if ( dim == 2) { // N4 NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); if (FullNeighbors) { // N8 NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); } } if ( dim == 3) { // N6 NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]; NeighborCoord[2] = Coord[2]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]; NeighborCoord[2] = Coord[2]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); if (FullNeighbors) { // N26 // Middle Slice NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); // BackSlice (Diagonal) NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); //BackSlice (Non-Diag) NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); // FrontSlice (Diagonal) NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); //FrontSlice(Non-Diag) NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); } } return nodeList; } template void ShortestPathImageFilter:: SetStartIndex (const typename TInputImageType::IndexType &StartIndex) { for (unsigned int i=0;i v; v[0] = m_EndIndex[0]-a[0]; v[1] = m_EndIndex[1]-a[1]; v[2] = m_EndIndex[2]-a[2]; return m_CostFunction->GetMinCost() * v.GetNorm(); } template void ShortestPathImageFilter:: InitGraph() { if(!m_Initialized) { // Clean up previous stuff CleanUp(); // Calc Number of nodes m_ImageDimensions = TInputImageType::ImageDimension; const InputImageSizeType &size = this->GetInput()->GetRequestedRegion().GetSize(); m_Graph_NumberOfNodes = 1; for (NodeNumType i=0; iInitialize(); } template void ShortestPathImageFilter:: StartShortestPathSearch() { // Setup Timer clock_t startAll = clock(); clock_t stopAll = clock(); // init variables double durationAll = 0; bool timeout = false; - bool makeNewHeapNecessary = false; NodeNumType mainNodeListIndex = 0; DistanceType curNodeDistance = 0; - DistanceType curNodeDistAndEst = 0; NodeNumType numberOfNodesChecked = 0; // Create Multimap (tree structure for fast searching) std::multimap myMap; std::pair< std::multimap::iterator, std::multimap::iterator> ret; std::multimap::iterator it; // At first, only startNote is discovered. myMap.insert( std::pair (m_Nodes[m_Graph_StartNode].distAndEst, &m_Nodes[m_Graph_StartNode]) ); // While there are discovered Nodes, pick the one with lowest distance, // update its neighbors and eventually delete it from the discovered Nodes list. while(!myMap.empty()) { numberOfNodesChecked++; /*if ( (numberOfNodesChecked % (m_Graph_NumberOfNodes/100)) == 0) { MITK_INFO << "Checked " << ( numberOfNodesChecked / (m_Graph_NumberOfNodes/100) ) << "% List: " << myMap.size() << "\n"; }*/ // Get element with lowest score mainNodeListIndex = myMap.begin()->second->mainListIndex; - curNodeDistAndEst = myMap.begin()->second->distAndEst; curNodeDistance = myMap.begin()->second->distance; myMap.begin()->second->closed = true; // close it // Debug: //MITK_INFO << "INFO: size " << myMap.size(); /* for (it = myMap.begin(); it != myMap.end(); ++it) { MITK_INFO << "(1) " << it->first << "|" << it->second->distAndEst << "|"<second->mainListIndex; } */ // Kicks out element with lowest score myMap.erase( myMap.begin() ); // if wanted, store vector order if (m_StoreVectorOrder) { m_VectorOrder.push_back(mainNodeListIndex); } // Check neighbors std::vector neighborNodes = GetNeighbors(mainNodeListIndex, m_Graph_fullNeighbors); for (NodeNumType i=0; iclosed) continue; // this nodes is already closed, go to next neighbor IndexType coordCurNode = NodeToCoord(mainNodeListIndex); IndexType coordNeighborNode = NodeToCoord(neighborNodes[i]->mainListIndex); // calculate the new Distance to the current neighbor double newDistance = curNodeDistance + (m_CostFunction->GetCost(coordCurNode, coordNeighborNode)); // if it is shorter than any yet known path to this neighbor, than the current path is better. Save that! if ((newDistance < neighborNodes[i]->distance) || (neighborNodes[i]->distance == -1) ) { // if that neighbornode is not in discoverednodeList yet, Push it there and update if (neighborNodes[i]->distance == -1) { neighborNodes[i]->distance = newDistance; neighborNodes[i]->distAndEst = newDistance + getEstimatedCostsToTarget(coordNeighborNode); neighborNodes[i]->prevNode = mainNodeListIndex; myMap.insert( std::pair (m_Nodes[neighborNodes[i]->mainListIndex].distAndEst, &m_Nodes[neighborNodes[i]->mainListIndex]) ); /* MITK_INFO << "Inserted: " << m_Nodes[neighborNodes[i]->mainListIndex].distAndEst << "|" << m_Nodes[neighborNodes[i]->mainListIndex].mainListIndex; MITK_INFO << "INFO: size " << myMap.size(); for (it = myMap.begin(); it != myMap.end(); ++it) { MITK_INFO << "(1) " << it->first << "|" << it->second->distAndEst << "|"<second->mainListIndex; } */ } // or if is already in discoverednodelist, update else { /* it = myMap.find(neighborNodes[i]->distAndEst); if (it == myMap.end() ) { MITK_INFO << "Nothing!"; // look further for (it = myMap.begin(); it != myMap.end(); ++it) { if ((*it).second->mainListIndex == lookForId) { MITK_INFO << "But it is there!!!"; MITK_INFO << "Searched for: " << lookFor << " but had: " << (*it).second->distAndEst; } } } */ // 1st : find and delete old element bool found = false; - double lookFor = neighborNodes[i]->distAndEst; - unsigned int lookForId = neighborNodes[i]->mainListIndex; ret = myMap.equal_range(neighborNodes[i]->distAndEst); if ((ret.first == ret.second)) { /*+++++++++++++ no exact match +++++++++++++*/ //MITK_INFO << "No exact match!"; // if this happens, you are screwed /* MITK_INFO << "Was looking for: " << lookFor << " ID: " << lookForId; if (ret.first != myMap.end() ) { it = ret.first; MITK_INFO << "Found: " << it->first << " ID: " << it->second->mainListIndex; ++it; MITK_INFO << "Found: " << it->first << " ID: " << it->second->mainListIndex; --it; --it; MITK_INFO << "Found: " << it->first << " ID: " << it->second->mainListIndex; } // look if that ID is found in the map for (it = myMap.begin(); it != myMap.end(); ++it) { if ((*it).second->mainListIndex == lookForId) { MITK_INFO << "But it is there!!!"; MITK_INFO << "Searched dist: " << lookFor << " found dist: " << (*it).second->distAndEst; } } */ } else { for (it=ret.first; it!=ret.second; ++it) { if (it->second->mainListIndex == neighborNodes[i]->mainListIndex) { found = true; myMap.erase(it); /* MITK_INFO << "INFO: size " << myMap.size(); MITK_INFO << "Erase: " << it->first << "|" << it->second->mainListIndex; MITK_INFO << "INFO: size " << myMap.size(); for (it = myMap.begin(); it != myMap.end(); ++it) { MITK_INFO << "(1) " << it->first << "|" << it->second->distAndEst << "|"<second->mainListIndex; } */ break; } } } if (!found) { //MITK_INFO << "Could not find it! :("; continue; } // 2nd: update and insert new element neighborNodes[i]->distance = newDistance; neighborNodes[i]->distAndEst = newDistance + getEstimatedCostsToTarget(coordNeighborNode); neighborNodes[i]->prevNode = mainNodeListIndex; //myMap.insert( std::pair (neighborNodes[i]->distAndEst, neighborNodes[i])); myMap.insert( std::pair (m_Nodes[neighborNodes[i]->mainListIndex].distAndEst, &m_Nodes[neighborNodes[i]->mainListIndex]) ); //MITK_INFO << "Re-Inserted: " << m_Nodes[neighborNodes[i]->mainListIndex].distAndEst << "|" << m_Nodes[neighborNodes[i]->mainListIndex].mainListIndex; //MITK_INFO << "INFO: size " << myMap.size(); /*for (it = myMap.begin(); it != myMap.end(); ++it) { MITK_INFO << "(1) " << it->first << "|" << it->second->distAndEst << "|"<second->mainListIndex; }*/ } } } // finished with checking all neighbors. // Check Timeout, if activated if (m_ActivateTimeOut) { stopAll = clock(); durationAll = (double)(stopAll - startAll) / CLOCKS_PER_SEC; if (durationAll >= 30) { //MITK_INFO << "TIMEOUT!! Search took over 30 seconds"; timeout = true ; } } // Check end criteria: // For multiple points if ( multipleEndPoints ) { // super slow, make it faster - for (int i=0 ;i void ShortestPathImageFilter:: MakeOutputs() { //MITK_INFO << "Make Output"; if (m_MakeOutputImage) { OutputImagePointer output0 = this->GetOutput(0); output0->SetRegions( this->GetInput()->GetLargestPossibleRegion() ); output0->Allocate(); OutputImageIteratorType shortestPathImageIt (output0, output0->GetRequestedRegion()); // Create ShortestPathImage (Output 0) for (shortestPathImageIt.GoToBegin(); !shortestPathImageIt.IsAtEnd(); ++shortestPathImageIt) { // First intialize with background color shortestPathImageIt.Set( BACKGROUND ) ; } if (!multipleEndPoints) // Only one path was calculated { - for (int i=0; i< m_VectorPath.size(); i++) + for (unsigned int i=0; i< m_VectorPath.size(); i++) { shortestPathImageIt.SetIndex( m_VectorPath[i] ); shortestPathImageIt.Set( FOREGROUND ) ; } } else // multiple pathes has been calculated, draw all { - for (int i =0; i typename ShortestPathImageFilter::OutputImagePointer ShortestPathImageFilter:: GetVectorOrderImage() { // Create Vector Order Image // Return it OutputImagePointer image = OutputImageType::New(); image->SetRegions( this->GetInput()->GetLargestPossibleRegion() ); image->Allocate(); OutputImageIteratorType vectorOrderImageIt (image, image->GetRequestedRegion()); //MITK_INFO << "GetVectorOrderImage"; for (vectorOrderImageIt.GoToBegin(); !vectorOrderImageIt.IsAtEnd(); ++vectorOrderImageIt) { // First intialize with background color vectorOrderImageIt.Value() = BACKGROUND ; } for (int i=0; i< m_VectorOrder.size(); i++) { vectorOrderImageIt.SetIndex(NodeToCoord(m_VectorOrder[i]) ); vectorOrderImageIt.Set( BACKGROUND+i) ; } return image; } template typename ShortestPathImageFilter::OutputImagePointer ShortestPathImageFilter:: GetDistanceImage() { // Create Distance Image // Return it OutputImagePointer image = OutputImageType::New(); image->SetRegions( this->GetInput()->GetLargestPossibleRegion() ); image->Allocate();; OutputImageIteratorType distanceImageIt (image, image->GetRequestedRegion()); // Create Distance Image (Output 1) NodeNumType myNodeNum; for (distanceImageIt.GoToBegin(); !distanceImageIt.IsAtEnd(); ++distanceImageIt) { IndexType index = distanceImageIt.GetIndex(); myNodeNum = CoordToNode(index); double newVal = m_Nodes[myNodeNum].distance; distanceImageIt.Set(newVal); } } template std::vector< typename ShortestPathImageFilter::IndexType > ShortestPathImageFilter:: GetVectorPath() { return m_VectorPath; } template std::vector< std::vector< typename ShortestPathImageFilter::IndexType > > ShortestPathImageFilter:: GetMultipleVectorPaths() { return m_MultipleVectorPaths; } template void ShortestPathImageFilter:: MakeShortestPathVector() { //MITK_INFO << "Make ShortestPath Vec"; // single end point if ( !multipleEndPoints ) { // fill m_VectorPath with the Shortest Path m_VectorPath.clear(); // Go backwards from endnote to startnode NodeNumType prevNode = m_Graph_EndNode; - while (prevNode != -1) + while(prevNode != m_Graph_StartNode) { m_VectorPath.push_back( NodeToCoord(prevNode) ); - - if (prevNode == m_Graph_StartNode) - break; - prevNode = m_Nodes[prevNode].prevNode; - } - + } m_VectorPath.push_back( NodeToCoord(prevNode) ); // reverse it std::reverse(m_VectorPath.begin(), m_VectorPath.end() ); } // Multiple end end points and pathes else { - for (int i=0; i void ShortestPathImageFilter:: CleanUp() { m_VectorOrder.clear(); m_VectorPath.clear(); //TODO: if multiple Path, clear all multiple Paths if (m_Nodes) delete [] m_Nodes; } template void ShortestPathImageFilter:: GenerateData() { // Build Graph InitGraph(); // Calc Shortest Parth StartShortestPathSearch(); // Fill Shortest Path MakeShortestPathVector(); // Make Outputs MakeOutputs(); } template void ShortestPathImageFilter:: PrintSelf( std::ostream& os, Indent indent ) const { Superclass::PrintSelf(os,indent); } } /* end namespace itk */ #endif // __itkShortestPathImageFilter_txx