# [vtkusers] Opacity discrepancy with downscaled volume despite opacity unit distance == spacing

Elvis Stansvik elvis.stansvik at orexplore.com
Sun Feb 12 04:40:56 EST 2017

```I've now realized that I've made a blunder. In order to get the two volumes
to look the same, I should of course set the ScalarOpacityUnitDistance to
the *same* value for both volumes.

The attached PNG shows the result when I set the ScalarOpacityUnitDistance
to 0.006 (the spacing of the higher-resolution volume) for both volumes
(code below).

The volumes now look very similar opacity-wise, but they are still not
quite equal. The (0-255) HSV values of the left/right volumes are (0, 95,
100) and (0, 93, 100), so the right one (the low res one) is still a little
less opaque than the left one.

Anyone who can explain where this discrepancy comes from?

My question is really: How can two volumes with the exact same shape (a
cube) and bounds in VTK world coordinates looks different opacity-wise,
when they are rendered with the same opacity transfer function and have the
same ScalarOpacityUnitDistance set?

Elvis

main.cpp:

#include <algorithm>

#include <vtkCamera.h>
#include <vtkColorTransferFunction.h>
#include <vtkGPUVolumeRayCastMapper.h>
#include <vtkImageData.h>
#include <vtkImageInterpolator.h>
#include <vtkImageResize.h>
#include <vtkPiecewiseFunction.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartPointer.h>
#include <vtkVolume.h>
#include <vtkVolumeProperty.h>

// Create a volume from the given image
vtkSmartPointer<vtkVolume> createVolume(vtkSmartPointer<vtkImageData>
image) {
auto color = vtkSmartPointer<vtkColorTransferFunction>::New();

auto opacity = vtkSmartPointer<vtkPiecewiseFunction>::New();

auto property = vtkSmartPointer<vtkVolumeProperty>::New();
property->SetColor(color);
property->SetScalarOpacity(opacity);
property->SetInterpolationTypeToLinear();
property->SetScalarOpacityUnitDistance(0.006);

auto mapper = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
mapper->SetInputData(image);

auto volume = vtkSmartPointer<vtkVolume>::New();
volume->SetMapper(mapper);
volume->SetProperty(property);

return volume;
}

int main(int argc, char *argv[]) {

// Create a 30x30x30 volume
auto image = vtkSmartPointer<vtkImageData>::New();
image->SetDimensions(30, 30, 30);
image->SetSpacing(0.006, 0.006, 0.006);
image->AllocateScalars(VTK_FLOAT, 1);

auto imagePtr = static_cast<float *>(image->GetScalarPointer());
std::fill_n(imagePtr, 30 * 30 * 30, 1.0);

auto volume = createVolume(image);

// Create a smaller (10x10x10) version
auto interpolator = vtkSmartPointer<vtkImageInterpolator>::New();
interpolator->SetInterpolationModeToLinear();

auto resize = vtkSmartPointer<vtkImageResize>::New();
resize->SetInputData(image);
resize->SetOutputDimensions(10, 10, 10);
resize->SetInterpolator(interpolator);
resize->Update();

auto smallVolume = createVolume(resize->GetOutput());
smallVolume->SetPosition(0.2, 0, 0);

// Render the two volumes
auto renderer = vtkSmartPointer<vtkRenderer>::New();
renderer->SetBackground(1.0, 1.0, 1.0);
renderer->ResetCamera();

auto camera = renderer->GetActiveCamera();
camera->SetParallelProjection(1);

auto window = vtkSmartPointer<vtkRenderWindow>::New();
window->SetSize(800, 400);

auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
interactor->SetRenderWindow(window);
interactor->Start();

return 0;
}

CMakeLists.txt:

cmake_minimum_required(VERSION 3.1)

project(TestCase)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(VTK COMPONENTS
vtkCommonCore
vtkCommonDataModel
vtkCommonExecutionModel
vtkInteractionStyle
vtkImagingCore
vtkRenderingCore
vtkRenderingOpenGL2
vtkRenderingVolume
vtkRenderingVolumeOpenGL2
)

vtkCommonCore
vtkCommonDataModel
vtkCommonExecutionModel
vtkImagingCore
vtkInteractionStyle
vtkRenderingCore
vtkRenderingOpenGL2
vtkRenderingVolume
vtkRenderingVolumeOpenGL2
)

target_include_directories(TestCase PUBLIC
\${VTK_INCLUDE_DIRS}
)

target_compile_definitions(TestCase PUBLIC
\${VTK_DEFINITIONS}
)

2017-02-09 14:45 GMT+01:00 Elvis Stansvik <elvis.stansvik at orexplore.com>:

> Hi all,
>
> The following example shows a 30x30x30 volume rendered, and next to it a
> downscaled version of it (but using an identical opacity/transfer
> function). Notice how in the result (attached), the downscaled version is
> less opaque. This is despite me using
>
>     SetScalarOpacityUnitDistance(image->GetSpacing()[0])
>
> to set the scalar opacity unit distance to the spacing of the respective
> image. I would thought calling SetScalarOpacityUnitDistance like this would
> ensure both volumes look the same (apart from resolution).
>
> How can I make both volumes look the same opacity-wise when using the same
> transfer functions?
>
> Elvis
>
> main.cpp:
>
>
> #include <algorithm>
>
> #include <vtkCamera.h>
> #include <vtkColorTransferFunction.h>
> #include <vtkGPUVolumeRayCastMapper.h>
> #include <vtkImageData.h>
> #include <vtkImageResize.h>
> #include <vtkPiecewiseFunction.h>
> #include <vtkRenderer.h>
> #include <vtkRenderWindow.h>
> #include <vtkRenderWindowInteractor.h>
> #include <vtkSmartPointer.h>
> #include <vtkVolume.h>
> #include <vtkVolumeProperty.h>
>
> // Create a volume from the given image
> vtkSmartPointer<vtkVolume> createVolume(vtkSmartPointer<vtkImageData>
> image) {
>     auto color = vtkSmartPointer<vtkColorTransferFunction>::New();
>
>     auto opacity = vtkSmartPointer<vtkPiecewiseFunction>::New();
>
>     auto property = vtkSmartPointer<vtkVolumeProperty>::New();
>     property->SetColor(color);
>     property->SetScalarOpacity(opacity);
>     property->SetInterpolationTypeToLinear();
>     property->SetScalarOpacityUnitDistance(image->GetSpacing()[0]);
>
>     auto mapper = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
>     mapper->SetInputData(image);
>
>     auto volume = vtkSmartPointer<vtkVolume>::New();
>     volume->SetMapper(mapper);
>     volume->SetProperty(property);
>
>     return volume;
> }
>
> int main(int argc, char *argv[]) {
>
>     // Create a 30x30x30 volume
>     auto image = vtkSmartPointer<vtkImageData>::New();
>     image->SetDimensions(30, 30, 30);
>     image->SetSpacing(0.006, 0.006, 0.006);
>     image->AllocateScalars(VTK_FLOAT, 1);
>
>     auto imagePtr = static_cast<float *>(image->GetScalarPointer());
>     std::fill_n(imagePtr, 30 * 30 * 30, 1.0);
>
>     auto volume = createVolume(image);
>
>     // Create a smaller (10x10x10) version
>     auto resize = vtkSmartPointer<vtkImageResize>::New();
>     resize->SetInputData(image);
>     resize->SetOutputDimensions(10, 10, 10);
>     resize->Update();
>
>     auto smallVolume = createVolume(resize->GetOutput());
>     smallVolume->SetPosition(0.2, 0, 0);
>
>     // Render the two volumes
>     auto renderer = vtkSmartPointer<vtkRenderer>::New();
>     renderer->SetBackground(1.0, 1.0, 1.0);
>     renderer->ResetCamera();
>
>     auto camera = renderer->GetActiveCamera();
>     camera->SetParallelProjection(1);
>
>     auto window = vtkSmartPointer<vtkRenderWindow>::New();
>     window->SetSize(800, 400);
>
>     auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
>     interactor->SetRenderWindow(window);
>     interactor->Start();
>
>     return 0;
> }
>
>
> CMakeLists.txt:
>
>
> cmake_minimum_required(VERSION 3.1)
>
> project(TestCase)
>
> set(CMAKE_CXX_STANDARD 11)
> set(CMAKE_CXX_STANDARD_REQUIRED ON)
>
> find_package(VTK COMPONENTS
>     vtkCommonCore
>     vtkCommonDataModel
>     vtkCommonExecutionModel
>     vtkInteractionStyle
>     vtkImagingCore
>     vtkRenderingCore
>     vtkRenderingOpenGL2
>     vtkRenderingVolume
>     vtkRenderingVolumeOpenGL2
> )
>
>
>     vtkCommonCore
>     vtkCommonDataModel
>     vtkCommonExecutionModel
>     vtkImagingCore
>     vtkInteractionStyle
>     vtkRenderingCore
>     vtkRenderingOpenGL2
>     vtkRenderingVolume
>     vtkRenderingVolumeOpenGL2
> )
>
> target_include_directories(TestCase PUBLIC
>     \${VTK_INCLUDE_DIRS}
> )
>
>
> target_compile_definitions(TestCase PUBLIC
>     \${VTK_DEFINITIONS}
> )
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/vtkusers/attachments/20170212/0d1ca043/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: new-result.png
Type: image/png
Size: 9507 bytes
Desc: not available
URL: <http://public.kitware.com/pipermail/vtkusers/attachments/20170212/0d1ca043/attachment.png>
```