#include <cpExtensions/Visualization/ImageBlender.h>
+#include <cstring>
+
#include <vtkDataObject.h>
#include <vtkImageData.h>
#include <vtkImageIterator.h>
<< std::endl;
}
+// -------------------------------------------------------------------------
+unsigned int cpExtensions::Visualization::ImageBlender::
+GetNumberOfImages( ) const
+{
+ return( ( const_cast< Self* >( this ) )->GetNumberOfInputConnections( 0 ) );
+}
+
// -------------------------------------------------------------------------
const double& cpExtensions::Visualization::ImageBlender::
GetMaxWindow( ) const
b = c->second.B;
}
else
- r = g = b = double( 1 );
+ {
+ TColor c;
+ r = c.R;
+ g = c.G;
+ b = c.B;
+
+ } // fi
}
// -------------------------------------------------------------------------
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
} // rof
- // Initialize window/level
- vtkImageData* main_image = inData[ 0 ][ 0 ];
- double range[ 2 ];
- main_image->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 ];
-
- // Update window/level
- 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;
-
// Real update
this->_GenerateData( inData[ 0 ], numInputs, outData[ 0 ], outExt, id );
}
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(
int id
)
{
- vtkImageIterator< unsigned char > inItsFast[ 256 ];
- unsigned char* inSIFast[ 256 ];
- vtkImageProgressIterator< unsigned char > outIt( outData, outExt, this, id );
-
- /*
- double *weights =
- static_cast<vtkDoubleArray *>(this->GetWeights())->GetPointer(0);
- double totalWeight = this->CalculateTotalWeight();
- int normalize = this->GetNormalizeByWeight();
- */
-
- vtkImageIterator< unsigned char > *inIts;
- unsigned char** inSI;
- if( numInputs < 256 )
- {
- inIts = inItsFast;
- inSI = inSIFast;
- }
- else
+ 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 )
{
- inIts = new vtkImageIterator< unsigned char >[ numInputs ];
- inSI = new unsigned char*[ numInputs ];
-
- } // fi
-
- // Loop through all input ImageData to initialize iterators
- for( int i = 0; i < numInputs; ++i )
- inIts[ i ].Initialize( inDatas[ i ], outExt );
-
- // Loop through output pixels
- double m = double( 1 ) / this->m_Window;
- double c = double( 0.5 ) - ( this->m_Level / this->m_Window );
- while( !outIt.IsAtEnd( ) )
- {
- // Prepare all iterators
- for( int j = 0; j < numInputs; ++j )
- inSI[ j ] = inIts[ j ].BeginSpan( );
- unsigned char* outSI = outIt.BeginSpan( );
- unsigned char* outSIEnd = outIt.EndSpan( );
-
- // Pixel operation
- while( outSI != outSIEnd )
+ int dk = ( k - this->m_Extent[ 4 ] ) * e13;
+ for( int j = outExt[ 2 ]; j <= outExt[ 3 ]; ++j )
{
- // Window/Level value from main image
- double wl = ( *inSI[ 0 ] * m ) + c;
- if( wl < double( 0 ) ) wl = double( 0 );
- if( wl > double( 1 ) ) wl = double( 1 );
-
- // Prepare color values
- double r = wl;
- double g = wl;
- double b = wl;
- double a = double( 1 );
-
- /*
- double sum = 0.;
- for(int k=0; k < numInputs; ++k)
- {
- sum += weights[k] * *inSI[k];
- }
- */
-
- r *= double( 255 );
- g *= double( 255 );
- b *= double( 255 );
- a *= double( 255 );
-
- // Assign RGBA value
- *outSI = static_cast< unsigned char >( r ); outSI++;
- *outSI = static_cast< unsigned char >( g ); outSI++;
- *outSI = static_cast< unsigned char >( b ); outSI++;
- *outSI = static_cast< unsigned char >( a ); outSI++;
-
- // Advance inputs
- for( int l = 0; l < numInputs; ++l )
- inSI[ l ]++;
-
- } // elihw
-
- // Advance all iterators
- for( int j = 0; j < numInputs; ++j )
- inIts[ j ].NextSpan( );
- outIt.NextSpan( );
+ 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;
- } // elihw
+ // Prepare color
+ r = g = b = v;
+ a = _1;
- // Free auxiliary buffers
- if( numInputs >= 256 )
- {
- delete [] inIts;
- delete [] inSI;
+ // 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
- } // fi
+ } // rof
}
// eof - $RCSfile$