]> Creatis software - cpPlugins.git/blobdiff - lib/cpExtensions/Visualization/ImageBlender.cxx
Double click widget integrated with segmentation and deformation filters.
[cpPlugins.git] / lib / cpExtensions / Visualization / ImageBlender.cxx
index 3d90d5823dd1558934f7fa64856ab22e842745fe..d5cbbd4b872326263d88ba1abaf9845b2dd7084f 100644 (file)
@@ -1,5 +1,7 @@
 #include <cpExtensions/Visualization/ImageBlender.h>
 
+#include <cstring>
+
 #include <vtkDataObject.h>
 #include <vtkImageData.h>
 #include <vtkImageIterator.h>
@@ -33,6 +35,13 @@ PrintSelf( std::ostream& os, vtkIndent indent )
       << std::endl;
 }
 
+// -------------------------------------------------------------------------
+unsigned int cpExtensions::Visualization::ImageBlender::
+GetNumberOfImages( ) const
+{
+  return( ( const_cast< Self* >( this ) )->GetNumberOfInputConnections( 0 ) );
+}
+
 // -------------------------------------------------------------------------
 const double& cpExtensions::Visualization::ImageBlender::
 GetMaxWindow( ) const
@@ -124,7 +133,13 @@ GetColor(
     b = c->second.B;
   }
   else
-    r = g = b = double( 1 );
+  {
+    TColor c;
+    r = c.R;
+    g = c.G;
+    b = c.B;
+
+  } // fi
 }
 
 // -------------------------------------------------------------------------
@@ -168,10 +183,49 @@ RequestInformation(
   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
@@ -227,25 +281,6 @@ ThreadedRequestData(
 
   } // 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 );
 }
@@ -258,6 +293,44 @@ FillInputPortInformation( int i, vtkInformation* info )
   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(
@@ -268,99 +341,78 @@ _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$