diff --git a/Modules/DiffusionImaging/Algorithms/Connectomics/mitkConnectomicsNetworkCreator.cpp b/Modules/DiffusionImaging/Algorithms/Connectomics/mitkConnectomicsNetworkCreator.cpp index 5412609b0b..8f7541f354 100644 --- a/Modules/DiffusionImaging/Algorithms/Connectomics/mitkConnectomicsNetworkCreator.cpp +++ b/Modules/DiffusionImaging/Algorithms/Connectomics/mitkConnectomicsNetworkCreator.cpp @@ -1,760 +1,762 @@ /*=================================================================== 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" // VTK #include #include #include mitk::ConnectomicsNetworkCreator::ConnectomicsNetworkCreator() : m_FiberBundle() , m_Segmentation() , m_ConNetwork( mitk::ConnectomicsNetwork::New() ) , idCounter(0) , m_LabelToVertexMap() , m_LabelToNodePropertyMap() , allowLoops( 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 ) { } 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; } 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->clear(); m_LabelToVertexMap.clear(); m_LabelToNodePropertyMap.clear(); 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 ); } //MappingStrategy strategy = EndElementPosition; //MappingStrategy strategy = JustEndPointVerticesNoLabel; MappingStrategy strategy = EndElementPositionAvoidingWhiteMatter; if ( singleTract && ( singleTract->Size() > 0 ) ) { AddConnectionToNetwork( ReturnAssociatedVertexPairForLabelPair( ReturnLabelForFiberTract( singleTract, strategy ) ) ); } } + // Prune unconnected nodes + m_ConNetwork->PruneUnconnectedSingleNodes(); // provide network with geometry m_ConNetwork->SetGeometry( m_Segmentation->GetGeometry() ); m_ConNetwork->UpdateBounds(); m_ConNetwork->SetIsModified( true ); MBI_INFO << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_INFO_NETWORK_CREATED; } void mitk::ConnectomicsNetworkCreator::AddConnectionToNetwork(ConnectionType newConnection) { VertexType vertexA = newConnection.first; VertexType vertexB = newConnection.second; // if vertices A and B exist if( vertexA && vertexB) { // 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 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 PrecomputeAndDistance: { return PrecomputeVertexLocationsBySegmentation( singleTract ); } case JustEndPointVerticesNoLabel: { return JustEndPointVerticesNoLabelTest( singleTract ); } case EndElementPositionAvoidingWhiteMatter: { return EndElementPositionLabelAvoidingWhiteMatter( singleTract ); } } // To remove warnings, this code should never be reached MBI_ERROR << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_INVALID_MAPPING; ImageLabelPairType nullPair( NULL, NULL ); 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++ ) { 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_Segmentation->GetPixelValueByIndex( firstElementSegIndex ); int lastLabel = m_Segmentation->GetPixelValueByIndex( lastElementSegIndex ); labelpair.first = firstLabel; labelpair.second = lastLabel; // Add property to property map if( ! ( m_LabelToNodePropertyMap.count( firstLabel ) > 0 ) ) { NetworkNode firstNode; firstNode.coordinates.resize( 3 ); for( unsigned int index = 0; index < firstNode.coordinates.size() ; index++ ) { firstNode.coordinates[ index ] = firstElementSegIndex[ index ] ; } firstNode.label = LabelToString( firstLabel ); m_LabelToNodePropertyMap.insert( std::pair< ImageLabelType, NetworkNode >( firstLabel, firstNode ) ); } if( ! ( m_LabelToNodePropertyMap.count( lastLabel ) > 0 ) ) { NetworkNode lastNode; lastNode.coordinates.resize( 3 ); for( unsigned int index = 0; index < lastNode.coordinates.size() ; index++ ) { lastNode.coordinates[ index ] = lastElementSegIndex[ index ] ; } lastNode.label = LabelToString( lastLabel ); m_LabelToNodePropertyMap.insert( std::pair< ImageLabelType, NetworkNode >( lastLabel, lastNode ) ); } } return labelpair; } 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++ ) { 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_Segmentation->GetPixelValueByIndex( firstElementSegIndex ); int lastLabel = m_Segmentation->GetPixelValueByIndex( 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 if( ! ( m_LabelToNodePropertyMap.count( firstLabel ) > 0 ) ) { NetworkNode firstNode; firstNode.coordinates.resize( 3 ); for( unsigned int index = 0; index < firstNode.coordinates.size() ; index++ ) { firstNode.coordinates[ index ] = firstElementSegIndex[ index ] ; } firstNode.label = LabelToString( firstLabel ); m_LabelToNodePropertyMap.insert( std::pair< ImageLabelType, NetworkNode >( firstLabel, firstNode ) ); } if( ! ( m_LabelToNodePropertyMap.count( lastLabel ) > 0 ) ) { NetworkNode lastNode; lastNode.coordinates.resize( 3 ); for( unsigned int index = 0; index < lastNode.coordinates.size() ; index++ ) { lastNode.coordinates[ index ] = lastElementSegIndex[ index ] ; } lastNode.label = LabelToString( lastLabel ); m_LabelToNodePropertyMap.insert( std::pair< ImageLabelType, NetworkNode >( lastLabel, lastNode ) ); } } 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++ ) { 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 if( ! ( m_LabelToNodePropertyMap.count( firstLabel ) > 0 ) ) { NetworkNode firstNode; firstNode.coordinates.resize( 3 ); for( unsigned int index = 0; index < firstNode.coordinates.size() ; index++ ) { firstNode.coordinates[ index ] = firstElementSegIndex[ index ] ; } firstNode.label = LabelToString( firstLabel ); m_LabelToNodePropertyMap.insert( std::pair< ImageLabelType, NetworkNode >( firstLabel, firstNode ) ); } if( ! ( m_LabelToNodePropertyMap.count( lastLabel ) > 0 ) ) { NetworkNode lastNode; lastNode.coordinates.resize( 3 ); for( unsigned int index = 0; index < lastNode.coordinates.size() ; index++ ) { lastNode.coordinates[ index ] = lastElementSegIndex[ index ] ; } lastNode.label = LabelToString( lastLabel ); m_LabelToNodePropertyMap.insert( std::pair< ImageLabelType, NetworkNode >( lastLabel, lastNode ) ); } } 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++ ) { if( indexVectorOfPointsToUse[ index ] > singleTract->Size() ) { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_ESTIMATING_BEYOND_END; return; } if( indexVectorOfPointsToUse[ index ] < 0 ) { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_ESTIMATING_BEYOND_START; 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++ ) { 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++ ) { 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++ ) { sum = sum + differenceVector[ index ] * differenceVector[ index ]; } length = std::sqrt( sum ); for( 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 ); 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 ] ); } tempLabel = m_Segmentation->GetPixelValueByIndex( tempIndex ); 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++ ) { 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++ ) { 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++ ) { 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_Segmentation->GetPixelValueByIndex( tempIndex ); if( !IsBackgroundLabel( tempLabel ) ) { label = tempLabel; mitkIndex = tempIndex; return; } // hit next point without finding brain matter currentRetractionIndex = currentRetractionIndex + retractionStepIndexSize; if( ( currentRetractionIndex < 1 ) || ( currentRetractionIndex > ( singleTract->Size() - 2 ) ) ) { keepRetracting = false; } } } } diff --git a/Modules/DiffusionImaging/IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetwork.cpp b/Modules/DiffusionImaging/IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetwork.cpp index 55d44dad68..c35a2bef23 100644 --- a/Modules/DiffusionImaging/IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetwork.cpp +++ b/Modules/DiffusionImaging/IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetwork.cpp @@ -1,503 +1,556 @@ /*=================================================================== 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 /* 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( 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() { 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++ ) { 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 ) { if( maximumDegree < vectorOfDegree[ index ] ) { maximumDegree = vectorOfDegree[ index ]; } } return maximumDegree; } std::vector< double > mitk::ConnectomicsNetwork::GetLocalClusteringCoefficients( ) { 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 for (vertexPair = vertices(m_Network); vertexPair.first != vertexPair.second; ++vertexPair.first) { vectorOfClusteringCoefficients[ m_Network[ *vertexPair.first ].id ] = 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 ) { vectorOfClusteringCoefficientsByDegree[ degree ] = 0; int n_k( 0 ); for( int index( 0 ); index < vectorOfDegree.size(); ++index ) { if( degree == 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 ) { 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 ) { globalClusteringCoefficient += degreeDistribution[ degree ] / ( (double) normalizationParameter) * vectorOfClusteringCoefficientsByDegree[ degree ]; } return globalClusteringCoefficient; } mitk::ConnectomicsNetwork::NetworkType* mitk::ConnectomicsNetwork::GetBoostGraph() { return &m_Network; } 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++ ) { 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->GetTimeSlicedGeometry()->UpdateInformation(); } + +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 ); +} \ No newline at end of file diff --git a/Modules/DiffusionImaging/IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetwork.h b/Modules/DiffusionImaging/IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetwork.h index ef9e157f8d..001874f95c 100644 --- a/Modules/DiffusionImaging/IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetwork.h +++ b/Modules/DiffusionImaging/IODataStructures/ConnectomicsNetwork/mitkConnectomicsNetwork.h @@ -1,178 +1,188 @@ /*=================================================================== 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 "MitkDiffusionImagingExports.h" #include "mitkBaseData.h" #include namespace mitk { /** * \brief Base Class for Connectomics Networks */ class MitkDiffusionImaging_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( itk::DataObject *data ); // 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(); /** 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( ); /** Get a vector in the format vector[ degree ] = average clustering coefficient */ std::vector< double > GetClusteringCoefficientsByDegree( ); /** Get the global clustering coefficient */ double GetGlobalClusteringCoefficient( ); /** Access boost graph directly */ NetworkType* GetBoostGraph(); /** 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(); + protected: ConnectomicsNetwork(); virtual ~ConnectomicsNetwork(); + /** 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(); + NetworkType m_Network; /// Flag which indicates whether the network has been modified since the last check /// /// mainly for rendering purposes bool m_IsModified; private: }; } // namespace mitk #endif /* _MITK_ConnectomicsNetwork_H */ diff --git a/Modules/DiffusionImaging/Rendering/mitkConnectomicsNetworkMapper3D.cpp b/Modules/DiffusionImaging/Rendering/mitkConnectomicsNetworkMapper3D.cpp index c54e3431ca..0c91da3715 100644 --- a/Modules/DiffusionImaging/Rendering/mitkConnectomicsNetworkMapper3D.cpp +++ b/Modules/DiffusionImaging/Rendering/mitkConnectomicsNetworkMapper3D.cpp @@ -1,180 +1,181 @@ /*=================================================================== 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" mitk::ConnectomicsNetworkMapper3D::ConnectomicsNetworkMapper3D() { //TODO: implement m_NetworkAssembly = vtkPropAssembly::New(); } mitk::ConnectomicsNetworkMapper3D:: ~ConnectomicsNetworkMapper3D() { //TODO: implement m_NetworkAssembly->Delete(); } void mitk::ConnectomicsNetworkMapper3D::GenerateDataForRenderer(mitk::BaseRenderer* renderer) { //TODO: implement if( this->GetInput() == NULL ) { return; } if( this->GetInput()->GetIsModified( ) ) { GenerateData(); } } void mitk::ConnectomicsNetworkMapper3D::GenerateData() { - //TODO: implement + m_NetworkAssembly->Delete(); + m_NetworkAssembly = vtkPropAssembly::New(); - // Here is the part where a graph is given and converted to points and connections between points... + // 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(); mitk::Point3D tempWorldPoint, tempCNFGeometryPoint; //////////////////////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] ); } this->GetData()->GetGeometry()->IndexToWorld( tempCNFGeometryPoint, tempWorldPoint ); sphereSource->SetCenter( tempWorldPoint[0] , tempWorldPoint[1], tempWorldPoint[2] ); sphereSource->SetRadius(1.0); vtkSmartPointer mapper = vtkSmartPointer::New(); mapper->SetInput(sphereSource->GetOutput()); vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); m_NetworkAssembly->AddPart(actor); } //////////////////////Create Tubes///////////////////////// 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]; } this->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]; } this->GetData()->GetGeometry()->IndexToWorld( tempCNFGeometryPoint, tempWorldPoint ); lineSource->SetPoint2(tempWorldPoint[0], tempWorldPoint[1], tempWorldPoint[2] ); vtkSmartPointer tubes = vtkSmartPointer::New(); tubes->SetInput( lineSource->GetOutput() ); tubes->SetNumberOfSides( 12 ); double radiusFactor = 1.0 + ((double) vectorOfEdges[i].second.weight) / 10.0 ; tubes->SetRadius( std::log10( radiusFactor ) ); vtkSmartPointer mapper2 = vtkSmartPointer::New(); mapper2->SetInput( tubes->GetOutput() ); vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper2); double maxWeight = (double) this->GetInput()->GetMaximumWeight(); double colourFactor = vectorOfEdges[i].second.weight / maxWeight; actor->GetProperty()->SetColor( colourFactor, colourFactor, colourFactor); m_NetworkAssembly->AddPart(actor); } (static_cast ( GetData() ) )->SetIsModified( false ); //this->UpdateVtkObjects(); } const mitk::ConnectomicsNetwork* mitk::ConnectomicsNetworkMapper3D::GetInput() { return static_cast ( GetData() ); } void mitk::ConnectomicsNetworkMapper3D::SetDefaultProperties(DataNode* node, BaseRenderer* renderer , bool overwrite) { //TODO: implement // hand it to the superclass for base default properties 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; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/Connectomics/QmitkBrainNetworkAnalysisView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/Connectomics/QmitkBrainNetworkAnalysisView.cpp index 36c7ca2d3a..d7deab545d 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/Connectomics/QmitkBrainNetworkAnalysisView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/Connectomics/QmitkBrainNetworkAnalysisView.cpp @@ -1,677 +1,710 @@ /*=================================================================== 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. ===================================================================*/ // ####### Blueberry includes ####### #include #include // ####### Qmitk includes ####### #include "QmitkBrainNetworkAnalysisView.h" #include "QmitkStdMultiWidget.h" // ####### Qt includes ####### #include // ####### ITK includes ####### #include // ####### MITK includes ####### #include #include "mitkConnectomicsSyntheticNetworkGenerator.h" #include "mitkConnectomicsSimulatedAnnealingManager.h" #include "mitkConnectomicsSimulatedAnnealingPermutationModularity.h" #include "mitkConnectomicsSimulatedAnnealingCostFunctionModularity.h" // Includes for image casting between ITK and MITK #include "mitkImageCast.h" #include "mitkITKImageImport.h" #include "mitkImageAccessByItk.h" const std::string QmitkBrainNetworkAnalysisView::VIEW_ID = "org.mitk.views.brainnetworkanalysis"; QmitkBrainNetworkAnalysisView::QmitkBrainNetworkAnalysisView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) , m_ConnectomicsNetworkCreator( mitk::ConnectomicsNetworkCreator::New() ) , m_demomode( false ) , m_currentIndex( 0 ) { } QmitkBrainNetworkAnalysisView::~QmitkBrainNetworkAnalysisView() { } void QmitkBrainNetworkAnalysisView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkBrainNetworkAnalysisViewControls; m_Controls->setupUi( parent ); QObject::connect( m_Controls->convertToRGBAImagePushButton, SIGNAL(clicked()), this, SLOT(OnConvertToRGBAImagePushButtonClicked()) ); QObject::connect( m_Controls->networkifyPushButton, SIGNAL(clicked()), this, SLOT(OnNetworkifyPushButtonClicked()) ); QObject::connect( m_Controls->syntheticNetworkCreationPushButton, SIGNAL(clicked()), this, SLOT(OnSyntheticNetworkCreationPushButtonClicked()) ); - QObject::connect( (QObject*)( m_Controls->syntheticNetworkComboBox ), SIGNAL(currentIndexChanged (int)), this, SLOT(OnSyntheticNetworkComboBoxCurrentIndexChanged(int)) ); - QObject::connect( (QObject*)( m_Controls->modularizePushButton ), SIGNAL(clicked()), this, SLOT(OnModularizePushButtonClicked()) ); + QObject::connect( (QObject*)( m_Controls->syntheticNetworkComboBox ), SIGNAL(currentIndexChanged (int)), this, SLOT(OnSyntheticNetworkComboBoxCurrentIndexChanged(int)) ); + QObject::connect( (QObject*)( m_Controls->modularizePushButton ), SIGNAL(clicked()), this, SLOT(OnModularizePushButtonClicked()) ); + QObject::connect( (QObject*)( m_Controls->prunePushButton ), SIGNAL(clicked()), this, SLOT(OnPrunePushButtonClicked()) ); } // GUI is different for developer and demo mode m_demomode = false; if( m_demomode ) { this->m_Controls->convertToRGBAImagePushButton->hide(); this->m_Controls->networkifyPushButton->show(); this->m_Controls->networkifyPushButton->setText( "Create Network" ); this->m_Controls->modularizePushButton->hide(); + this->m_Controls->prunePushButton->hide(); this->m_Controls->syntheticNetworkOptionsGroupBox->show(); //--------------------------- fill comboBox--------------------------- this->m_Controls->syntheticNetworkComboBox->insertItem(0,"Regular lattice"); this->m_Controls->syntheticNetworkComboBox->insertItem(1,"Heterogenic sphere"); this->m_Controls->syntheticNetworkComboBox->insertItem(2,"Random network"); } else { this->m_Controls->convertToRGBAImagePushButton->show(); this->m_Controls->networkifyPushButton->show(); this->m_Controls->networkifyPushButton->setText( "Networkify" ); this->m_Controls->modularizePushButton->show(); + this->m_Controls->prunePushButton->show(); this->m_Controls->syntheticNetworkOptionsGroupBox->show(); //--------------------------- fill comboBox--------------------------- this->m_Controls->syntheticNetworkComboBox->insertItem(0,"Regular lattice"); this->m_Controls->syntheticNetworkComboBox->insertItem(1,"Heterogenic sphere"); this->m_Controls->syntheticNetworkComboBox->insertItem(2,"Random network"); this->m_Controls->syntheticNetworkComboBox->insertItem(3,"Scale free network"); this->m_Controls->syntheticNetworkComboBox->insertItem(4,"Small world network"); } this->WipeDisplay(); } void QmitkBrainNetworkAnalysisView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkBrainNetworkAnalysisView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkBrainNetworkAnalysisView::WipeDisplay() { m_Controls->lblWarning->setVisible( true ); m_Controls->inputImageOneNameLabel->setText( mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_DASH ); m_Controls->inputImageOneNameLabel->setVisible( false ); m_Controls->inputImageOneLabel->setVisible( false ); m_Controls->inputImageTwoNameLabel->setText( mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_DASH ); m_Controls->inputImageTwoNameLabel->setVisible( false ); m_Controls->inputImageTwoLabel->setVisible( false ); m_Controls->numberOfVerticesLabel->setText( mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_DASH ); m_Controls->numberOfEdgesLabel->setText( mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_DASH ); m_Controls->numberOfSelfLoopsLabel->setText( mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_DASH ); m_Controls->averageDegreeLabel->setText( mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_DASH ); m_Controls->connectionDensityLabel->setText( mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_DASH ); m_Controls->efficiencyLabel->setText( mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_DASH ); m_Controls->globalClusteringLabel->setText( mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_DASH ); m_Controls->betweennessNetworkHistogramCanvas->SetHistogram( NULL ); m_Controls->degreeNetworkHistogramCanvas->SetHistogram( NULL ); m_Controls->shortestPathNetworkHistogramCanvas->SetHistogram( NULL ); m_Controls->betweennessNetworkHistogramCanvas->update(); m_Controls->degreeNetworkHistogramCanvas->update(); m_Controls->shortestPathNetworkHistogramCanvas->update(); m_Controls->betweennessNetworkHistogramCanvas->Clear(); m_Controls->degreeNetworkHistogramCanvas->Clear(); m_Controls->shortestPathNetworkHistogramCanvas->Clear(); m_Controls->betweennessNetworkHistogramCanvas->Replot(); m_Controls->degreeNetworkHistogramCanvas->Replot(); m_Controls->shortestPathNetworkHistogramCanvas->Replot(); } void QmitkBrainNetworkAnalysisView::OnSelectionChanged( std::vector nodes ) { this->WipeDisplay(); // Valid options are either // 1 image (parcellation) // // 1 image (parcellation) // 1 fiber bundle // // 1 network if( nodes.size() > 2 ) { return; } bool alreadyFiberBundleSelected( false ), alreadyImageSelected( false ), currentFormatUnknown( true ); // iterate all selected objects, adjust warning visibility for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; currentFormatUnknown = true; if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { currentFormatUnknown = false; if( alreadyImageSelected ) { this->WipeDisplay(); return; } alreadyImageSelected = true; m_Controls->lblWarning->setVisible( false ); m_Controls->inputImageOneNameLabel->setText(node->GetName().c_str()); m_Controls->inputImageOneNameLabel->setVisible( true ); m_Controls->inputImageOneLabel->setVisible( true ); } if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { currentFormatUnknown = false; // a fiber bundle has to be in conjunction with a parcellation if( nodes.size() != 2 || alreadyFiberBundleSelected ) { this->WipeDisplay(); return; } alreadyFiberBundleSelected = true; m_Controls->lblWarning->setVisible( false ); m_Controls->inputImageTwoNameLabel->setText(node->GetName().c_str()); m_Controls->inputImageTwoNameLabel->setVisible( true ); m_Controls->inputImageTwoLabel->setVisible( true ); } { // network section mitk::ConnectomicsNetwork* network = dynamic_cast( node->GetData() ); if( node.IsNotNull() && network ) { currentFormatUnknown = false; if( nodes.size() != 1 ) { // only valid option is a single network this->WipeDisplay(); return; } m_Controls->lblWarning->setVisible( false ); m_Controls->inputImageOneNameLabel->setText(node->GetName().c_str()); m_Controls->inputImageOneNameLabel->setVisible( true ); m_Controls->inputImageOneLabel->setVisible( true ); int noVertices = network->GetNumberOfVertices(); int noEdges = network->GetNumberOfEdges(); int noSelfLoops = network->GetNumberOfSelfLoops(); double averageDegree = network->GetAverageDegree(); double connectionDensity = network->GetConnectionDensity(); double globalClustering = network->GetGlobalClusteringCoefficient(); m_Controls->numberOfVerticesLabel->setText( QString::number( noVertices ) ); m_Controls->numberOfEdgesLabel->setText( QString::number( noEdges ) ); m_Controls->numberOfSelfLoopsLabel->setText( QString::number( noSelfLoops ) ); m_Controls->averageDegreeLabel->setText( QString::number( averageDegree ) ); m_Controls->connectionDensityLabel->setText( QString::number( connectionDensity ) ); m_Controls->globalClusteringLabel->setText( QString::number( globalClustering ) ); mitk::ConnectomicsNetwork::Pointer connectomicsNetwork( network ); mitk::ConnectomicsHistogramsContainer *histogramContainer = histogramCache[ connectomicsNetwork ]; if(histogramContainer) { m_Controls->betweennessNetworkHistogramCanvas->SetHistogram( histogramContainer->GetBetweennessHistogram() ); m_Controls->degreeNetworkHistogramCanvas->SetHistogram( histogramContainer->GetDegreeHistogram() ); m_Controls->shortestPathNetworkHistogramCanvas->SetHistogram( histogramContainer->GetShortestPathHistogram() ); m_Controls->betweennessNetworkHistogramCanvas->DrawProfiles(); m_Controls->degreeNetworkHistogramCanvas->DrawProfiles(); m_Controls->shortestPathNetworkHistogramCanvas->DrawProfiles(); double efficiency = histogramContainer->GetShortestPathHistogram()->GetEfficiency(); m_Controls->efficiencyLabel->setText( QString::number( efficiency ) ); } } } // end network section if ( currentFormatUnknown ) { this->WipeDisplay(); return; } } // end for loop } void QmitkBrainNetworkAnalysisView::OnSyntheticNetworkComboBoxCurrentIndexChanged(int currentIndex) { m_currentIndex = currentIndex; switch (m_currentIndex) { case 0: this->m_Controls->parameterOneLabel->setText( "Nodes per side" ); this->m_Controls->parameterTwoLabel->setText( "Internode distance" ); this->m_Controls->parameterOneSpinBox->setEnabled( true ); this->m_Controls->parameterOneSpinBox->setValue( 5 ); this->m_Controls->parameterTwoDoubleSpinBox->setEnabled( true ); this->m_Controls->parameterTwoDoubleSpinBox->setMaximum( 999.999 ); this->m_Controls->parameterTwoDoubleSpinBox->setValue( 10.0 ); break; case 1: this->m_Controls->parameterOneLabel->setText( "Number of nodes" ); this->m_Controls->parameterTwoLabel->setText( "Radius" ); this->m_Controls->parameterOneSpinBox->setEnabled( true ); this->m_Controls->parameterOneSpinBox->setValue( 1000 ); this->m_Controls->parameterTwoDoubleSpinBox->setEnabled( true ); this->m_Controls->parameterTwoDoubleSpinBox->setMaximum( 999.999 ); this->m_Controls->parameterTwoDoubleSpinBox->setValue( 50.0 ); break; case 2: this->m_Controls->parameterOneLabel->setText( "Number of nodes" ); this->m_Controls->parameterTwoLabel->setText( "Edge percentage" ); this->m_Controls->parameterOneSpinBox->setEnabled( true ); this->m_Controls->parameterOneSpinBox->setValue( 100 ); this->m_Controls->parameterTwoDoubleSpinBox->setEnabled( true ); this->m_Controls->parameterTwoDoubleSpinBox->setMaximum( 1.0 ); this->m_Controls->parameterTwoDoubleSpinBox->setValue( 0.5 ); break; case 3: //GenerateSyntheticScaleFreeNetwork( network, 1000 ); break; case 4: //GenerateSyntheticSmallWorldNetwork( network, 1000 ); break; default: this->m_Controls->parameterOneLabel->setText( "Parameter 1" ); this->m_Controls->parameterTwoLabel->setText( "Paramater 2" ); this->m_Controls->parameterOneSpinBox->setEnabled( false ); this->m_Controls->parameterOneSpinBox->setValue( 0 ); this->m_Controls->parameterTwoDoubleSpinBox->setEnabled( false ); this->m_Controls->parameterTwoDoubleSpinBox->setValue( 0.0 ); } } void QmitkBrainNetworkAnalysisView::OnSyntheticNetworkCreationPushButtonClicked() { // warn if trying to create a very big network // big network is a network with > 5000 nodes (estimate) // this might fill up the memory to the point it freezes int numberOfNodes( 0 ); switch (m_currentIndex) { case 0: numberOfNodes = this->m_Controls->parameterOneSpinBox->value() * this->m_Controls->parameterOneSpinBox->value() * this->m_Controls->parameterOneSpinBox->value(); break; case 1: numberOfNodes = this->m_Controls->parameterOneSpinBox->value(); break; case 2: numberOfNodes = this->m_Controls->parameterOneSpinBox->value(); break; case 3: // not implemented yet break; case 4: // not implemented yet break; default: break; } if( numberOfNodes > 5000 ) { QMessageBox msgBox; msgBox.setText("Trying to generate very large network."); msgBox.setIcon( QMessageBox::Warning ); msgBox.setInformativeText("You are trying to generate a network with more than 5000 nodes, this is very resource intensive and might lead to program instability. Proceed with network generation?"); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); int ret = msgBox.exec(); switch (ret) { case QMessageBox::Yes: // continue break; case QMessageBox::No: // stop return; break; default: // should never be reached break; } } // proceed mitk::ConnectomicsSyntheticNetworkGenerator::Pointer generator = mitk::ConnectomicsSyntheticNetworkGenerator::New(); mitk::DataNode::Pointer networkNode = mitk::DataNode::New(); int parameterOne = this->m_Controls->parameterOneSpinBox->value(); double parameterTwo = this->m_Controls->parameterTwoDoubleSpinBox->value(); - ////add network to datastorage + //add network to datastorage networkNode->SetData( generator->CreateSyntheticNetwork( m_currentIndex, parameterOne, parameterTwo ) ); networkNode->SetName( mitk::ConnectomicsConstantsManager::CONNECTOMICS_PROPERTY_DEFAULT_CNF_NAME ); if( generator->WasGenerationSuccessfull() ) { this->GetDefaultDataStorage()->Add( networkNode ); } else { MITK_WARN << "Problem occured during synthetic network generation."; } return; } void QmitkBrainNetworkAnalysisView::OnConvertToRGBAImagePushButtonClicked() { std::vector nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataNode* node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information( NULL, mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_CONNECTOMICS_CREATION, mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_SELECTION_WARNING); return; } // here we have a valid mitk::DataNode // a node itself is not very useful, we need its data item (the image) mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast( data ); if (image) { std::stringstream message; std::string name; message << mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_PERFORMING_IMAGE_PROCESSING_FOR_IMAGE; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; } message << "."; MITK_INFO << message.str(); // Convert to RGBA AccessByItk( image, TurnIntoRGBA ); this->GetDefaultDataStorage()->GetNamedNode( mitk::ConnectomicsConstantsManager::CONNECTOMICS_PROPERTY_DEFAULT_RGBA_NAME )->GetData()->SetGeometry( node->GetData()->GetGeometry() ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } template < typename TPixel, unsigned int VImageDimension > void QmitkBrainNetworkAnalysisView::TurnIntoRGBA( itk::Image* inputImage) { typedef itk::RGBAPixel< unsigned char > RGBAPixelType; typedef itk::Image< TPixel, VImageDimension > TemplateImageType; typedef itk::Image< RGBAPixelType, VImageDimension > RGBAImageType; itk::ImageRegionIterator it_inputImage(inputImage, inputImage->GetLargestPossibleRegion()); TPixel minimumValue, maximumValue; it_inputImage.GoToBegin(); maximumValue = minimumValue = it_inputImage.Value(); for(it_inputImage.GoToBegin(); !it_inputImage.IsAtEnd(); ++it_inputImage) { if ( it_inputImage.Value() < minimumValue ) { minimumValue = it_inputImage.Value(); } else { if ( it_inputImage.Value() > maximumValue ) { maximumValue = it_inputImage.Value(); } } } int range = int ( maximumValue - minimumValue ); //needs to be castable to int int offset = int ( minimumValue ); if ( range < 0 ) //error { return; } std::vector< unsigned int > histogram; histogram.resize( range + 1, 0 ); for(it_inputImage.GoToBegin(); !it_inputImage.IsAtEnd(); ++it_inputImage) { histogram[ int ( it_inputImage.Value() ) - offset ] += 1; } int gapCounter = 0; //this variable will be used to count the empty labels //stores how much has to be subtracted from the image to remove gaps std::vector< TPixel > subtractionStorage; subtractionStorage.resize( range + 1, 0 ); for( int index = 0; index <= range; index++ ) { if( histogram[ index ] == 0 ) { gapCounter++; //if the label is empty, increase gapCounter } else { subtractionStorage[ index ] = TPixel ( gapCounter ); } } //remove gaps from label image for(it_inputImage.GoToBegin(); !it_inputImage.IsAtEnd(); ++it_inputImage) { it_inputImage.Value() = it_inputImage.Value() - subtractionStorage[ int ( it_inputImage.Value() ) ]; } // create colour vector std::vector< RGBAPixelType > lookupTable; { RGBAPixelType backgroundColour; for( int elementIndex = 0; elementIndex < 4; ++elementIndex ) { backgroundColour.SetElement( elementIndex, 0 ); } lookupTable.push_back( backgroundColour ); for(int colourNumber = 0; colourNumber < range ; ++colourNumber) { RGBAPixelType colour; for( int elementIndex = 0; elementIndex < 3; ++elementIndex ) { colour.SetElement( elementIndex, rand() % 256 ); } colour.SetAlpha( 255 ); lookupTable.push_back( colour ); } } // create RGBA image typename RGBAImageType::Pointer rgbaImage = RGBAImageType::New(); rgbaImage->SetRegions(inputImage->GetLargestPossibleRegion().GetSize()); rgbaImage->SetSpacing(inputImage->GetSpacing()); rgbaImage->SetOrigin(inputImage->GetOrigin()); rgbaImage->Allocate(); //fill with appropriate colours itk::ImageRegionIterator it_rgbaImage(rgbaImage, rgbaImage->GetLargestPossibleRegion()); for(it_inputImage.GoToBegin(), it_rgbaImage.GoToBegin(); !it_inputImage.IsAtEnd(); ++it_inputImage, ++it_rgbaImage) { it_rgbaImage.Value() = lookupTable[ int ( it_inputImage.Value() ) ]; } mitk::Image::Pointer mitkRGBAImage = mitk::ImportItkImage( rgbaImage ); mitk::DataNode::Pointer rgbaImageNode = mitk::DataNode::New(); rgbaImageNode->SetData(mitkRGBAImage); rgbaImageNode->SetProperty(mitk::ConnectomicsConstantsManager::CONNECTOMICS_PROPERTY_NAME, mitk::StringProperty::New(mitk::ConnectomicsConstantsManager::CONNECTOMICS_PROPERTY_DEFAULT_RGBA_NAME)); rgbaImageNode->SetBoolProperty( mitk::ConnectomicsConstantsManager::CONNECTOMICS_PROPERTY_VOLUMERENDERING, true); this->GetDefaultDataStorage()->Add( rgbaImageNode ); } void QmitkBrainNetworkAnalysisView::OnNetworkifyPushButtonClicked() { std::vector nodes = this->GetDataManagerSelection(); if ( nodes.empty() ) { QMessageBox::information( NULL, mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_CONNECTOMICS_CREATION, mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_SELECTION_WARNING); return; } if (! ( nodes.size() == 2 ) ) { QMessageBox::information( NULL, mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_CONNECTOMICS_CREATION, mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_SELECTION_WARNING); return; } mitk::DataNode* firstNode = nodes.front(); mitk::DataNode* secondNode = nodes.at(1); if (!firstNode) { // Nothing selected. Inform the user and return QMessageBox::information( NULL, mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_CONNECTOMICS_CREATION, mitk::ConnectomicsConstantsManager::CONNECTOMICS_GUI_SELECTION_WARNING); return; } // here we have a valid mitk::DataNode // a node itself is not very useful, we need its data item (the image) mitk::BaseData* firstData = firstNode->GetData(); mitk::BaseData* secondData = secondNode->GetData(); if (firstData && secondData) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast( firstData ); mitk::FiberBundleX* fiberBundle = dynamic_cast( secondData ); // check whether order was switched if (! (image && fiberBundle) ) { image = dynamic_cast( secondData ); fiberBundle = dynamic_cast( firstData ); } if (image && fiberBundle) { m_ConnectomicsNetworkCreator->SetSegmentation( image ); m_ConnectomicsNetworkCreator->SetFiberBundle( fiberBundle ); m_ConnectomicsNetworkCreator->CreateNetworkFromFibersAndSegmentation(); mitk::DataNode::Pointer networkNode = mitk::DataNode::New(); - ////add network to datastorage + //add network to datastorage networkNode->SetData( m_ConnectomicsNetworkCreator->GetNetwork() ); networkNode->SetName( mitk::ConnectomicsConstantsManager::CONNECTOMICS_PROPERTY_DEFAULT_CNF_NAME ); this->GetDefaultDataStorage()->Add( networkNode ); } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkBrainNetworkAnalysisView::OnModularizePushButtonClicked() { std::vector nodes = this->GetDataManagerSelection(); if ( nodes.empty() ) { QMessageBox::information( NULL, "Modularization calculation", "Please select exactly one network."); return; } for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { return; } { mitk::ConnectomicsNetwork* network = dynamic_cast( node->GetData() ); if( node.IsNotNull() && network ) { typedef mitk::ConnectomicsSimulatedAnnealingPermutationModularity::ToModuleMapType MappingType; int depthOfModuleRecursive( 2 ); double startTemperature( 2.0 ); double stepSize( 4.0 ); mitk::ConnectomicsNetwork::Pointer connectomicsNetwork( network ); 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( connectomicsNetwork ); permutation->SetDepth( depthOfModuleRecursive ); permutation->SetStepSize( stepSize ); manager->SetPermutation( permutation.GetPointer() ); manager->RunSimulatedAnnealing( startTemperature, stepSize ); MappingType mapping = permutation->GetMapping(); MappingType::iterator iter = mapping.begin(); MappingType::iterator end = mapping.end(); int loop( 0 ); while( iter != end ) { MBI_DEBUG << "Vertex " << iter->first << " belongs to module " << iter->second ; MBI_INFO << "Vertex " << iter->first << " belongs to module " << iter->second ; iter++; } MBI_DEBUG << "Overall number of modules is " << permutation->getNumberOfModules( &mapping ) ; MBI_DEBUG << "Cost is " << costFunction->Evaluate( network, &mapping ) ; MBI_INFO << "Overall number of modules is " << permutation->getNumberOfModules( &mapping ) ; MBI_INFO << "Cost is " << costFunction->Evaluate( network, &mapping ) ; return; } } } } + +void QmitkBrainNetworkAnalysisView::OnPrunePushButtonClicked() +{ + std::vector nodes = this->GetDataManagerSelection(); + if ( nodes.empty() ) + { + QMessageBox::information( NULL, "Network pruning", "Please select one or more network."); + return; + } + + for( std::vector::iterator it = nodes.begin(); + it != nodes.end(); + ++it ) + { + mitk::DataNode::Pointer node = *it; + + if( node.IsNotNull() && dynamic_cast(node->GetData()) ) + { + return; + } + + { + mitk::ConnectomicsNetwork* network = dynamic_cast( node->GetData() ); + if( node.IsNotNull() && network ) + { + network->PruneUnconnectedSingleNodes(); + } + } + } +} diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/Connectomics/QmitkBrainNetworkAnalysisView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/Connectomics/QmitkBrainNetworkAnalysisView.h index ef6158c2bc..712604a641 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/Connectomics/QmitkBrainNetworkAnalysisView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/Connectomics/QmitkBrainNetworkAnalysisView.h @@ -1,115 +1,118 @@ /*=================================================================== 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 QmitkBrainNetworkAnalysisView_h #define QmitkBrainNetworkAnalysisView_h #include #include #include "ui_QmitkBrainNetworkAnalysisViewControls.h" #include "mitkConnectomicsNetworkCreator.h" #include "mitkConnectomicsNetworkMapper3D.h" #include "mitkConnectomicsHistogramCache.h" // ####### ITK includes ####### #include /*! \brief QmitkBrainNetworkAnalysisView This bundle provides GUI for the brain network analysis algorithms. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkBrainNetworkAnalysisView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; QmitkBrainNetworkAnalysisView(); virtual ~QmitkBrainNetworkAnalysisView(); virtual void CreateQtPartControl(QWidget *parent); virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); protected slots: /// \brief Called when the user clicks the GUI button void OnConvertToRGBAImagePushButtonClicked(); /// \brief Align two images by copying the geometry void OnNetworkifyPushButtonClicked(); /// \brief Create synthetic networks void OnSyntheticNetworkCreationPushButtonClicked(); /// \brief Adjust parameters depending on synthetic network type void OnSyntheticNetworkComboBoxCurrentIndexChanged(int currentIndex); /// \brief Create modularization of network void OnModularizePushButtonClicked(); + /// \brief Prune network + void OnPrunePushButtonClicked(); + protected: // ####### Functions ####### /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( std::vector nodes ); /// \brief Converts an image into a RGBA image template < typename TPixel, unsigned int VImageDimension > void TurnIntoRGBA( itk::Image* inputImage); /// \brief Wipe display and empty statistics void WipeDisplay(); // ####### Variables ####### Ui::QmitkBrainNetworkAnalysisViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; mitk::ConnectomicsNetworkCreator::Pointer m_ConnectomicsNetworkCreator; mitk::ConnectomicsNetworkMapper3D::Pointer m_NetworkMapper; /// Cache for histograms mitk::ConnectomicsHistogramCache histogramCache; // Demo/Developer mode toggle bool m_demomode; // The selected synthetic network type int m_currentIndex; }; #endif // _QMITKBRAINNETWORKANALYSISVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/Connectomics/QmitkBrainNetworkAnalysisViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/Connectomics/QmitkBrainNetworkAnalysisViewControls.ui index 497e043298..6001212fcb 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/Connectomics/QmitkBrainNetworkAnalysisViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/Connectomics/QmitkBrainNetworkAnalysisViewControls.ui @@ -1,363 +1,370 @@ QmitkBrainNetworkAnalysisViewControls 0 0 227 - 1012 + 1045 0 0 QmitkTemplate Data QLabel { color: rgb(255, 0, 0) } Please select data! Image 1: - Image 2: - Convert the selected image to RGBA format Convert to RGBA Create a network from a parcellation and a fiber image Networkify Create Synthetic Networks Divide in Modules + + + + Prune Network + + + Qt::Vertical 20 40 true Synthetic Network Options Parameter 1 false 9999 Parameter 2 false 3 999.899999999999977 Network Statistics # of vertices: # of edges: - - # of self loops: - average degree - connection density - efficiency - global clustering - Histograms 0 0 50 150 50 150 50 150 Qt::Vertical 20 40 QmitkNetworkHistogramCanvas QWidget
internal/Connectomics/QmitkNetworkHistogramCanvas.h
1