vtkGPUVolumeRayCastMapper only consider the last label defined in a mask

Hello,
I have a doubt I am using vtkGPUVolumeRayCastMapper with a label type mask. And I works if I only define label 1. But I add the label 2 it considers the label 1 as label 2 so the material it takes for both labels are label 2. It is as if it overwrites label 1 with label 2 and both have the same material. So If I have a mask of label 1 it returns the image with material 2. That is, the last set. Someone had the same problem?. Can it be a bug?. Thank you

    vtkNew<vtkColorTransferFunction> color_tf;
vtkNew<vtkPiecewiseFunction> opacity_tf;


opacity_tf->AddPoint(-100, 0.00);
opacity_tf->AddPoint(0, 0.00);

//SKIN
color_tf->AddRGBPoint(-100, .94, .74, .50);
color_tf->AddRGBPoint(0, .93, .66, .53);

// ARTERY
color_tf->AddRGBPoint(460, .82, .32, .22);
color_tf->AddRGBPoint(464, .44, .72, .82);
color_tf->AddRGBPoint(495, .85, .0, .01);
opacity_tf->AddPoint(volume_opacity_pos_, 0.0);


//BONE
color_tf->AddRGBPoint(568, .90, .85, .75);
color_tf->AddRGBPoint(750, .90, .85, .75);
opacity_tf->AddPoint(volume_opacity_pos_ + 56, 0.05);
opacity_tf->AddPoint(volume_opacity_pos_ + 129, 0.05);
opacity_tf->AddPoint(volume_opacity_pos_ + 324, 0.05);
opacity_tf->AddPoint(volume_opacity_pos_ + 335, 0.05);

//TEETH
color_tf->AddRGBPoint(850, .96, .96, .96);
opacity_tf->AddPoint(volume_opacity_pos_ + 379, 0.0);


//Fully Transparent
vtkNew<vtkColorTransferFunction> color_tf2;
color_tf2->DeepCopy(color_tf);
vtkNew<vtkPiecewiseFunction> opacity_tf2;
opacity_tf2->AddPoint(-100, 0.00);
opacity_tf2->AddPoint(0, 0.00);
opacity_tf2->AddPoint(volume_opacity_pos_, 0.0);
opacity_tf2->AddPoint(volume_opacity_pos_ + 56, 0.00);
opacity_tf2->AddPoint(volume_opacity_pos_ + 129, 0.00);
opacity_tf2->AddPoint(volume_opacity_pos_ + 324, 0.00);
opacity_tf2->AddPoint(volume_opacity_pos_ + 335, 0.00);
opacity_tf2->AddPoint(volume_opacity_pos_ + 379, 0.0);

 //I have tried just in case	       
  //vtkVolumeProperty::SafeDownCast
 //(get_volume()->GetProperty())->
 //SetIndependentComponents(true);

//Semi Transparent
vtkVolumeProperty::SafeDownCast(get_volume()->GetProperty())->SetLabelColor(1, color_tf);
vtkVolumeProperty::SafeDownCast(get_volume()->GetProperty())->SetLabelScalarOpacity(1, opacity_tf);

//Transparent
vtkVolumeProperty::SafeDownCast(get_volume()->GetProperty())->SetLabelColor(2, color_tf2);
  vtkVolumeProperty::SafeDownCast(get_volume()->GetProperty())->SetLabelScalarOpacity(2, opacity_tf2);

 vtkGPUVolumeRayCastMapper::SafeDownCast
(dcm_volume_->volume_->GetMapper())
 ->SetMaskTypeToLabelMap();
 vtkGPUVolumeRayCastMapper::SafeDownCast
 (dcm_volume_->volume_->GetMapper())
 ->SetMaskInput(ImageCast->GetOutput());
vtkGPUVolumeRayCastMapper::
  SafeDownCast(dcm_volume_->volume_
 ->GetMapper())->SetMaskBlendFactor(1.0);
vtkGPUVolumeRayCastMapper::SafeDownCast
  (dcm_volume_->volume_->
  GetMapper())->Update();
dcm_volume_->volume_->
      GetMapper()->Modified();

You need to enable nearest neighbor interpolation for rendering binary labelmaps, otherwise at the boundary you will always see the color corresponding to the lowest value (due to interpolation).

Note that you cannot volume render binary labelmaps nicely, as they will appear blocky which makes it hard to recognize shapes. For proper display, I know two options that work well:

  • A. Store each label in a separate volume, apply Gaussian blurring, and use multi-volume rendering. This allows very fast updates when the labelmap is changed but it requires lots of memory, because each label needs its own volume. It is useful for real-time applications (for example, simulate drilling into the volume in virtual reality).
  • B. Convert to surface mesh using flying edges filter and smooth the surface. The conversion and smoothing may take several seconds, so labelmap updates take time, but rendering is fast and you don’t need memory to store extra volumes. This approach is used in 3D Slicer’s segment editor module (which allows interactive editing of labelmaps).

Thank you for answering. Yes I noticed that block thing around the label. I gad to put those areas opacity 0. Now, I have an issue with labels that I cannot define 2 labels. It always takes the last one you define.

For example if i have a mask full of 1s and I define two labels 1 and 2. The volume texture will take the value of the material of the label 2 even the mask is full of 1s not the first one and it won’t consider the two labels. I tried this small example and it did not work. I need something very basic to show some selected areas by mouse fully transparent and some others half transparent. Very very basic even with blocks showing it would be ok. I was debugging and i saw that texture only considered one component instead of two. I will keep looking into the code.

Thank you very much

I don’t understand what you describe, but your example above misses setting interpolation to nearest neighbor and without that you cannot volume render labelmaps.

If you have trouble setting up your transfer functions then another approach is to specify RGBA values for each voxel instead (by enabling independent components).

Hi thank you for answering. I would like to enable the transfer voxel for regions of the mask not intensity values. But it only allows me to define one label the second is ignored. To click one region for example make it red, to click + shift make it green. If I define only the red label it works if I define green and red it does not work. I wonder what it is the reason. Thanks I added the interpolation in my code.

I think I found the problem. It is a bug of the label algorithm. If you have one label only it works. But If you have two labels and you are using the first one you need to have at least one voxel with label 0 and 2 to make it work. I am testing it and doing that I manage to get the two labels for that reason the test of vtk of this feature works because it has the 0, 1 and 2 labels defined. By now, I will make this trick, but I wonder if it is possible to report it.

Thanks for all the help