X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=lib%2FcpExtensions%2FVisualization%2FImageBlender.cxx;h=44a08abc90c9f169d7dd89661b3c82c6dfda4ded;hb=dbc5b32e13cf4a299ce29a5666a8e0a2ff5e62a8;hp=d5cbbd4b872326263d88ba1abaf9845b2dd7084f;hpb=dc7b0175c06fcd6bd7a6d475a2592336953dad36;p=cpPlugins.git diff --git a/lib/cpExtensions/Visualization/ImageBlender.cxx b/lib/cpExtensions/Visualization/ImageBlender.cxx index d5cbbd4..44a08ab 100644 --- a/lib/cpExtensions/Visualization/ImageBlender.cxx +++ b/lib/cpExtensions/Visualization/ImageBlender.cxx @@ -1,7 +1,5 @@ #include -#include - #include #include #include @@ -17,220 +15,163 @@ New( ) return( new Self( ) ); } -// ------------------------------------------------------------------------- -void cpExtensions::Visualization::ImageBlender:: -PrintSelf( std::ostream& os, vtkIndent indent ) -{ - this->Superclass::PrintSelf( os, indent ); - - // Objects - os << indent << "Colors: " << std::endl; - auto i = this->m_Colors.begin( ); - for( ; i != this->m_Colors.end( ); ++i ) - os - << indent << indent << i->first << " : [" - << i->second.R << ", " - << i->second.G << ", " - << i->second.B << "]" - << std::endl; -} - // ------------------------------------------------------------------------- unsigned int cpExtensions::Visualization::ImageBlender:: -GetNumberOfImages( ) const -{ - return( ( const_cast< Self* >( this ) )->GetNumberOfInputConnections( 0 ) ); -} - -// ------------------------------------------------------------------------- -const double& cpExtensions::Visualization::ImageBlender:: -GetMaxWindow( ) const +GetNumberOfInputs( ) { - return( this->m_MaxWindow ); + unsigned int np = this->GetNumberOfInputPorts( ); + unsigned int ni = 0; + for( unsigned int p = 0; p < np; ++p ) + ni += this->GetNumberOfInputConnections( p ); + return( ni ); } // ------------------------------------------------------------------------- -const double& cpExtensions::Visualization::ImageBlender:: -GetMaxLevel( ) const -{ - return( this->m_MaxLevel ); -} - -// ------------------------------------------------------------------------- -const double& cpExtensions::Visualization::ImageBlender:: -GetMinWindow( ) const +cpExtensions::Visualization::ImageBlender:: +ImageBlender( ) + : Superclass( ) { - return( this->m_MinWindow ); + this->SetNumberOfInputPorts( 1 ); } // ------------------------------------------------------------------------- -const double& cpExtensions::Visualization::ImageBlender:: -GetMinLevel( ) const +cpExtensions::Visualization::ImageBlender:: +~ImageBlender( ) { - return( this->m_MinLevel ); } // ------------------------------------------------------------------------- -const double& cpExtensions::Visualization::ImageBlender:: -GetWindow( ) const +int cpExtensions::Visualization::ImageBlender:: +RequestInformation( + vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector + ) { - return( this->m_Window ); -} + if( this->GetNumberOfInputConnections( 0 ) == 0 ) + return( 0 ); -// ------------------------------------------------------------------------- -const double& cpExtensions::Visualization::ImageBlender:: -GetLevel( ) const -{ - return( this->m_Level ); + vtkDataObject::SetPointDataActiveScalarInfo( + outputVector->GetInformationObject( 0 ), + VTK_UNSIGNED_CHAR, + 1 + ); + return( 1 ); } // ------------------------------------------------------------------------- -void cpExtensions::Visualization::ImageBlender:: -SetWindow( const double& w ) +int cpExtensions::Visualization::ImageBlender:: +RequestData( + vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector + ) { - if( this->m_Window != w ) + this->m_Ranges.clear( ); + for( int i = 0; i < this->GetNumberOfInputPorts( ); ++i ) { - this->m_Window = w; - this->Modified( ); - - } // fi -} + vtkInformationVector* portInfo = inputVector[ i ]; + for( int j = 0; j < portInfo->GetNumberOfInformationObjects( ); ++j ) + { + vtkInformation* info = portInfo->GetInformationObject( j ); + vtkImageData* image = vtkImageData::SafeDownCast( + info->Get( vtkDataObject::DATA_OBJECT( ) ) + ); + if( image != NULL ) + { + double r[ 2 ]; + image->GetScalarRange( r ); + this->m_Ranges.push_back( r[ 0 ] ); + this->m_Ranges.push_back( r[ 1 ] ); + } + else + { + this->m_Ranges.push_back( double( 0 ) ); + this->m_Ranges.push_back( double( 0 ) ); -// ------------------------------------------------------------------------- -void cpExtensions::Visualization::ImageBlender:: -SetLevel( const double& l ) -{ - if( this->m_Level != l ) - { - this->m_Level = l; - this->Modified( ); + } // fi - } // fi -} + } // rof -// ------------------------------------------------------------------------- -void cpExtensions::Visualization::ImageBlender:: -SetWindowLevel( const double& w, const double& l ) -{ - this->SetWindow( w ); - this->SetLevel( l ); + } // rof + return( + this->Superclass::RequestData( request, inputVector, outputVector ) + ); } // ------------------------------------------------------------------------- -void cpExtensions::Visualization::ImageBlender:: -GetColor( - const unsigned int& i, - double& r, - double& g, - double& b - ) const +// Description: +// This templated function executes the filter for any type of data. +template< class T > +void cpExtensions_Visualization_ImageBlender_Execute( + cpExtensions::Visualization::ImageBlender* self, + vtkImageData** inDatas, int numInputs, + const std::vector< double >& ranges, vtkImageData* outData, + int outExt[ 6 ], int id, T* really_not_used + ) { - auto c = this->m_Colors.find( i ); - if( c != this->m_Colors.end( ) ) + vtkImageIterator< T > inItsFast[ 256 ]; + T* inSIFast[ 256 ]; + vtkImageProgressIterator< T > outIt( outData, outExt, self, id ); + vtkImageIterator< T >* inIts; + T** inSI; + if( numInputs < 256 ) { - r = c->second.R; - g = c->second.G; - b = c->second.B; + inIts = inItsFast; + inSI = inSIFast; } else { - TColor c; - r = c.R; - g = c.G; - b = c.B; + inIts = new vtkImageIterator< T >[ numInputs ]; + inSI = new T*[ numInputs ]; } // fi -} -// ------------------------------------------------------------------------- -void cpExtensions::Visualization::ImageBlender:: -SetColor( - const unsigned int& i, - const double& r, - const double& g, - const double& b - ) -{ - this->m_Colors[ i ] = TColor( r, g, b ); - this->Modified( ); -} + // Loop through all input ImageData to initialize iterators + for( int i = 0; i < numInputs; ++i ) + inIts[ i ].Initialize( inDatas[ i ], outExt ); -// ------------------------------------------------------------------------- -cpExtensions::Visualization::ImageBlender:: -ImageBlender( ) - : Superclass( ), - m_MaxWindow( double( 0 ) ), - m_MaxLevel( double( 0 ) ), - m_MinWindow( double( 0 ) ), - m_MinLevel( double( 0 ) ), - m_Window( double( 0 ) ), - m_Level( double( 0 ) ) -{ - this->SetNumberOfInputPorts( 1 ); -} + // Loop through output pixels + while( !outIt.IsAtEnd( ) ) + { + for( int j = 0; j < numInputs; ++j ) + inSI[ j ] = inIts[ j ].BeginSpan( ); -// ------------------------------------------------------------------------- -cpExtensions::Visualization::ImageBlender:: -~ImageBlender( ) -{ -} + T* outSI = outIt.BeginSpan( ); + T* outSIEnd = outIt.EndSpan( ); -// ------------------------------------------------------------------------- -int cpExtensions::Visualization::ImageBlender:: -RequestInformation( - vtkInformation* request, - vtkInformationVector** inputVector, - vtkInformationVector* outputVector - ) -{ - // Check number of inputs - int numInputs = this->GetNumberOfInputConnections( 0 ); - if( numInputs == 0 ) - return( 0 ); + // Pixel operation + while( outSI != outSIEnd ) + { + // Input 0 is ignored: it is just used to guarantee sizes all over + // the result + double vmax = double( 0 ); + for( int k = 1; k < numInputs; ++k ) + { + double v = + ( ( double( k ) * double( *inSI[ k ] ) ) - ranges[ k << 1 ] ) / + ( ranges[ ( k << 1 ) + 1 ] - ranges[ k << 1 ] ); + vmax = ( vmax < v )? v: vmax; - // Get input image - vtkInformation* inInfo = inputVector[ 0 ]->GetInformationObject( 0 ); - if( inInfo == NULL ) - return( 0 ); - vtkImageData* inData = vtkImageData::SafeDownCast( - inInfo->Get( vtkDataObject::DATA_OBJECT( ) ) - ); - if( inData == NULL ) - return( 0 ); + } // rof + *outSI = static_cast< T >( vmax ); + outSI++; + for( int l = 0; l < numInputs; ++l ) + inSI[ l ]++; - // Configure buffer extent - inData->GetExtent( this->m_Extent ); - this->m_Extent[ 1 ] -= this->m_Extent[ 0 ]; - this->m_Extent[ 3 ] -= this->m_Extent[ 2 ]; - this->m_Extent[ 5 ] -= this->m_Extent[ 4 ]; - this->m_Extent[ 1 ] += 1; - this->m_Extent[ 3 ] += 1; - this->m_Extent[ 5 ] += 1; + } // elihw + for( int j = 0; j < numInputs; ++j ) + inIts[ j ].NextSpan( ); + outIt.NextSpan( ); - // Configure window/level - double range[ 2 ]; - inData->GetScalarRange( range ); - this->m_MaxWindow = range[ 1 ] - range[ 0 ]; - this->m_MinWindow = this->m_MaxWindow * double( 1e-2 ); - this->m_MinLevel = range[ 0 ]; - this->m_MaxLevel = range[ 1 ]; - if( this->m_Window < this->m_MinWindow ) - this->m_Window = this->m_MinWindow; - if( this->m_Window > this->m_MaxWindow ) - this->m_Window = this->m_MaxWindow; - if( this->m_Level < this->m_MinLevel ) - this->m_Level = this->m_MinLevel; - if( this->m_Level > this->m_MaxLevel ) - this->m_Level = this->m_MaxLevel; - this->m_WLSlope = double( 1 ) / this->m_Window; - this->m_WLOffset = double( 0.5 ) - ( this->m_Level / this->m_Window ); + } // elihw - // Configure output type - vtkDataObject::SetPointDataActiveScalarInfo( - outputVector->GetInformationObject( 0 ), - VTK_UNSIGNED_CHAR, 4 - ); - return( 1 ); + if( numInputs >= 256) + { + delete [] inIts; + delete [] inSI; + + } // fi } // ------------------------------------------------------------------------- @@ -239,8 +180,7 @@ ThreadedRequestData( vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector, - vtkImageData*** inData, - vtkImageData** outData, + vtkImageData*** inData, vtkImageData** outData, int outExt[ 6 ], int id ) { @@ -252,28 +192,20 @@ ThreadedRequestData( } // fi int numInputs = this->GetNumberOfInputConnections( 0 ); + int scalarType = inData[ 0 ][ 0 ]->GetScalarType( ); int numComp = inData[ 0 ][ 0 ]->GetNumberOfScalarComponents( ); - if( numComp > 1 ) - { - vtkErrorMacro( - "ThreadedRequestData: Input has " << numComp - << " components, but just 1 is supported" - ); - return; - - } // fi - for( int i = 1; i < numInputs; ++i ) { + int otherType = inData[ 0 ][ i ]->GetScalarType( ); int otherComp = inData[ 0 ][ i ]->GetNumberOfScalarComponents( ); - if( otherComp != numComp ) + if( otherType != scalarType || otherComp != numComp ) { if( id == 0 ) vtkErrorMacro( "ThreadedRequestData: Input " << i - << " has " << otherComp - << " components, but input 0 has " << numComp - << " components" + << " has " << otherComp << " components of type " + << otherType << ", but input 0 has " << numComp + << " components of type " << scalarType ); return; @@ -281,8 +213,19 @@ ThreadedRequestData( } // rof - // Real update - this->_GenerateData( inData[ 0 ], numInputs, outData[ 0 ], outExt, id ); + switch( scalarType ) + { + vtkTemplateMacro( + cpExtensions_Visualization_ImageBlender_Execute( + this, inData[ 0 ], numInputs, this->m_Ranges, + outData[ 0 ], outExt, id, static_cast< VTK_TT* >( 0 ) + ) + ); + default: + if( id == 0 ) + vtkErrorMacro( << "Execute: Unknown ScalarType" ); + return; + } // hctiws } // ------------------------------------------------------------------------- @@ -290,129 +233,7 @@ int cpExtensions::Visualization::ImageBlender:: FillInputPortInformation( int i, vtkInformation* info ) { info->Set( vtkAlgorithm::INPUT_IS_REPEATABLE( ), 1 ); - return( this->Superclass::FillInputPortInformation( i, info ) ); -} - - -// ------------------------------------------------------------------------- -#define cpExtensions_ImageBlender_Type( O, V, T, B ) \ - O V = O( 0 ); \ - switch( T ) \ - { \ - case VTK_CHAR: \ - V = O( *( reinterpret_cast< char* >( B ) ) ); \ - break; \ - case VTK_SHORT: \ - V = O( *( reinterpret_cast< short* >( B ) ) ); \ - break; \ - case VTK_INT: \ - V = O( *( reinterpret_cast< int* >( B ) ) ); \ - break; \ - case VTK_LONG: \ - V = O( *( reinterpret_cast< long* >( B ) ) ); \ - break; \ - case VTK_UNSIGNED_CHAR: \ - V = O( *( reinterpret_cast< unsigned char* >( B ) ) ); \ - break; \ - case VTK_UNSIGNED_SHORT: \ - V = O( *( reinterpret_cast< unsigned short* >( B ) ) ); \ - break; \ - case VTK_UNSIGNED_INT: \ - V = O( *( reinterpret_cast< unsigned int* >( B ) ) ); \ - break; \ - case VTK_UNSIGNED_LONG: \ - V = O( *( reinterpret_cast< unsigned long* >( B ) ) ); \ - break; \ - case VTK_FLOAT: \ - V = O( *( reinterpret_cast< float* >( B ) ) ); \ - break; \ - case VTK_DOUBLE: \ - V = O( *( reinterpret_cast< double* >( B ) ) ); \ - break; \ - } - -// ------------------------------------------------------------------------- -void cpExtensions::Visualization::ImageBlender:: -_GenerateData( - vtkImageData** inDatas, - int numInputs, - vtkImageData* outData, - int outExt[6], - int id - ) -{ - static const double _0 = double( 0 ); - static const double _1 = double( 1 ); - static const double _255 = double( 255 ); - - unsigned char* mBuffer = - reinterpret_cast< unsigned char* >( inDatas[ 0 ]->GetScalarPointer( ) ); - unsigned char* oBuffer = - reinterpret_cast< unsigned char* >( outData->GetScalarPointer( ) ); - int mType = inDatas[ 0 ]->GetScalarType( ); - int mSize = inDatas[ 0 ]->GetScalarSize( ); - - double r, g, b, a; - int e13 = this->m_Extent[ 1 ] * this->m_Extent[ 3 ]; - for( int k = outExt[ 4 ]; k <= outExt[ 5 ]; ++k ) - { - int dk = ( k - this->m_Extent[ 4 ] ) * e13; - for( int j = outExt[ 2 ]; j <= outExt[ 3 ]; ++j ) - { - int dj = ( ( j - this->m_Extent[ 2 ] ) * this->m_Extent[ 3 ] ) + dk; - for( int i = outExt[ 0 ]; i <= outExt[ 1 ]; ++i ) - { - int di = ( i - this->m_Extent[ 0 ] ) + dj; - - // Get main value - cpExtensions_ImageBlender_Type( - double, v, mType, mBuffer + ( di * mSize ) - ); - v *= this->m_WLSlope; - v += this->m_WLOffset; - if( v < _0 ) v = _0; - if( v > _1 ) v = _1; - - // Prepare color - r = g = b = v; - a = _1; - - // Blend colors - for( int i = 1; i < numInputs; ++i ) - { - unsigned char* cBuffer = - reinterpret_cast< unsigned char* >( - inDatas[ i ]->GetScalarPointer( ) - ); - int cType = inDatas[ i ]->GetScalarType( ); - int cSize = inDatas[ i ]->GetScalarSize( ); - cpExtensions_ImageBlender_Type( - double, c, cType, cBuffer + ( di * cSize ) - ); - if( c > double( 0 ) ) - { - TColor rgb = this->m_Colors[ i ]; - r *= rgb.R * rgb.N; - g *= rgb.G * rgb.N; - b *= rgb.B * rgb.N; - a = _1; - - } // fi - - } // rof - - // Update color - int di4 = di << 2; - oBuffer[ di4 + 0 ] = static_cast< unsigned char >( r * _255 ); - oBuffer[ di4 + 1 ] = static_cast< unsigned char >( g * _255 ); - oBuffer[ di4 + 2 ] = static_cast< unsigned char >( b * _255 ); - oBuffer[ di4 + 3 ] = static_cast< unsigned char >( a * _255 ); - - } // rof - - } // rof - - } // rof + return( this->Superclass::FillInputPortInformation( i,info ) ); } // eof - $RCSfile$