2 /*===================================================================
4 The Medical Imaging Interaction Toolkit (MITK)
6 Copyright (c) German Cancer Research Center,
7 Division of Medical and Biological Informatics.
10 This software is distributed WITHOUT ANY WARRANTY; without
11 even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 See LICENSE.txt or http://www.mitk.org for details.
16 ===================================================================*/
18 #ifndef _MITK_CORRELATIONCALCULATOR_TXX
19 #define _MITK_CORRELATIONCALCULATOR_TXX
23 #include <mitkLogMacros.h>
25 #include <mitkImageCast.h>
26 #include <mitkImageAccessByItk.h>
27 #include <mitkImagePixelReadAccessor.h>
29 #include <itkImageRegionConstIteratorWithIndex.h>
32 mitk::CorrelationCalculator<T>::CorrelationCalculator()
33 : m_InvalidTimeSeries( true )
34 , m_ParcellationImage( nullptr )
35 , m_TimeSeriesImage( nullptr )
40 mitk::CorrelationCalculator<T>::~CorrelationCalculator()
45 double mitk::CorrelationCalculator<T>::CalculatePearsonCorrelationCoefficient( const std::vector<T>& one, const std::vector<T>& two )
47 double standardDevOne( std::sqrt(CalculateCovariance( one, one )) );
48 double standardDevTwo( std::sqrt(CalculateCovariance( two, two )) );
50 return CalculateCovariance(one, two) / (standardDevOne * standardDevTwo);
55 double mitk::CorrelationCalculator<T>::CalculateCovariance( const std::vector<T>& one, const std::vector<T>& two )
57 if( one.size() != two.size() )
59 MITK_WARN << "Expect two same length vectors for covariance.";
63 double meanOne( std::accumulate( one.begin(), one.end(), 0.0 ) / double(one.size()) );
64 double meanTwo( std::accumulate( two.begin(), two.end(), 0.0 ) / double(two.size()) );
68 for(unsigned int index(0); index < one.size(); ++index)
70 sum += (one[index] - meanOne ) * (two[index] - meanTwo);
73 double n( one.size() );
79 std::vector< double > mitk::CorrelationCalculator<T>::ExtractAverageTimeSeriesOfParcel( int parcelValue )
81 if( this->m_InvalidTimeSeries)
83 this->ExtractAllAverageTimeSeries();
84 this->m_InvalidTimeSeries = false;
87 std::vector< double > result;
89 if( m_AverageTimeSeries.count(parcelValue) > 0 )
91 result = m_AverageTimeSeries.find(parcelValue)->second;
98 void mitk::CorrelationCalculator<T>::DoWholeCorrelation( )
100 if(this->m_TimeSeriesImage->GetDimension() != 4 )
102 MITK_ERROR << "Expect 3D+t timeseries image.";
105 // calculate numbe of voxels
106 unsigned int numberOfVoxels(1);
108 for(unsigned int loop(0); loop < 3; ++loop)
110 numberOfVoxels *= this->m_TimeSeriesImage->GetDimension( loop );
111 dim[loop] = this->m_TimeSeriesImage->GetDimension( loop );
113 m_CorrelationMatrix = vnl_matrix<double>(numberOfVoxels, numberOfVoxels);
114 unsigned int numberOfSteps( this->m_TimeSeriesImage->GetDimension( 3 ));
116 //iterate over all voxels and calculate correlation
117 for( unsigned int i( 0 ); i < numberOfVoxels; ++i )
119 for( unsigned int j(0); j < i; ++j)
121 std::vector< T > one, two;
122 one.resize(numberOfSteps);
123 two.resize(numberOfSteps);
125 mitk::ImagePixelReadAccessor<T, 4> readAccess(m_TimeSeriesImage);
130 idx_i[2] = (i / (dim[0] * dim[1])) % dim[2];
131 idx_i[1] = (i / dim[0]) % dim[1];
132 idx_i[0] = i % dim[0];
134 idx_j[2] = (j / (dim[0] * dim[1])) % dim[2];
135 idx_j[1] = (j / dim[0]) % dim[1];
136 idx_j[0] = j % dim[0];
138 for(unsigned int timestep(0); timestep < numberOfSteps; ++timestep)
142 one[timestep] = readAccess.GetPixelByIndex(idx_i);
143 two[timestep] = readAccess.GetPixelByIndex(idx_j);
146 m_CorrelationMatrix[i][j] = mitk::CorrelationCalculator<T>::CalculatePearsonCorrelationCoefficient( one, two );
147 m_CorrelationMatrix[j][i] = m_CorrelationMatrix[i][j];
149 m_CorrelationMatrix[i][i] = 1;
154 void mitk::CorrelationCalculator<T>::DoParcelCorrelation( typename mitk::CorrelationCalculator<T>::ParcelMode mode )
156 this->ExtractCenterOfMassForParcels();
158 m_CorrelationMatrix = vnl_matrix<double>(m_ParcelCenterOfMass.size(), m_ParcelCenterOfMass.size());
161 AccessFixedDimensionByItk(this->m_TimeSeriesImage, ExtractAllAverageTimeSeries, 4);
165 for( std::map< int, std::vector<double> >::const_iterator it(m_AverageTimeSeries.begin()); it != m_AverageTimeSeries.end(); ++it, ++i)
168 for(std::map< int, std::vector<double> >::const_iterator inner_it(m_AverageTimeSeries.begin()); inner_it != it; ++inner_it, ++j)
172 case UseAverageTimeSeries :
173 m_CorrelationMatrix[i][j] = mitk::CorrelationCalculator<double>::CalculatePearsonCorrelationCoefficient( it->second, inner_it->second );
175 case UseMaximumCorrelation :
176 m_CorrelationMatrix[i][j] = mitk::CorrelationCalculator<T>::GetParcelCorrelation(it->first, inner_it->first, mode);
178 case UseAverageCorrelation :
179 m_CorrelationMatrix[i][j] = mitk::CorrelationCalculator<T>::GetParcelCorrelation(it->first, inner_it->first, mode);
182 mitkThrow() << "No valid parcel correlation mode selected";
184 m_CorrelationMatrix[j][i] = m_CorrelationMatrix[i][j];
187 m_CorrelationMatrix[i][i] = 1;
188 m_LabelOrderMap.insert(std::pair< unsigned int, int >(i, it->first));
193 double mitk::CorrelationCalculator<T>::GetParcelCorrelation(const int& parcelA, const int& parcelB, typename mitk::CorrelationCalculator<T>::ParcelMode& mode) const
197 if(m_ParcelTimeSeries.count(parcelA) < 1 || m_ParcelTimeSeries.count(parcelB) < 1)
199 MITK_ERROR << "Tried to calculate correlation between at least one non-existent parcel " << parcelA << " and " << parcelB;
202 std::vector< std::vector< T > > parcelATimeSeriesVector = m_ParcelTimeSeries.find( parcelA )->second;
203 std::vector< std::vector< T > > parcelBTimeSeriesVector = m_ParcelTimeSeries.find( parcelB )->second;
207 case UseAverageTimeSeries :
209 mitkThrow() << "Wrong function called for this mode.";
212 case UseMaximumCorrelation :
214 for(unsigned int i(0); i < parcelATimeSeriesVector.size(); ++i)
216 for(unsigned int j(0); j < parcelBTimeSeriesVector.size(); ++j)
219 mitk::CorrelationCalculator<T>::CalculatePearsonCorrelationCoefficient(
220 parcelATimeSeriesVector[i], parcelBTimeSeriesVector[j]
230 case UseAverageCorrelation :
233 for(unsigned int i(0); i < parcelATimeSeriesVector.size(); ++i)
235 for(unsigned int j(0); j < parcelBTimeSeriesVector.size(); ++j)
238 mitk::CorrelationCalculator<T>::CalculatePearsonCorrelationCoefficient(
239 parcelATimeSeriesVector[i], parcelBTimeSeriesVector[j]
243 result = corr / double( parcelATimeSeriesVector.size() * parcelBTimeSeriesVector.size() );
248 mitkThrow() << "No valid parcel correlation mode selected";
256 void mitk::CorrelationCalculator<T>::Modified( ) const
258 Superclass::Modified();
262 void mitk::CorrelationCalculator<T>::Modified( )
264 Superclass::Modified();
265 this->m_InvalidTimeSeries = true;
269 template< typename TPixel, unsigned int VImageDimension >
270 void mitk::CorrelationCalculator<T>::ExtractAllAverageTimeSeries( itk::Image<TPixel, VImageDimension>* itkTimeSeriesImage )
272 // storage contains for each parcel value a vector of length time steps,
273 // which manages the pixel value vectors for each time step
274 std::map< int, std::vector< std::vector< T > > > storage;
276 itk::ImageRegionConstIteratorWithIndex< itk::Image<TPixel, VImageDimension> > it_itkTimeSeriesImage(
277 itkTimeSeriesImage, itkTimeSeriesImage->GetLargestPossibleRegion() );
279 unsigned int timesteps( itkTimeSeriesImage->GetLargestPossibleRegion().GetSize()[3] );
281 for( it_itkTimeSeriesImage.GoToBegin(); !it_itkTimeSeriesImage.IsAtEnd(); ++it_itkTimeSeriesImage )
283 itk::Index< 4 > itkIndex = it_itkTimeSeriesImage.GetIndex();
284 itk::Index< 3 > itkIndex3D;
285 for(unsigned int axis( 0 ); axis < 3; ++axis )
287 itkIndex3D.SetElement( axis, itkIndex.GetElement(axis) );
290 mitk::Point3D tempPoint;
292 m_TimeSeriesImage->GetGeometry()->IndexToWorld( itkIndex3D, tempPoint );
293 mitk::ImagePixelReadAccessor<int, 3> readAccess(m_ParcellationImage);
294 int value( std::floor( readAccess.GetPixelByWorldCoordinates( tempPoint ) + 0.5 ) );
296 if(storage.count(value) == 0)
298 std::vector< std::vector< T > > temp;
299 temp.resize( timesteps );
300 storage.insert(std::pair< int, std::vector< std::vector< T > > >(value, temp));
303 storage[value][ itkIndex.GetElement( 3 ) ].push_back( it_itkTimeSeriesImage.Value() );
307 for( typename std::map< int, std::vector< std::vector< T > > >::iterator it = storage.begin(); it != storage.end(); ++it )
309 std::vector< double > means;
310 means.resize( timesteps );
311 for(unsigned int loop(0); loop < timesteps; ++loop)
313 means[loop] = std::accumulate( it->second[loop].begin(), it->second[loop].end(), 0.0 ) / double(it->second[loop].size());
315 m_AverageTimeSeries.insert( std::pair< int, std::vector< double > >(it->first, means) );
317 // reorder the information in storage for m_ParcelTimeSeries
318 // time series of each voxel by their parcellation value
319 std::vector< std::vector< T > > vectorOfTimeSeriesVectors;
320 vectorOfTimeSeriesVectors.resize(it->second[0].size());
321 for(unsigned int loop(0); loop < vectorOfTimeSeriesVectors.size(); ++loop)
323 vectorOfTimeSeriesVectors[loop].resize(timesteps);
326 for(unsigned int step(0); step < timesteps; ++step)
328 for(unsigned int number(0); number < vectorOfTimeSeriesVectors.size(); ++number)
330 vectorOfTimeSeriesVectors[number][step] = it->second[step][number];
333 m_ParcelTimeSeries.insert(std::pair< int, std::vector< std::vector< T > > >(it->first, vectorOfTimeSeriesVectors));
338 void mitk::CorrelationCalculator<T>::ExtractCenterOfMassForParcels()
340 itk::Image< int, 3 >::Pointer itkParcelImage;
341 mitk::CastToItkImage( m_ParcellationImage, itkParcelImage );
343 itk::ImageRegionConstIteratorWithIndex< itk::Image<int, 3> > it_itkParcelImage(
344 itkParcelImage, itkParcelImage->GetLargestPossibleRegion() );
346 std::map< int, std::vector< mitk::Point3D > > storage;
348 for( it_itkParcelImage.GoToBegin(); !it_itkParcelImage.IsAtEnd(); ++it_itkParcelImage )
350 mitk::Point3D tempPoint;
352 m_ParcellationImage->GetGeometry()->IndexToWorld( it_itkParcelImage.GetIndex(), tempPoint );
354 if( storage.count( it_itkParcelImage.Value() ) == 1 )
356 storage[ it_itkParcelImage.Value() ].push_back( tempPoint );
360 storage.insert( std::pair< int, std::vector< mitk::Point3D > >(
361 it_itkParcelImage.Value(), std::vector< mitk::Point3D >( 1, tempPoint ) ));
365 for( std::map< int, std::vector< mitk::Point3D > >::iterator it( storage.begin() ); it != storage.end(); ++it )
367 itk::Vector< int, 3 > tempVector( 0 );
369 for( unsigned int loop(0); loop < it->second.size(); ++loop)
371 for(unsigned int index(0); index < 3; ++index)
373 tempVector[index] = tempVector[index] + it->second[loop][index];
377 mitk::Point3D tempPoint;
379 for( unsigned int loop(0); loop < 3; ++loop )
381 tempPoint.SetElement(loop, tempVector.GetElement(loop) / it->second.size());
384 m_ParcelCenterOfMass.insert( std::pair< int, mitk::Point3D >(it->first, tempPoint) );
389 const vnl_matrix< double >* mitk::CorrelationCalculator<T>::GetCorrelationMatrix() const
391 return &m_CorrelationMatrix;
395 const std::map< unsigned int, int >* mitk::CorrelationCalculator<T>::GetLabelOrderMap() const
397 return &m_LabelOrderMap;
401 mitk::ConnectomicsNetwork::Pointer mitk::CorrelationCalculator<T>::GetConnectomicsNetwork()
403 mitk::ConnectomicsNetwork::NetworkType* boostGraph = new mitk::ConnectomicsNetwork::NetworkType;
405 std::map< int, mitk::ConnectomicsNetwork::VertexDescriptorType > idToVertexMap;
408 unsigned int numberOfNodes( m_CorrelationMatrix.columns() );
410 for(unsigned int loop(0); loop < numberOfNodes; ++loop )
412 idToVertexMap.insert( std::pair< int, mitk::ConnectomicsNetwork::VertexDescriptorType >(loop, boost::add_vertex( *boostGraph )) );
415 if( m_ParcelCenterOfMass.size() > 0)
417 std::map< int, mitk::Point3D >::const_iterator it = m_ParcelCenterOfMass.begin();
418 for(unsigned int loop(0); (loop < numberOfNodes) && (it != m_ParcelCenterOfMass.end()); ++loop, ++it )
420 (*boostGraph)[ idToVertexMap[loop] ].id = idToVertexMap[loop];
421 (*boostGraph)[ idToVertexMap[loop] ].label = std::to_string( it->first );
422 (*boostGraph)[ idToVertexMap[loop] ].coordinates.resize(3);
423 for(unsigned int dimension(0); dimension < 3; ++dimension)
425 (*boostGraph)[ idToVertexMap[loop] ].coordinates[dimension] = it->second[dimension];
431 for( unsigned int i(0); i < numberOfNodes; ++i)
433 for(unsigned int j(0); j < i; ++j)
435 mitk::ConnectomicsNetwork::VertexDescriptorType vertexA = idToVertexMap[i];
436 mitk::ConnectomicsNetwork::VertexDescriptorType vertexB = idToVertexMap[j];
437 boost::add_edge( vertexA, vertexB, *boostGraph );
438 (*boostGraph)[ boost::edge(vertexA, vertexB, *boostGraph ).first ].sourceId = (*boostGraph)[vertexA].id;
439 (*boostGraph)[ boost::edge(vertexA, vertexB, *boostGraph ).first ].targetId = (*boostGraph)[vertexB].id;
440 (*boostGraph)[ boost::edge(vertexA, vertexB, *boostGraph ).first ].weight = 1;
441 (*boostGraph)[ boost::edge(vertexA, vertexB, *boostGraph ).first ].edge_weight = m_CorrelationMatrix[i][j];
446 mitk::ConnectomicsNetwork::Pointer network = mitk::ConnectomicsNetwork::New();
447 network->SetBoostGraph( boostGraph );
448 network->SetGeometry( dynamic_cast<mitk::BaseGeometry*>(m_TimeSeriesImage->GetGeometry()->Clone().GetPointer()) );
449 network->UpdateBounds();
450 network->SetIsModified( true );
454 #endif /* _MITK_CORRELATIONCALCULATOR_TXX */