VTK volume rendering problem

I am using the vtk library from C ++ to generate and render some synthetic voxel data with a given display of color and transparency. An example is shown below: Sample image

As the picture shows, the data is 3D in general and it works great. However, in special cases where the data becomes 2D, the visualization windows do not show anything .

I am posting a few lines of my code that might be helpful.

imageData = vtkSmartPointer<vtkImageData>::New();
imageData->SetDimensions(X1, X2, X3); //For 2D, one of X1,X2 & X3=1
imageData->AllocateScalars(VTK_INT, 1);
int* I = new int[X1X2X3](); //int X1X2X3 = X1*X2*X3
I = static_cast<int*>(imageData->GetScalarPointer());

      

Note that for 2D, either X1 = 1 or X2 = 1 or X3 = 1. Any suggestions?

EDIT: I am adding an equivalent code that will demonstrate the exact problem I am facing:

main.cpp

//#include <vtkAutoInit.h> // if not using CMake to compile, necessary to use this macro
//#define vtkRenderingCore_AUTOINIT 3(vtkInteractionStyle, vtkRenderingFreeType, vtkRenderingOpenGL2)
//#define vtkRenderingVolume_AUTOINIT 1(vtkRenderingVolumeOpenGL2)
//#define vtkRenderingContext2D_AUTOINIT 1(vtkRenderingContextOpenGL2)
#include <vtkSmartPointer.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartVolumeMapper.h>
#include <vtkColorTransferFunction.h>
#include <vtkVolumeProperty.h>
#include <vtkSampleFunction.h>
#include <vtkPiecewiseFunction.h>
#include <vtkImageData.h>
#include <stdlib.h>
using namespace std;

int main()
{
    //Declaring Variables
    vtkSmartPointer<vtkImageData> imageData;
    vtkSmartPointer<vtkVolumeProperty> volumeProperty;
    vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity;
    vtkSmartPointer<vtkColorTransferFunction> color;
    vtkSmartPointer<vtkVolume> volume;
    vtkSmartPointer<vtkSmartVolumeMapper> mapper;
    vtkSmartPointer<vtkActor> actor;
    vtkSmartPointer<vtkRenderer> renderer;
    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor;
    vtkSmartPointer<vtkRenderWindow> renderWindow;
    int* I;
    int X1, X2, X3, X1X2X3;

    //Assigning Values , Allocating Memory
    X1 = 10;
    X2 = 10;
    X3 = 10;
    X1X2X3 = X1*X2*X3;
    I = new int[X1X2X3]();
    imageData = vtkSmartPointer<vtkImageData>::New();
    volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New();
    compositeOpacity = vtkSmartPointer<vtkPiecewiseFunction>::New();
    color = vtkSmartPointer<vtkColorTransferFunction>::New();
    volume = vtkSmartPointer<vtkVolume>::New();
    mapper = vtkSmartPointer<vtkSmartVolumeMapper>::New();
    actor = vtkSmartPointer<vtkActor>::New();
    renderer = vtkSmartPointer<vtkRenderer>::New();
    renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
    renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); 
    volumeProperty->ShadeOff();
    volumeProperty->SetInterpolationType(0);
    volumeProperty->SetColor(color);
    volumeProperty->SetScalarOpacity(compositeOpacity);
    imageData->SetDimensions(X1, X2, X3);
    imageData->AllocateScalars(VTK_INT, 1);
    I = static_cast<int*>(imageData->GetScalarPointer());
    renderWindow->AddRenderer(renderer);
    renderWindowInteractor->SetRenderWindow(renderWindow);
    renderer->SetBackground(0.5, 0.5, 0.5);
    renderWindow->SetSize(800, 800);    
    mapper->SetBlendModeToComposite();
    imageData->UpdateCellGhostArrayCache();
    mapper->SetRequestedRenderModeToRayCast();
    mapper->SetInputData(imageData);
    volume->SetMapper(mapper);
    volume->SetProperty(volumeProperty);
    renderer->AddViewProp(volume);
    volumeProperty->ShadeOff();

    //Setting Voxel Data and Its Properties
    for (int i = 0; i < X1X2X3; i++)
    {
        I[i] = i;
        compositeOpacity->AddPoint(i, 1);
        color->AddRGBPoint(i, double( rand()) / RAND_MAX, double(rand()) / RAND_MAX, double(rand()) / RAND_MAX);
    }

    renderer->ResetCamera();
    renderWindow->Render();
    renderWindowInteractor->Start();
    getchar();
    return 0;
}

      

CMakeLists.txt

cmake_minimum_required(VERSION 3.0)
project(EvoSim)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(CMAKE_USE_RELATIVE_PATHS ON)
#GRABBING VTK
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})

add_executable(MAIN main.cpp)
target_link_libraries(MAIN ${VTK_LIBRARIES})

      

This results in an output like below (for, X1 = X2 = X3 = 10) enter image description here

However, if I do X1 = 1, the output window is empty.

EDIT:

I just noticed that the number of voxels by a certain size displayed on the screen is always less than the maximum number of voxels in those dimensions. For example, if X1 = X2 = X3 = 10, the number of voxels in each dimension displayed on vtkwindow is 9. This is not what I would expect. I think this is a problem with X1 = 1 making 1-1 = 0 voxel display. Any suggestions ??

+3


source to share


1 answer


This remained unanswered. So I am adding a solution / workaround. I had to add an extra dummy layer in each imagedata dimension. [Cm. This line in the code imageData-> SetDimensions (X1 +1, X2 + 1, X3 + 1); ]. Rest is self-evident.

#pragma once
//#include <vtkAutoInit.h> // if not using CMake to compile, necessary to use this macro
//#define vtkRenderingCore_AUTOINIT 3(vtkInteractionStyle, vtkRenderingFreeType, vtkRenderingOpenGL2)
//#define vtkRenderingVolume_AUTOINIT 1(vtkRenderingVolumeOpenGL2)
//#define vtkRenderingContext2D_AUTOINIT 1(vtkRenderingContextOpenGL2)
#include <vtkSmartPointer.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartVolumeMapper.h>
#include <vtkColorTransferFunction.h>
#include <vtkVolumeProperty.h>
#include <vtkSampleFunction.h>
#include <vtkPiecewiseFunction.h>
#include <vtkImageData.h>
#include <stdlib.h>
#include <numeric>      // std::iota
using namespace std;

int main()
{
    //Declaring Variables
    vtkSmartPointer<vtkImageData> imageData;
    vtkSmartPointer<vtkVolumeProperty> volumeProperty;
    vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity;
    vtkSmartPointer<vtkColorTransferFunction> color;
    vtkSmartPointer<vtkVolume> volume;
    vtkSmartPointer<vtkSmartVolumeMapper> mapper;
    vtkSmartPointer<vtkActor> actor;
    vtkSmartPointer<vtkRenderer> renderer;
    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor;
    vtkSmartPointer<vtkRenderWindow> renderWindow;
    int X1, X2, X3, X1X2X3;
    //Assigning Values , Allocating Memory
    X1 = 10;
    X2 = 10;
    X3 = 10;
    X1X2X3 = X1*X2*X3;
    imageData = vtkSmartPointer<vtkImageData>::New();
    imageData->SetDimensions(X1 + 1, X2 + 1, X3 + 1);
    imageData->AllocateScalars(VTK_INT, 1);
    volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New();
    compositeOpacity = vtkSmartPointer<vtkPiecewiseFunction>::New();
    color = vtkSmartPointer<vtkColorTransferFunction>::New();
    volume = vtkSmartPointer<vtkVolume>::New();
    mapper = vtkSmartPointer<vtkSmartVolumeMapper>::New();
    actor = vtkSmartPointer<vtkActor>::New();
    renderer = vtkSmartPointer<vtkRenderer>::New();
    renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
    renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
    volumeProperty->ShadeOff();
    volumeProperty->SetInterpolationType(0);
    volumeProperty->SetColor(color);
    volumeProperty->SetScalarOpacity(compositeOpacity);
    imageData->AllocateScalars(VTK_INT, 1);
    renderWindow->AddRenderer(renderer);
    renderWindowInteractor->SetRenderWindow(renderWindow);
    renderer->SetBackground(0.5, 0.5, 0.5);
    renderWindow->SetSize(800, 800);
    mapper->SetBlendModeToComposite();
    imageData->UpdateCellGhostArrayCache();
    mapper->SetRequestedRenderModeToRayCast();
    mapper->SetInputData(imageData);
    volume->SetMapper(mapper);
    volume->SetProperty(volumeProperty);
    renderer->AddViewProp(volume);
    volumeProperty->ShadeOff();

    //I is supposed to store the 3D data which has to be shown as volume visualization. This 3D data is stored 
    //as a 1D array in which the order of iteration over 3 dimensions is x->y->z, this leads to the following 
    //3D to 1D index conversion farmula index1D =  i + X1*j + X1*X2*k   
    vector<int> I(X1X2X3,0); // No need to use int* I = new int[X1X2X3] //Vectors are good
    std::iota(&I[0], &I[0] + X1X2X3, 1); //Creating dummy data as 1,2,3...X1X2X3

    //Setting Voxel Data and Its Properties
    for (int k = 0; k < X3 + 1 ; k++)   
    {
        for (int j = 0; j < X2 + 1 ; j++)
        {
            for (int i = 0; i < X1 + 1 ; i++)
            {
                int* voxel = static_cast<int*>(imageData->GetScalarPointer(i, j, k));

                if (i==X1 || j== X2 || k==X3)
                {
                    //Assigning zeros to dummy voxels, these will not be displayed anyways
                    voxel[0] = 0;
                }

                else
                {
                    //copying data from I to imagedata voxel
                    voxel[0] = I[i + X1*j + X1*X2*k];
                }               
            }
        }
    }

    //Setting Up Display Properties
    for (int i = 1; i < X1X2X3; i++)
    {
        compositeOpacity->AddPoint(i, 1);
        color->AddRGBPoint(i, double(rand()) / RAND_MAX, double(rand()) / RAND_MAX, double(rand()) / RAND_MAX);
    }

    renderer->ResetCamera();
    renderWindow->Render();
    renderWindowInteractor->Start();
    getchar();
    return 0;
}

      



Now the expected number of voxels in each dimension (10 according to the above code) are visible correctly

enter image description here

+1


source







All Articles