From be40532af01f0fe6b1cf9b6ecab37e4c4e9eaa51 Mon Sep 17 00:00:00 2001 From: Leonardo Florez-Valencia Date: Wed, 30 Sep 2015 16:50:28 -0500 Subject: [PATCH] Segmentation and WindowLevel interaction updated --- .../Visualization/ImageInteractorStyle.cxx | 7 +- .../Visualization/ImageSliceActors.cxx | 143 ++++++++++++------ .../Visualization/ImageSliceActors.h | 8 + lib/cpExtensions/Visualization/MPRActors.cxx | 117 +++++++++++++- lib/cpExtensions/Visualization/MPRActors.h | 21 ++- lib/cpExtensions/Visualization/MPRObjects.cxx | 20 ++- 6 files changed, 242 insertions(+), 74 deletions(-) diff --git a/lib/cpExtensions/Visualization/ImageInteractorStyle.cxx b/lib/cpExtensions/Visualization/ImageInteractorStyle.cxx index ab3fee3..b784808 100644 --- a/lib/cpExtensions/Visualization/ImageInteractorStyle.cxx +++ b/lib/cpExtensions/Visualization/ImageInteractorStyle.cxx @@ -402,8 +402,8 @@ WindowLevel( ) this->WindowLevelCurrentPosition[ 1 ] ) / double( size[ 1 ] ); - double w = this->WindowLevelInitial[ 0 ] * ( double( 1 ) + sw ); - double l = this->WindowLevelInitial[ 1 ] * ( double( 1 ) + sl ); + double w = this->WindowLevelInitial[ 0 ] + ( sw * 1000.0 ); + double l = this->WindowLevelInitial[ 1 ] + ( sl * 1000.0 ); double minw = this->m_MPRActors->GetMinWindow( 0 ); double maxw = this->m_MPRActors->GetMaxWindow( 0 ); double minl = this->m_MPRActors->GetMinLevel( 0 ); @@ -414,8 +414,7 @@ WindowLevel( ) if( l < minl ) l = minl; if( maxl < l ) l = maxl; - this->m_MPRActors->SetWindow( 0, w ); - this->m_MPRActors->SetLevel( 0, l ); + this->m_MPRActors->SetWindowLevel( 0, w, l ); this->Interactor->Render( ); this->_RenderAssociateInteractors( ); } diff --git a/lib/cpExtensions/Visualization/ImageSliceActors.cxx b/lib/cpExtensions/Visualization/ImageSliceActors.cxx index 52be1f1..ef55f54 100644 --- a/lib/cpExtensions/Visualization/ImageSliceActors.cxx +++ b/lib/cpExtensions/Visualization/ImageSliceActors.cxx @@ -22,62 +22,22 @@ New( ) void cpExtensions::Visualization::ImageSliceActors:: AddInputConnection( vtkAlgorithmOutput* aout, int axis ) { - unsigned int nImages = this->SliceMappers.size( ); - vtkSmartPointer< vtkImageSliceMapper > mapper = vtkSmartPointer< vtkImageSliceMapper >::New( ); this->SliceMappers.push_back( mapper ); mapper->SetInputConnection( aout ); - mapper->SetOrientation( - ( nImages == 0 )? axis: this->SliceMappers[ 0 ]->GetOrientation( ) - ); - mapper->Update( ); - - vtkSmartPointer< vtkImageActor > actor = - vtkSmartPointer< vtkImageActor >::New( ); - this->ImageActors.push_back( actor ); - actor->SetMapper( mapper ); - actor->Modified( ); - - if( nImages == 0 ) - { - this->AddItem( this->TextActor ); - this->AddItem( this->PlaneActor ); - - } // fi - this->AddItem( actor ); - this->Modified( ); + this->_ConfigureNewInput( axis ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageSliceActors:: AddInputData( vtkImageData* data, int axis ) { - unsigned int nImages = this->SliceMappers.size( ); - vtkSmartPointer< vtkImageSliceMapper > mapper = vtkSmartPointer< vtkImageSliceMapper >::New( ); this->SliceMappers.push_back( mapper ); mapper->SetInputData( data ); - mapper->SetOrientation( - ( nImages == 0 )? axis: this->SliceMappers[ 0 ]->GetOrientation( ) - ); - mapper->Update( ); - - vtkSmartPointer< vtkImageActor > actor = - vtkSmartPointer< vtkImageActor >::New( ); - this->ImageActors.push_back( actor ); - actor->SetMapper( mapper ); - actor->Modified( ); - - if( nImages == 0 ) - { - this->AddItem( this->TextActor ); - this->AddItem( this->PlaneActor ); - - } // fi - this->AddItem( actor ); - this->Modified( ); + this->_ConfigureNewInput( axis ); } // ------------------------------------------------------------------------- @@ -190,6 +150,34 @@ GetPlaneActor( ) const return( this->PlaneActor ); } +// ------------------------------------------------------------------------- +void cpExtensions::Visualization::ImageSliceActors:: +SetInterpolate( bool v ) +{ + if( this->Interpolate != v ) + { + for( unsigned int i = 0; i < this->ImageActors.size( ); ++i ) + this->ImageActors[ i ]->SetInterpolate( v ); + this->Interpolate = v; + this->Modified( ); + + } // fi +} + +// ------------------------------------------------------------------------- +void cpExtensions::Visualization::ImageSliceActors:: +InterpolateOn( ) +{ + this->SetInterpolate( true ); +} + +// ------------------------------------------------------------------------- +void cpExtensions::Visualization::ImageSliceActors:: +InterpolateOff( ) +{ + this->SetInterpolate( false ); +} + // ------------------------------------------------------------------------- double* cpExtensions::Visualization::ImageSliceActors:: GetDisplayBounds( ) const @@ -204,7 +192,12 @@ GetDisplayBounds( ) const void cpExtensions::Visualization::ImageSliceActors:: GetDisplayBounds( double bounds[ 6 ] ) const { - if( this->ImageActors.size( ) > 0 ) + if( this->ImageActors.size( ) == 0 ) + { + bounds[ 0 ] = bounds[ 2 ] = bounds[ 4 ] = double( -1 ); + bounds[ 1 ] = bounds[ 3 ] = bounds[ 5 ] = double( -1 ); + } + else this->ImageActors[ 0 ]->GetDisplayBounds( bounds ); } @@ -347,7 +340,7 @@ SetSliceNumber( const int& slice ) this->PlaneSource->Modified( ); this->PlaneMapper->Modified( ); this->PlaneActor->Modified( ); - this->Modified( ); + this->UpdateText( ); } // ------------------------------------------------------------------------- @@ -374,10 +367,35 @@ UpdateText( ) this->Modified( ); } +// ------------------------------------------------------------------------- +void cpExtensions::Visualization::ImageSliceActors:: +UpdateText( const double& w, const double& l ) +{ + if( this->SliceMappers.size( ) > 0 ) + { + char axis; + int axId = this->SliceMappers[ 0 ]->GetOrientation( ); + if ( axId == 0 ) axis = 'X'; + else if( axId == 1 ) axis = 'Y'; + else if( axId == 2 ) axis = 'Z'; + + std::sprintf( + this->TextBuffer, "Axis: %c (%d) | W/L (%.2f/%.2f)", + axis, this->SliceMappers[ 0 ]->GetSliceNumber( ), w, l + ); + } + else + this->TextBuffer[ 0 ] = '\0'; + this->TextActor->SetInput( this->TextBuffer ); + this->TextActor->Modified( ); + this->Modified( ); +} + // ------------------------------------------------------------------------- cpExtensions::Visualization::ImageSliceActors:: ImageSliceActors( ) - : Superclass( ) + : Superclass( ), + Interpolate( false ) { this->Clear( ); } @@ -388,4 +406,39 @@ cpExtensions::Visualization::ImageSliceActors:: { } +// ------------------------------------------------------------------------- +void cpExtensions::Visualization::ImageSliceActors:: +_ConfigureNewInput( int axis ) +{ + unsigned int nImages = this->ImageActors.size( ); + + // Configure mapper + vtkImageSliceMapper* mapper = this->SliceMappers[ nImages ]; + if( nImages == 0 ) + mapper->SetOrientation( axis ); + else + mapper->SetOrientation( this->SliceMappers[ 0 ]->GetOrientation( ) ); + mapper->Update( ); + + // Create actor + vtkSmartPointer< vtkImageActor > actor = + vtkSmartPointer< vtkImageActor >::New( ); + this->ImageActors.push_back( actor ); + actor->SetMapper( mapper ); + actor->SetInterpolate( this->Interpolate ); + actor->Modified( ); + + if( nImages == 0 ) + { + this->AddItem( this->TextActor ); + this->AddItem( this->PlaneActor ); + + } // fi + this->AddItem( actor ); + + if( nImages > 1 ) + this->SetSliceNumber( this->GetSliceNumber( ) ); + this->Modified( ); +} + // eof - $RCSfile$ diff --git a/lib/cpExtensions/Visualization/ImageSliceActors.h b/lib/cpExtensions/Visualization/ImageSliceActors.h index 0e1fdae..90b9ff0 100644 --- a/lib/cpExtensions/Visualization/ImageSliceActors.h +++ b/lib/cpExtensions/Visualization/ImageSliceActors.h @@ -50,6 +50,10 @@ namespace cpExtensions vtkActor* GetPlaneActor( ); const vtkActor* GetPlaneActor( ) const; + void SetInterpolate( bool v ); + void InterpolateOn( ); + void InterpolateOff( ); + double* GetDisplayBounds( ) const; void GetDisplayBounds( double bounds[ 6 ] ) const; @@ -59,11 +63,14 @@ namespace cpExtensions int GetSliceNumberMaxValue( ) const; void SetSliceNumber( const int& slice ); void UpdateText( ); + void UpdateText( const double& w, const double& l ); protected: ImageSliceActors( ); virtual ~ImageSliceActors( ); + void _ConfigureNewInput( int axis ); + private: // Purposely not implemented ImageSliceActors( const Self& ); @@ -73,6 +80,7 @@ namespace cpExtensions // Multiple actors std::vector< vtkSmartPointer< vtkImageSliceMapper > > SliceMappers; std::vector< vtkSmartPointer< vtkImageActor > > ImageActors; + bool Interpolate; // Unique objects vtkSmartPointer< vtkPolyData > PlaneSource; diff --git a/lib/cpExtensions/Visualization/MPRActors.cxx b/lib/cpExtensions/Visualization/MPRActors.cxx index 90fdb7d..54e689a 100644 --- a/lib/cpExtensions/Visualization/MPRActors.cxx +++ b/lib/cpExtensions/Visualization/MPRActors.cxx @@ -1,8 +1,11 @@ #include +#include + #include #include #include +#include #include #include #include @@ -40,6 +43,7 @@ AddInputConnection( vtkAlgorithmOutput* aout ) this->ImageMaps[ 0 ]->SetInputConnection( aout ); this->SetLookupTableToWindowLevel( 0 ); this->_Update( 0 ); + this->ResetWindowLevel( 0 ); return( 0 ); } else @@ -64,7 +68,9 @@ AddInputConnection( vtkAlgorithmOutput* aout ) vtkSmartPointer< vtkImageMapToColors >::New( ) ); this->ImageMaps[ N ]->SetInputConnection( aout ); - this->SetLookupTableToWindowLevel( N ); + this->SetLookupTableToColor( + N, double( 1 ), double( 0 ), double( 0 ) + ); this->_Update( N ); return( N ); } @@ -87,6 +93,7 @@ AddInputData( vtkImageData* image ) this->ImageMaps[ 0 ]->SetInputData( image ); this->SetLookupTableToWindowLevel( 0 ); this->_Update( 0 ); + this->ResetWindowLevel( 0 ); return( 0 ); } else @@ -107,7 +114,9 @@ AddInputData( vtkImageData* image ) vtkSmartPointer< vtkImageMapToColors >::New( ) ); this->ImageMaps[ N ]->SetInputData( image ); - this->SetLookupTableToWindowLevel( N ); + this->SetLookupTableToColor( + N, double( 1 ), double( 0 ), double( 0 ) + ); this->_Update( N ); return( N ); } @@ -196,6 +205,15 @@ PopDataFrom( w->RemoveActor( this->ImageOutlineActor ); } +// ------------------------------------------------------------------------- +void cpExtensions::Visualization::MPRActors:: +LinkInteractors( ) +{ + this->_Update( 0 ); + this->_Update( 1 ); + this->_Update( 2 ); +} + // ------------------------------------------------------------------------- void cpExtensions::Visualization::MPRActors:: SetLookupTable( unsigned int i, vtkScalarsToColors* lut ) @@ -345,6 +363,27 @@ SetLevel( unsigned int i, const double& l ) } // fi } +// ------------------------------------------------------------------------- +void cpExtensions::Visualization::MPRActors:: +SetWindowLevel( unsigned int i, const double& w, const double& l ) +{ + vtkWindowLevelLookupTable* lut = + dynamic_cast< vtkWindowLevelLookupTable* >( this->GetLookupTable( i ) ); + if( lut != NULL ) + { + lut->SetWindow( w ); + lut->SetLevel( l ); + lut->Build( ); + this->ImageMaps[ i ]->Modified( ); + + for( unsigned int j = 0; j < 3; ++j ) + this->Slices[ 0 ][ j ]->UpdateText( w, l ); + + this->Modified( ); + + } // fi +} + // ------------------------------------------------------------------------- void cpExtensions::Visualization::MPRActors:: ResetWindowLevel( unsigned int i ) @@ -357,6 +396,8 @@ ResetWindowLevel( unsigned int i ) double r[ 2 ]; image->GetScalarRange( r ); lut->SetTableRange( r ); + lut->SetWindow( r[ 1 ] - r[ 0 ] ); + lut->SetLevel( ( r[ 1 ] + r[ 0 ] ) / double( 2 ) ); lut->Build( ); this->ImageMaps[ i ]->Modified( ); this->Modified( ); @@ -364,6 +405,64 @@ ResetWindowLevel( unsigned int i ) } // fi } +// ------------------------------------------------------------------------- +void cpExtensions::Visualization::MPRActors:: +SetLookupTableToColor( + unsigned int i, const double& r, const double& g, const double& b + ) +{ + static const double _0 = double( 0 ); + static const double _1 = double( 1 ); + static const double _2 = double( 2 ); + static const double _4 = double( 4 ); + static const double _6 = double( 6 ); + static const double _OPACITY = double( 0.6 ); + + // Check if the input has been configured + vtkImageData* image = this->_Image( i ); + if( image == NULL ) + return; + + double range[ 2 ]; + image->GetScalarRange( range ); + + // Get HSV from display color + double cmax = ( r > g )? r: g; cmax = ( b > cmax )? b: cmax; + double cmin = ( r < g )? r: g; cmin = ( b < cmin )? b: cmin; + double d = cmax - cmin; + + double saturation = ( std::fabs( cmax ) > _0 )? d / cmax: _0; + double value = cmax; + double hue = _0; + if( d > _0 ) + { + if( r == cmax ) + hue = std::fmod( ( g - b ) / d, _6 ); + else if( g == cmax ) + hue = ( ( b - r ) / d ) + _2; + else if( b == cmax ) + hue = ( ( r - g ) / d ) + _4; + hue *= _1 / _6; + + } // fi + + // Define new lookup table + vtkSmartPointer< vtkLookupTable > lut = + vtkSmartPointer< vtkLookupTable >::New( ); + lut->SetScaleToLinear( ); + lut->SetAboveRangeColor( _0, _0, _0, _0 ); + lut->SetBelowRangeColor( _0, _0, _0, _0 ); + lut->SetNanColor( _0, _0, _0, _0 ); + lut->SetTableRange( range[ 0 ], range[ 1 ] ); + lut->SetAlphaRange( _0, _OPACITY ); + lut->SetHueRange( _0, hue ); + lut->SetSaturationRange( _0, saturation ); + lut->SetValueRange( _0, value ); + lut->Build( ); + + this->SetLookupTable( i, lut ); +} + // ------------------------------------------------------------------------- int cpExtensions::Visualization::MPRActors:: GetSliceNumberMinValue( const int& axis ) const @@ -464,7 +563,9 @@ _Image( unsigned int i ) const vtkAlgorithm* algo = this->ImageMaps[ i ]->GetInputAlgorithm( ); vtkInformation* info = algo->GetOutputInformation( 0 ); return( - vtkImageData::SafeDownCast( info->Get( vtkDataObject::DATA_OBJECT( ) ) ) + vtkImageData::SafeDownCast( + info->Get( vtkDataObject::DATA_OBJECT( ) ) + ) ); } else @@ -490,6 +591,16 @@ _Update( unsigned int i ) ); this->Slices[ j ][ k ]->UpdateText( ); + // Add all of slice's props + this->Slices[ j ][ k ]->InitTraversal( ); + vtkProp* prop = this->Slices[ j ][ k ]->GetNextProp( ); + while( prop != NULL ) + { + this->AddItem( prop ); + prop = this->Slices[ j ][ k ]->GetNextProp( ); + + } // elihw + } // rof } // rof diff --git a/lib/cpExtensions/Visualization/MPRActors.h b/lib/cpExtensions/Visualization/MPRActors.h index 0aafebe..d0de6e0 100644 --- a/lib/cpExtensions/Visualization/MPRActors.h +++ b/lib/cpExtensions/Visualization/MPRActors.h @@ -41,11 +41,6 @@ namespace cpExtensions int AddInputConnection( vtkAlgorithmOutput* aout ); int AddInputData( vtkImageData* image ); - /* - void SetInputConnection( vtkAlgorithmOutput* aout ); - void SetInputData( vtkImageData* image ); - */ - void PushDataInto( vtkRenderer* x, vtkRenderer* y, @@ -58,12 +53,7 @@ namespace cpExtensions vtkRenderer* z, vtkRenderer* w ); - void LinkInteractors( ) - { - this->_Update( 0 ); - this->_Update( 1 ); - this->_Update( 2 ); - } + void LinkInteractors( ); // Lookup table methods void SetLookupTable( unsigned int i, vtkScalarsToColors* lut ); @@ -79,8 +69,17 @@ namespace cpExtensions double GetLevel( unsigned int i ) const; void SetWindow( unsigned int i, const double& w ); void SetLevel( unsigned int i, const double& l ); + void SetWindowLevel( unsigned int i, const double& w, const double& l ); void ResetWindowLevel( unsigned int i ); + // Color lookup table + void SetLookupTableToColor( + unsigned int i, + const double& r = double( 1 ), + const double& g = double( 0 ), + const double& b = double( 0 ) + ); + // Slice access int GetSliceNumberMinValue( const int& axis ) const; int GetSliceNumberMaxValue( const int& axis ) const; diff --git a/lib/cpExtensions/Visualization/MPRObjects.cxx b/lib/cpExtensions/Visualization/MPRObjects.cxx index ddc1747..914c46d 100644 --- a/lib/cpExtensions/Visualization/MPRObjects.cxx +++ b/lib/cpExtensions/Visualization/MPRObjects.cxx @@ -1,5 +1,9 @@ #include +#include +#include +#include + // ------------------------------------------------------------------------- cpExtensions::Visualization::MPRObjects* cpExtensions::Visualization::MPRObjects:: @@ -54,14 +58,6 @@ SetImage( vtkImageData* image ) this->m_Renderers[ 3 ] ); - // Correct cameras positions - /* TODO - vtkCamera* zCam = this->m_Renderers[ 2 ]->GetActiveCamera( ); - zCam->SetViewUp( 0, -1, 0 ); - zCam->SetPosition( 0, 0, -1 ); - zCam->SetFocalPoint( 0, 0, 0 ); - */ - // First rendering this->m_MPRActors->ResetSlices( ); this->ResetCameras( ); @@ -72,10 +68,12 @@ SetImage( vtkImageData* image ) void cpExtensions::Visualization::MPRObjects:: AddAuxiliaryImage( vtkImageData* image ) { - this->m_MPRActors->AddInputData( image ); - -#error Definir LUT de la nueva imagen + // Try to add new image + int id = this->m_MPRActors->AddInputData( image ); + if( id < 0 ) + return; + // Push everything on renderers this->m_MPRActors->PushDataInto( this->m_Renderers[ 0 ], this->m_Renderers[ 1 ], -- 2.47.1