GPU Label Map masking fails if the label map contains only one value
Hello community,
We're are trying the new label masking function introduced by @sankhesh in the MR 5124 It's working great, but if the label map contains only one value (0 or 1 for example), then the whole GPU rendering disappears :/
Here is a minimal example that reproduces the pb
// Init VTK factories
#include <vtkAutoInit.h>
VTK_MODULE_INIT( vtkInteractionStyle );
VTK_MODULE_INIT( vtkRenderingContextOpenGL2 );
VTK_MODULE_INIT( vtkRenderingFreeType );
VTK_MODULE_INIT( vtkRenderingOpenGL2 );
VTK_MODULE_INIT( vtkRenderingVolumeOpenGL2 );
#include <vtkActor.h>
#include <vtkColorTransferFunction.h>
#include <vtkDataArray.h>
#include <vtkGPUVolumeRayCastMapper.h>
#include <vtkImageData.h>
#include <vtkImageShiftScale.h>
#include <vtkMetaImageWriter.h>
#include <vtkObjectFactory.h>
#include <vtkPiecewiseFunction.h>
#include <vtkPointData.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSampleFunction.h>
#include <vtkSmartPointer.h>
#include <vtkSphere.h>
#include <vtkVolume.h>
#include <vtkVolumeProperty.h>
static void CreateImageData( vtkImageData* );
int main( int argc, char** argv )
{
std::cout << "Starting Label example" << std::endl;
// Create a sphere volume
vtkSmartPointer< vtkImageData > l_image = vtkSmartPointer< vtkImageData >::New();
CreateImageData( l_image );
std::cout << "\t Main Image Created" << std::endl;
// prepare the rendering pipeline
vtkSmartPointer< vtkRenderer > l_renderer = vtkSmartPointer< vtkRenderer >::New();
l_renderer->SetBackground( 0.3, 0.3, 0.3 );
vtkSmartPointer< vtkRenderWindow > l_render_window = vtkSmartPointer< vtkRenderWindow >::New();
l_render_window->AddRenderer( l_renderer );
l_render_window->SetSize( 900, 600 );
vtkSmartPointer< vtkRenderWindowInteractor > l_iren = vtkSmartPointer< vtkRenderWindowInteractor >::New();
l_iren->SetRenderWindow( l_render_window );
// setup gpu rendering
vtkSmartPointer< vtkGPUVolumeRayCastMapper > l_mapper = vtkSmartPointer< vtkGPUVolumeRayCastMapper >::New();
l_mapper->SetBlendModeToComposite();
l_mapper->SetInputData( l_image );
l_mapper->SetAutoAdjustSampleDistances( true );
// Main TF
vtkPiecewiseFunction* l_main_tf_opacity = vtkPiecewiseFunction::New();
l_main_tf_opacity->AddPoint( 0.0, 0.0 );
l_main_tf_opacity->AddPoint( 80.0, 1.0 );
l_main_tf_opacity->AddPoint( 80.1, 0.0 );
l_main_tf_opacity->AddPoint( 255.0, 0.0 );
vtkColorTransferFunction* l_main_tf_color = vtkColorTransferFunction::New();
l_main_tf_color->AddRGBPoint( 0.0, 1.0, 0.0, 0.0 ); // RED everywhere
l_main_tf_color->AddRGBPoint( 40.0, 1.0, 0.0, 0.0 ); // RED everywhere
l_main_tf_color->AddRGBPoint( 255.0, 1.0, 0.0, 01.0 ); // RED everywhere
vtkSmartPointer< vtkVolumeProperty > l_property = vtkSmartPointer< vtkVolumeProperty >::New();
l_property->SetShade( true );
l_property->SetIndependentComponents( true );
l_property->SetColor( l_main_tf_color );
l_property->SetScalarOpacity( l_main_tf_opacity );
l_property->SetInterpolationTypeToLinear();
vtkSmartPointer< vtkVolume > l_volume = vtkSmartPointer< vtkVolume >::New();
l_volume->SetMapper( l_mapper );
l_volume->SetProperty( l_property );
l_renderer->AddVolume( l_volume );
l_renderer->ResetCamera();
l_render_window->Render();
std::cout << "\t VR with a red sphere should be visible" << std::endl;
// label map pipeline
// prepare an empty label map of the same size;
vtkImageData* l_label_map = vtkImageData::New();
l_label_map->SetOrigin( l_image->GetOrigin() );
l_label_map->SetSpacing( l_image->GetSpacing() );
l_label_map->SetDimensions( l_image->GetDimensions() );
l_label_map->AllocateScalars( VTK_UNSIGNED_CHAR, 1 );
std::memset( l_label_map->GetScalarPointer(), 1, sizeof( unsigned char ) * l_label_map->GetNumberOfPoints() );
std::cout << "\t Label Map with value 1 everywhere created" << std::endl;
// HERE is the hack, you need to add at least one value of 0 in the mask otherwise it won't work
//static_cast< unsigned char* >( l_label_map->GetScalarPointer() )[ 0 ] = 0;
vtkColorTransferFunction* l_label_1_tf_color = vtkColorTransferFunction::New();
l_label_1_tf_color->AddRGBPoint( 0.0, 0.0, 1.0, 0.0 ); // GREEN everywhere
l_label_1_tf_color->AddRGBPoint( 40.0, 0.0, 1.0, 0.0 ); // GREEN everywhere
l_label_1_tf_color->AddRGBPoint( 255.0, 0.0, 1.0, 0.0 ); // GREEN everywhere
std::cout << "\t Feeding the property with a new Green TF for value 1" << std::endl;
l_property->SetLabelColor( 1, l_label_1_tf_color );
l_property->SetLabelScalarOpacity( 1, l_main_tf_opacity );
l_mapper->SetMaskInput( l_label_map );
/*
vtkSmartPointer< vtkMetaImageWriter > l_writer_1 = vtkSmartPointer< vtkMetaImageWriter >::New();
l_writer_1->SetFileName( "sphere.mhd" );
l_writer_1->SetInputData( l_image );
l_writer_1->Write();
vtkSmartPointer< vtkMetaImageWriter > l_writer_2 = vtkSmartPointer< vtkMetaImageWriter >::New();
l_writer_2->SetFileName( "mask.mhd" );
l_writer_2->SetInputData( l_label_map );
l_writer_2->Write();
*/
l_render_window->Render();
std::cout << "\t Nothing to render now" << std::endl;
l_iren->Start();
return EXIT_SUCCESS;
}
void CreateImageData( vtkImageData* a_image )
{
// Create a spherical implicit function.
vtkSmartPointer< vtkSphere > l_sphere = vtkSmartPointer< vtkSphere >::New();
l_sphere->SetRadius( 0.1 );
l_sphere->SetCenter( 0.0, 0.0, 0.0 );
vtkSmartPointer< vtkSampleFunction > l_sample_function = vtkSmartPointer< vtkSampleFunction >::New();
l_sample_function->SetImplicitFunction( l_sphere );
l_sample_function->SetOutputScalarTypeToDouble();
l_sample_function->SetSampleDimensions( 127, 127, 127 );
l_sample_function->SetModelBounds( -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 );
l_sample_function->SetCapping( false );
l_sample_function->SetComputeNormals( false );
l_sample_function->SetScalarArrayName( "values" );
l_sample_function->Update();
vtkDataArray* l_array = l_sample_function->GetOutput()->GetPointData()->GetScalars( "values" );
double l_range[ 2 ];
l_array->GetRange( l_range );
vtkSmartPointer< vtkImageShiftScale > l_shift_scale = vtkSmartPointer< vtkImageShiftScale >::New();
l_shift_scale->SetInputConnection( l_sample_function->GetOutputPort() );
l_shift_scale->SetShift( -l_range[ 0 ] );
double l_magnitude = l_range[ 1 ] - l_range[ 0 ];
if( l_magnitude == 0.0 ) {
l_magnitude = 1.0;
}
l_shift_scale->SetScale( 255.0 / l_magnitude );
l_shift_scale->SetOutputScalarTypeToShort();
l_shift_scale->Update();
a_image->ShallowCopy( l_shift_scale->GetOutput() );
}
As soon as the label map contains 2 values it works as expected, un-comment the following line for this:
static_cast< unsigned char* >( l_label_map->GetScalarPointer() )[ 0 ] = 0;
Simon