#include #include #include #include #include #include #include #include // ------------------------------------------------------------------------- cpExtensions::Visualization::ImageBlender:: Self* cpExtensions::Visualization::ImageBlender:: 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 { return( this->m_MaxWindow ); } // ------------------------------------------------------------------------- const double& cpExtensions::Visualization::ImageBlender:: GetMaxLevel( ) const { return( this->m_MaxLevel ); } // ------------------------------------------------------------------------- const double& cpExtensions::Visualization::ImageBlender:: GetMinWindow( ) const { return( this->m_MinWindow ); } // ------------------------------------------------------------------------- const double& cpExtensions::Visualization::ImageBlender:: GetMinLevel( ) const { return( this->m_MinLevel ); } // ------------------------------------------------------------------------- const double& cpExtensions::Visualization::ImageBlender:: GetWindow( ) const { return( this->m_Window ); } // ------------------------------------------------------------------------- const double& cpExtensions::Visualization::ImageBlender:: GetLevel( ) const { return( this->m_Level ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageBlender:: SetWindow( const double& w ) { if( this->m_Window != w ) { this->m_Window = w; this->Modified( ); } // fi } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageBlender:: SetLevel( const double& l ) { if( this->m_Level != l ) { this->m_Level = l; this->Modified( ); } // fi } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageBlender:: SetWindowLevel( const double& w, const double& l ) { this->SetWindow( w ); this->SetLevel( l ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageBlender:: GetColor( const unsigned int& i, double& r, double& g, double& b ) const { auto c = this->m_Colors.find( i ); if( c != this->m_Colors.end( ) ) { r = c->second.R; g = c->second.G; b = c->second.B; } else { TColor c; r = c.R; g = c.G; b = c.B; } // 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( ); } // ------------------------------------------------------------------------- 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 ); } // ------------------------------------------------------------------------- cpExtensions::Visualization::ImageBlender:: ~ImageBlender( ) { } // ------------------------------------------------------------------------- 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 ); // 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 ); // 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; // 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 ); // Configure output type vtkDataObject::SetPointDataActiveScalarInfo( outputVector->GetInformationObject( 0 ), VTK_UNSIGNED_CHAR, 4 ); return( 1 ); } // ------------------------------------------------------------------------- void cpExtensions::Visualization::ImageBlender:: ThreadedRequestData( vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector, vtkImageData*** inData, vtkImageData** outData, int outExt[ 6 ], int id ) { if( inData[ 0 ][ 0 ] == NULL ) { vtkErrorMacro( << "Input " << 0 << " must be specified." ); return; } // fi int numInputs = this->GetNumberOfInputConnections( 0 ); 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 otherComp = inData[ 0 ][ i ]->GetNumberOfScalarComponents( ); if( otherComp != numComp ) { if( id == 0 ) vtkErrorMacro( "ThreadedRequestData: Input " << i << " has " << otherComp << " components, but input 0 has " << numComp << " components" ); return; } // fi } // rof // Real update this->_GenerateData( inData[ 0 ], numInputs, outData[ 0 ], outExt, id ); } // ------------------------------------------------------------------------- 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 } // eof - $RCSfile$