3

I am using vtk library with C++ to generate and visualize some synthetic voxel data with given color and transparency mapping. An example is shown below: Sample Image

As shown in the figure, the data is 3D in general, and it works great. However, in specific cases when the data becomes 2D, the visualization windows shows nothing.

I am posting few lines of my code which may 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());

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

EDIT: I am adding an equivalent code, which 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 leads to an output like below (for, X1=X2=X3=10) enter image description here

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

EDIT:

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

  • So your data doesn't really become 2D, it is just one single layer of voxels? Have you checked whether the number of cells of your single-layer image data is what you expect? Maybe there is some sort of numbering issue, but that's difficult to say without seeing more of your code. – mululu Jul 28 '17 at 09:58
  • Yes, it is just one single layer of voxels. I have checked the number of cells in single-layer image data, it is as expected. I will post bare minimum equivalent code soon. – Harsh Kumar Narula Jul 28 '17 at 10:21

1 Answers1

2

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

#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 dimensions (10 as per the code above), are correctly seen

enter image description here