[vtkusers] Solid Voxelization with VTK

Berti Krüger berti_krueger at hotmail.com
Sun Sep 23 23:05:00 EDT 2018


Hi David,

thank you very much again for your great explanations (i looked at the vtkImageStencilData class description before writing the e-mail and as you have pointed out it is really missing some explanations on how it works internally) and of course your hints to improve the example code!

As you have written, i changed my code from

  // Convert stencil to image
  vtkNew<vtkImageStencil> stencil;
  stencil->SetInputData(binaryLabelMap);
  stencil->SetStencilConnection(polyDataToImageStencil->GetOutputPort());
  stencil->ReverseStencilOn();
  stencil->SetBackgroundValue(1); // General foreground value is 1 (background value because of reverse stencil)

  // Save result to output
  vtkNew<vtkImageCast> imageCast;
  imageCast->SetInputConnection(stencil->GetOutputPort());
  imageCast->SetOutputScalarTypeToUnsignedChar();
  imageCast->Update();
  binaryLabelMap->ShallowCopy(imageCast->GetOutput());



To:

  // Convert stencil to image
 vtkNew<vtkImageStencilToImage> imageStencilToImage;
 imageStencilToImage->SetInputConnection(polyDataToImageStencil->GetOutputPort());
 imageStencilToImage->SetOutsideValue(0);
 imageStencilToImage->SetInsideValue(1);
 imageStencilToImage->Update();

 // Save result to output
 binaryLabelMap->DeepCopy(imageStencilToImage->GetOutput());


which is really much shorter and better.


I also found out that i can change the vtkImage initialization code from

// fill the image with background voxels:
vtkIdType count = voxelImage->GetNumberOfPoints();
for (vtkIdType i = 0; i < count; ++i)
{
    voxelImage->GetPointData()->GetScalars()->SetTuple1(i, outval);
}

to simply:

voxelImage->GetPointData()->GetScalars()->Fill(outval);

I attached the improved version and the CMakeLists file.


So far it works really great and is quite fast:

[cid:c6c7244e-ff20-474f-a694-4c683d98b856]



But one thing is that i still get problems with some kind of meshes (i guess meshes which are not closed or watertight):


Alien Queen (minor problems):
[cid:23b830f9-073a-45d1-bad1-dddd550e2d69]

[cid:745f1387-542f-4562-8455-7e8b13d7ba62]



Eiffel Tower (completely wrong):

[cid:6c47ec8d-40cf-4b31-8183-62ff2a26a205][cid:b5391948-c2d3-4f6f-a54e-acd497194c10]



Maybe this could be solved by rasterizing the mesh in different directions and doing some kind of majority voting if a voxel is set or not.

I solved these cases by implementing a raycasting solution using a generalization of the point in polygon algorithm and

  // load STL file
  vtkNew<vtkSTLReader> reader;
  reader->SetFileName("eiffel_tower_small.stl");
  reader->Update();

  vtkNew<vtkPolyData> pd;
  pd->DeepCopy(reader->GetOutput());

  // compute bounds for stl mesh polydata
  double bounds[6];
  pd->GetBounds(bounds);

/*
 // Create the locator (obb tree)
  vtkNew<vtkOBBTree> obbTree;
  tree->SetDataSet(pd);
  tree->BuildLocator();
*/

  // Create the locator (modified bsp tree)
  vtkNew<vtkModifiedBSPTree> bspTree;
  bspTree->SetDataSet(pd);
  bspTree->BuildLocator();

  constexpr int numSamples = 32;


  //#pragma omp parallel for // not for vtkModifiedBSPTree !!
  for(int x = 0; x < imageResolutionX; x++)
  {
    for(int y = 0; y < imageResolutionY; y++)
    {
        for(int z = 0; z < imageResolutionZ; z++)
        {
    // pick an arbitrary sampling direction
    vtkVector3f ray_direction(0.0, 0.0, 0.0);
    vtkVector3f ray_direction2(0.0, 0.0, 0.0);

            // find world space position of the voxel
            constexpr int X_MIN = 0;
            constexpr int Y_MIN = 2;
            constexpr int Z_MIN = 4;

            vtkVector3f ray_origin( bounds[X_MIN] + spacing[0] * x,
                                    bounds[Y_MIN] + spacing[1] * y,
                                    bounds[Z_MIN] + spacing[2] * z);


    // randomly sample 3D space by sending rays in randomized directions
            unsigned int numIntersections = 0;

            int id = 0;

    for (int j = 0; j < numSamples; ++j)
    {
    // compute the random direction. Convert from polar to
          // euclidean to get an even distribution
               float theta = 2 * M_PI * random(genenerator);
               float phi = acos(1 - 2 * random(generator));

               ray_direction[0] = sin(phi) * cos(theta);
               ray_direction[1] = sin(phi) * sin(theta);
               ray_direction[2] = cos(phi);


            // check if the voxel is inside of the mesh.
            vtkNew<vtkPoints> intersectPoints;

               double lineP0[3] = {ray_origin[0], ray_origin[1], ray_origin[2]};

               double lineP1[3] = {ray_origin[0] + ray_direction[0] * 10000.0,
                                   ray_origin[1] + ray_direction[1] * 10000.0,
                                   ray_origin[2] + ray_direction[2] * 10000.0};


               //obbTree->IntersectWithLine(lineP0, lineP1, intersectPoints, NULL);

               bspTree->IntersectWithLine(lineP0, lineP1, 0.0001, intersectPoints, NULL);

               if (intersectPoints->GetNumberOfPoints() % 2 == 1)
                   numIntersections++;
    }

              // save answer
            unsigned int index = x + y * imageResolutionX
                                   + z * imageResolutionX * imageResolutionY;


            float hitPercentage = static_cast<float>(numIntersections) / static_cast<float>(numSamples);

if(hitPercentage >= 0.5)
                voxelImage[index] = inval;
    else
        voxelImage[index] = outval;
}
}
  }




________________________________
Von: David Gobbi <david.gobbi at gmail.com>
Gesendet: Sonntag, 23. September 2018 16:15
An: Berti Krüger
Cc: Csaba Pinter; VTK Users
Betreff: Re: [vtkusers] Solid Voxelization with VTK

Hi Berti,

Thanks for the code, I'm sure that people will find it useful.  The vtkImageStencilData class isn't described in much detail in the VTK documentation, but I can provide a brief description.

The vtkImageStencilData object stores each raster-line of a binary image as a list of (begin, end) pairs.  That is, each raster line has zero or more non-overlapping (begin, end) pairs.  When vtkImageStencil operates on an image, it simply iterates through the (begin, end) pairs to figure out what parts of the image to copy.  One way to think about this is that if the original binary image volume is stored as O(n^3) voxels, the vtkImageStencilData stores O(n^2) values.

When a vtkImageStencilData is created, it allocates enough memory to store one (begin, end) pair per raster line, since this matches the most common use case (i.e. a mask that corresponds to a convex object). Thereafter it performs additional allocations as necessary.

As for vtkPolyDataToImageStencil, it works by cutting your STL object along each XY plane to create polygons (zero or more polygons per slice), and then it rasterizes each polygon to create the (begin, end) pairs for each raster line.


One comment about your code: it would be more efficient to use vtkImageStencilToImage instead of vtkImageStencil and vtkImageCast.  The vtkImageStencilToImage filter requires only one input (the stencil), i.e. it doesn't require 'binaryLabelMap' as input.  Also, you can set the data type of the image that it produces as output, so it doesn't have to be followed by a cast.

Cheers,
 - David

On Sat, Sep 22, 2018 at 10:29 PM Berti Krüger <berti_krueger at hotmail.com<mailto:berti_krueger at hotmail.com>> wrote:

Hi all.


I am very sorry to revive this ancient thread.


But i thought that maybe it could help other vtk users in the future to have a compilable and working example of the final result. If someone thinks that this code could be useful as an vtk example then feel free to modify / correct / pimp / add this to the vtk examples on github.


I adapted the 3D slicer vtk code Csaba has pointed me to and incorporated the hints from David and everything works like a charm:


[cid:795e083b-ffaa-4d6b-8b3f-97deb637b01c]


The whole procedure is incredibly simple. Basically the vtkPolyData of the mesh is converted via the vtkPolyDataToImageStencil filter to a vtkImageStencil and the rest of the whole magic is only done by the vtkImageStencil filter:


// Convert stencil to image
vtkNew<vtkImageStencil> stencil;
stencil->SetInputData(binaryLabelMap);
stencil->SetStencilConnection(polyDataToImageStencil->GetOutputPort());
stencil->ReverseStencilOn();
stencil->SetBackgroundValue(1); // General foreground value is 1 (background value because of reverse stencil)

I would really like to know very roughly how the vtkImageStencil works internally without digging through all of the source code. Because it is really fast (some kind of rasterization maybe ?). If someone could drop me a line on how it works only in principle  that would be really great.


So thanks again to Bill, Csaba, David, Elvis and everyone else on this thread.



Kind regards,


Berti



PS: Example code, CMakeLists and example STL mesh are attached

________________________________
Von: Csaba Pinter <csaba.pinter at queensu.ca<mailto:csaba.pinter at queensu.ca>>
Gesendet: Montag, 11. Juni 2018 12:45
An: Berti Krüger
Cc: vtkusers at vtk.org<mailto:vtkusers at vtk.org>
Betreff: RE: [vtkusers] Solid Voxelization with VTK


Hi Berti,



That code is under BSD-style license, so you’re free to do basically anything with it. This implementation is already pretty simple; just a concatenation of several VTK filters, so you can just give it a try by copy-pasting the relevant part of that function into your code and see if it works. If you’re interested in using the vtkSegmentation library, let me know though!



Best,

csaba



From: Berti Krüger <berti_krueger at hotmail.com<mailto:berti_krueger at hotmail.com>>
Sent: Monday, June 11, 2018 02:46
To: Csaba Pinter <csaba.pinter at queensu.ca<mailto:csaba.pinter at queensu.ca>>; David Gobbi <david.gobbi at gmail.com<mailto:david.gobbi at gmail.com>>
Cc: vtkusers at vtk.org<mailto:vtkusers at vtk.org>
Subject: Re: [vtkusers] Solid Voxelization with VTK



Hi Csaba,



thank you very much for you answer and for offering your help.



I already have looked at it and i think if no simpler option will come up, i will give it a try (hoping not to have to change too much to get it working with my pipeline since i am an absolute vtk beginner :-) ).



How is this code licensed ? (i am only doing research work at the moment, the whole project i am working on is internal and just for testing and part of some larger work, it might be open sourced one day in the very far future but could even be not at all  and it will never be used commercially).





Regards



Berti





Am 05.06.2018 um 16:14 schrieb Csaba Pinter:

Hi Berti,



There is a pretty robust conversion algorithm implemented within 3D Slicer but using solely VTK:

https://github.com/Slicer/Slicer/blob/master/Libs/vtkSegmentationCore/vtkClosedSurfaceToBinaryLabelmapConversionRule.cxx#L118<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2FSlicer%2FSlicer%2Fblob%2Fmaster%2FLibs%2FvtkSegmentationCore%2FvtkClosedSurfaceToBinaryLabelmapConversionRule.cxx%23L118&data=02%7C01%7Ccsaba.pinter%40queensu.ca%7C3aab37ccc6914427982508d5cf66eedc%7Cd61ecb3b38b142d582c4efb2838b925c%7C1%7C1%7C636642963366161717&sdata=p0ekXyWC0VAuADrfhvReHFywfi8%2BD7jhe59iVCIZmqs%3D&reserved=0>

It consists of a short pipeline of standard VTK filters (some preprocessing then vtkPolyDataToImageStencil and vtkImageStencil).



Let me know if you have any questions.



csaba





From: vtkusers <vtkusers-bounces at public.kitware.com><mailto:vtkusers-bounces at public.kitware.com> On Behalf Of Berti Krüger
Sent: Tuesday, June 5, 2018 03:26
To: David Gobbi <david.gobbi at gmail.com><mailto:david.gobbi at gmail.com>
Cc: vtkusers at vtk.org<mailto:vtkusers at vtk.org>
Subject: Re: [vtkusers] Solid Voxelization with VTK



Hi David,



thank you very much for your help.



I tried the example from your link. Unfortunately the result is same as using the vtkVoxelModeller:



[Screenshot result voxelization]
I get only a voxelization of the surface. The interior of the voxelized cone is still hollow and not filled with voxels (at least this is implied by the visualization).



For the visualization i use Bill Lorensen's example code from here:

https://lorensen.github.io/VTKExamples/site/Cxx/Medical/GenerateCubesFromLabels/<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Florensen.github.io%2FVTKExamples%2Fsite%2FCxx%2FMedical%2FGenerateCubesFromLabels%2F&data=02%7C01%7Ccsaba.pinter%40queensu.ca%7C63496d6b50e24ff32f7808d5cab5a98b%7Cd61ecb3b38b142d582c4efb2838b925c%7C1%7C1%7C636637804016225671&sdata=4TKi7VbGBfbM4DpQuLib1m0YGmLJO%2FU7BAO6ZKCUpVU%3D&reserved=0>





I have attached this small example which compiles with VTK 8.1 to show the issue. It basicly only consist of the example code from your link (https://lorensen.github.io/VTKExamples/site/Cxx/PolyData/PolyDataToImageData/<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Florensen.github.io%2FVTKExamples%2Fsite%2FCxx%2FPolyData%2FPolyDataToImageData%2F&data=02%7C01%7Ccsaba.pinter%40queensu.ca%7C63496d6b50e24ff32f7808d5cab5a98b%7Cd61ecb3b38b142d582c4efb2838b925c%7C1%7C1%7C636637804016225671&sdata=hXqgnekqjjNPflRneU0sU7DFo%2B%2FcdBfIFDcpE%2FZXiOg%3D&reserved=0>) and the visualization code from the  Bill Lorensen's example from the link above. I have not changed much.



Any idea what is going wrong or what can i do get also voxelization of the interior (solid voxelization)?



Thank you very much in advance.





Regards



Berti



PolyDataToImageData - lorensen.github.io<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Florensen.github.io%2FVTKExamples%2Fsite%2FCxx%2FPolyData%2FPolyDataToImageData%2F&data=02%7C01%7Ccsaba.pinter%40queensu.ca%7C63496d6b50e24ff32f7808d5cab5a98b%7Cd61ecb3b38b142d582c4efb2838b925c%7C1%7C1%7C636637804016225671&sdata=hXqgnekqjjNPflRneU0sU7DFo%2B%2FcdBfIFDcpE%2FZXiOg%3D&reserved=0>

lorensen.github.io<http://lorensen.github.io>

If VTK is not installed but compiled on your system, you will need to specify the path to your VTK build:






GenerateCubesFromLabels - GitHub Pages<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Florensen.github.io%2FVTKExamples%2Fsite%2FCxx%2FMedical%2FGenerateCubesFromLabels%2F&data=02%7C01%7Ccsaba.pinter%40queensu.ca%7C63496d6b50e24ff32f7808d5cab5a98b%7Cd61ecb3b38b142d582c4efb2838b925c%7C1%7C1%7C636637804016225671&sdata=4TKi7VbGBfbM4DpQuLib1m0YGmLJO%2FU7BAO6ZKCUpVU%3D&reserved=0>

lorensen.github.io<http://lorensen.github.io>

Usage: GenerateCubesFromLabels FullHead.mhd StartLabel EndLabel where InputVolume is a meta file containing a 3 volume of discrete labels.






________________________________

Von: David Gobbi <david.gobbi at gmail.com<mailto:david.gobbi at gmail.com>>
Gesendet: Montag, 28. Mai 2018 23:13
An: Berti Krüger
Cc: vtkusers at vtk.org<mailto:vtkusers at vtk.org>
Betreff: Re: [vtkusers] Solid Voxelization with VTK



Hi Berti,



If its a triangulated surface that you want to fill with voxels, use vtkPolyDataToImageStencil:

https://lorensen.github.io/VTKExamples/site/Cxx/PolyData/PolyDataToImageData/<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Florensen.github.io%2FVTKExamples%2Fsite%2FCxx%2FPolyData%2FPolyDataToImageData%2F&data=02%7C01%7Ccsaba.pinter%40queensu.ca%7C63496d6b50e24ff32f7808d5cab5a98b%7Cd61ecb3b38b142d582c4efb2838b925c%7C1%7C1%7C636637804016225671&sdata=hXqgnekqjjNPflRneU0sU7DFo%2B%2FcdBfIFDcpE%2FZXiOg%3D&reserved=0>

PolyDataToImageData - lorensen.github.io<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Florensen.github.io%2FVTKExamples%2Fsite%2FCxx%2FPolyData%2FPolyDataToImageData%2F&data=02%7C01%7Ccsaba.pinter%40queensu.ca%7C63496d6b50e24ff32f7808d5cab5a98b%7Cd61ecb3b38b142d582c4efb2838b925c%7C1%7C1%7C636637804016225671&sdata=hXqgnekqjjNPflRneU0sU7DFo%2B%2FcdBfIFDcpE%2FZXiOg%3D&reserved=0>

lorensen.github.io<http://lorensen.github.io>

If VTK is not installed but compiled on your system, you will need to specify the path to your VTK build:






If its a mesh of 3D elements and you want to sample the elements to create voxels, try vtkResampleToImage.



 - David







On Mon, May 28, 2018 at 4:41 PM, Berti Krüger <berti_krueger at hotmail.com<mailto:berti_krueger at hotmail.com>> wrote:

Hello Everyone.

For my Project i have to voxelize a 3D-Triangle-Mesh. I already found the
vtkVoxelModeller which, while somewhat slow (only around 200 Triangles per
second), works, but only voxelizes the outer shell where the mesh boundary
triangles are. The inner part of the mesh stays hollow.

Is there some way to get solid voxelization of 3D-Triangle-Meshes out of the
box with VTK ?


Thank you very much in advance,

Berti


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://public.kitware.com/pipermail/vtkusers/attachments/20180924/0877d986/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: eiffel_tower_small.jpg
Type: image/jpeg
Size: 39385 bytes
Desc: eiffel_tower_small.jpg
URL: <https://public.kitware.com/pipermail/vtkusers/attachments/20180924/0877d986/attachment-0005.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: eiffel_tower_small_voxelization.jpg
Type: image/jpeg
Size: 36468 bytes
Desc: eiffel_tower_small_voxelization.jpg
URL: <https://public.kitware.com/pipermail/vtkusers/attachments/20180924/0877d986/attachment-0006.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: alienqueen.jpg
Type: image/jpeg
Size: 86457 bytes
Desc: alienqueen.jpg
URL: <https://public.kitware.com/pipermail/vtkusers/attachments/20180924/0877d986/attachment-0007.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: alienqueen_voxelization.jpg
Type: image/jpeg
Size: 65454 bytes
Desc: alienqueen_voxelization.jpg
URL: <https://public.kitware.com/pipermail/vtkusers/attachments/20180924/0877d986/attachment-0008.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: tentacle.jpg
Type: image/jpeg
Size: 67748 bytes
Desc: tentacle.jpg
URL: <https://public.kitware.com/pipermail/vtkusers/attachments/20180924/0877d986/attachment-0009.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: PolyDataToImageDataVisualizationSTL.cxx
Type: text/x-c++src
Size: 7981 bytes
Desc: PolyDataToImageDataVisualizationSTL.cxx
URL: <https://public.kitware.com/pipermail/vtkusers/attachments/20180924/0877d986/attachment-0001.cxx>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: CMakeLists.txt
URL: <https://public.kitware.com/pipermail/vtkusers/attachments/20180924/0877d986/attachment-0001.txt>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: eiffel_tower_small.stl
Type: application/sla
Size: 759184 bytes
Desc: eiffel_tower_small.stl
URL: <https://public.kitware.com/pipermail/vtkusers/attachments/20180924/0877d986/attachment-0001.stl>


More information about the vtkusers mailing list