<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css" style="display:none;"><!-- P {margin-top:0;margin-bottom:0;} --></style>
</head>
<body dir="ltr">
<div id="divtagdefaultwrapper" style="font-size:12pt;color:#000000;font-family:Calibri,Helvetica,sans-serif;" dir="ltr">
<p style="margin-top:0;margin-bottom:0">Hello everyone.</p>
<p style="margin-top:0;margin-bottom:0"><br>
</p>
<p style="margin-top:0;margin-bottom:0">One last update to this already long thread:</p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><br>
</span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;">Meanwhile i implemented a majority voting approach using the <span style="font-family: Calibri, Helvetica, sans-serif; font-size: 16px;">voxelization function from the last post</span> because
i had problems voxelizing meshes with degenerated normals or polygons with wrong orientation:</span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><br>
</span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><img size="65454" contenttype="image/jpeg" id="img419579" style="user-select: none; max-width: 99.9%;" tabindex="0" width="761" height="419" data-outlook-trace="F:1|T:1" src="cid:35c9abf9-ea5c-48e4-98d5-db27ec909ccd"><br>
<br>
</span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><br>
</span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;">Since the original algorithm from the last post more ore less simply <span><span>"rasterizes" the polygon data in 3D along the z-direction, no voxelization artifacts from wrong normals result
in this direction. </span></span></span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><span><span><br>
</span></span></span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><span><span>So to get rid of any artifacts in any direction, i voxelize the mesh three times in three different directions. </span></span></span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><span><span><span style="font-family: Calibri, Helvetica, sans-serif, EmojiFont, "Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols; font-size: 16px;"><br>
</span></span></span></span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><span><span><span style="font-family: Calibri, Helvetica, sans-serif, EmojiFont, "Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols; font-size: 16px;">With
the voxelization function given in the last post</span>, i voxelize the mesh as it was given and save the result in an vtkImageData object. Then i simply rotate the original mesh 90° around the y-Axis, voxelize it again and save the result in another <span>vtkImageData
object. After that i rotate the original mesh (unrotated version) again but this time 90° around the x-Axis, voxelize it and save the result again in another vtkImageData object. </span></span></span></span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><span><span><br>
</span></span></span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><span><span>At the end i have three vtkImageData objects with results of the voxelization of the mesh in three different directions (along the x-axis, y-axis, z-axis). </span></span></span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><span><span><br>
</span></span></span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><span><span>The resulting <span style="font-family: Calibri, Helvetica, sans-serif, EmojiFont, "Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols; font-size: 16px;">vtkImageData
objects</span> are of course all rotated 90° in different directions too, so a direction comparision of the voxelization results is not possible. But by using rotations by 90° all that changes for a direct comparision is that the x, y, z components of the coordinates
of the different results simply switch (e.g. x <-> z or x <-> y). So comparisions between the results can be done without any additional computations (no rotations of the vtkImageData or so). </span></span></span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><span><span><br>
</span></span></span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><span><span>I then compare each voxelization result with another. If at least two or all three voxelization results have a voxel set in a specific cell then the final result is that this
cell is set. Otherwise it is unset.</span></span></span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><span><span><br>
</span></span></span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><span><span><br>
</span></span></span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><span><span>The result:</span></span></span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><span><span> </span></span></span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"><img size="101543" contenttype="image/jpeg" id="img810628" tabindex="0" style="max-width: 99.9%; user-select: none;" data-outlook-trace="F:1|T:1" src="cid:784b647e-ef6e-461d-a16c-17b1974642a7"><br>
<br>
</span></p>
<p style="margin-top:0;margin-bottom:0"><span style="font-size: 12pt;"> </span></p>
<br>
<br>
It is even quite fast (only around three times slower than the simple voxelization step which is clear since it does three times the work) and much faster than the raycasting approach.
<div><br>
</div>
<div><b>Btw: Does one of the filters (<span>vtkPolyDataToImageStencil, <span>vtkImageStencilToImage) </span></span>use SMP?</b></div>
<div><br>
</div>
<div>I think it could be easily exploited because of the parallel nature of it.</div>
<div><br>
</div>
<div><br>
</div>
<div>Cheers,</div>
<div><br>
</div>
<div>Berti</div>
<div><br>
</div>
<div>
<div style="color: rgb(0, 0, 0);">
<hr style="display:inline-block;width:98%" tabindex="-1">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>Von:</b> vtkusers <vtkusers-bounces@public.kitware.com> im Auftrag von Berti Krüger <berti_krueger@hotmail.com><br>
<b>Gesendet:</b> Mittwoch, 26. September 2018 07:04<br>
<b>An:</b> David Gobbi<br>
<b>Cc:</b> VTK Users<br>
<b>Betreff:</b> Re: [vtkusers] Solid Voxelization with VTK</font>
<div> </div>
</div>
<meta content="text/html; charset=iso-8859-1">
<div dir="ltr">
<div id="x_divtagdefaultwrapper" dir="ltr" style="font-size:12pt; color:#000000; font-family:Calibri,Helvetica,sans-serif">
<p style="margin-top:0; margin-bottom:0"></p>
<div style="">Hi David,</div>
<div style=""><br>
</div>
<div style="">thanks again for your help.</div>
<div style=""><br>
</div>
<div style="">I added the method calls on the normalFilter as you have suggested but it didn't change the wrong voxelization of the Eiffel tower model. </div>
<div style=""><br>
</div>
<div style="">It did indead change the result to something different:</div>
<div style=""><br>
</div>
<div style=""><img size="54477" width="222" height="227" style="height: 227.045px; width: 222px; user-select: none;" id="689891_rs|3" tabindex="0" data-outlook-trace="F:1|T:1" src="cid:ea753225-8561-4c0f-a7b0-2bb764dff664"> <img size="88782" style="width: 283px; height: 287.834px; user-select: none;" id="407170_rs|3" tabindex="0" data-outlook-trace="F:1|T:1" src="cid:a3cf6ebe-b37d-42ec-b0aa-fc502c405607">
<img size="37648" style="height: 262.703px; width: 162px; user-select: none;" id="415426_rs|3" tabindex="0" data-outlook-trace="F:1|T:1" src="cid:4439e9e1-f381-4580-8b22-005d383ff492"><br>
<br>
</div>
<div style="">
<div style="font-size:16px"><b>left image: result with wrong orientation and without <span style="font-family:Calibri,Helvetica,sans-serif,EmojiFont,"Apple Color Emoji","Segoe UI Emoji",NotoColorEmoji,"Segoe UI Symbol","Android Emoji",EmojiSymbols">normalsFilter->AutoOrientNormalsOn()</span></b></div>
<div style="font-size:16px"><b>center image: mesh with wrong orientation and <span style="font-family:Calibri,Helvetica,sans-serif,EmojiFont,"Apple Color Emoji","Segoe UI Emoji",NotoColorEmoji,"Segoe UI Symbol","Android Emoji",EmojiSymbols">normalsFilter->AutoOrientNormalsOn()</span></b></div>
<div style="font-size:16px"><b><span style="font-family:Calibri,Helvetica,sans-serif,EmojiFont,"Apple Color Emoji","Segoe UI Emoji",NotoColorEmoji,"Segoe UI Symbol","Android Emoji",EmojiSymbols"></span>right image: meshlab corrected version</b></div>
<br>
</div>
<div style=""><br>
</div>
<div style="">I attached both Eiffel tower models (with the wrong normals / polygon orientation and the corrected meshlab version) if you want to try it yourself.</div>
<div style=""><br>
</div>
<div style="">The vtkStripper is indead unecessary. I tried various meshes with and without using the vtkStripper filter step inbetween and it didn't make any difference. Since i took it from the Slicer3D source code Csaba pointed me to, i don't have any idea
why the Slicer Guys use it there. Maybe they have some special kind of polydata where it is needed. For my general purpose meshes it does not seem to make a difference. The processing is, of course, faster without this additional step.</div>
<div style=""><br>
</div>
<div style="">The complete source code for voxelization and visualization and the CMakeList.txt is attached. </div>
<div style=""><br>
</div>
<div style=""><br>
</div>
<div style="">The resulting code for the voxelization function:</div>
<div style=""><br>
</div>
<div style="">
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b>bool ConvertPolyDataToBinaryLabelMap(vtkSmartPointer<vtkPolyData> closedSurfacePolyData, </b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> vtkSmartPointer<vtkImageData> binaryLabelMap)</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b>{</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> <span style="color:rgb(0,111,201)">
<i>// Check for consistency</i></span></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> if (closedSurfacePolyData->GetNumberOfPoints() < 2 || closedSurfacePolyData->GetNumberOfCells() < 2)</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> {</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> std::cout <<
<span style="color:rgb(75,165,36)">"Convert: Cannot create binary labelmap from surface with number of points: "</span></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> << closedSurfacePolyData->GetNumberOfPoints() <<
<span style="color:rgb(75,165,36)">" and number of cells: "</span> </b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> << closedSurfacePolyData->GetNumberOfCells() << std::endl;</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> </b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> return false;</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> }</b></span></div>
<div><b><br>
</b></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b><i><span style="color:rgb(0,111,201)"> // Compute polydata normals</span></i></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b><span style="color:rgb(0,111,201)"><i> //</i></span></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b><span style="color:rgb(0,111,201)"><i> // The purpose of the vtkPolyDataNormals filter here is to enforce a</i></span></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b><span style="color:rgb(0,111,201)"><i> // consistent orientation of the polygons (via the method ConsistencyOn)</i></span></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b><span style="color:rgb(0,111,201)"><i> // and to get an automatic determination of the correct orientation of the</i></span></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b><span style="color:rgb(0,111,201)"><i> // normals on the polydata surface (via the method AutoOrientNormalsOn).</i></span></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b><span style="color:rgb(0,111,201)"><i> //</i></span></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b><span style="color:rgb(0,111,201)"><i> // To increase the performance of the filter we turn off the splitting of </i></span></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b><span style="color:rgb(0,111,201)"><i> // sharp edges (via the method SplittingOff) since it is not necessary for</i></span></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b><span style="color:rgb(0,111,201)"><i> // getting a correct result here.</i></span></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b><span style="color:rgb(0,111,201)"><i> //</i></span></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b><span style="color:rgb(0,111,201)"><i> // The application of the filter on the polydata is purely optional if all </i></span></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b><span style="color:rgb(0,111,201)"><i> // the polygons are already correctly oriented.</i></span></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> vtkNew<vtkPolyDataNormals> normalFilter;</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> normalFilter->SetInputData(closedSurfacePolyData);</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> normalFilter->ConsistencyOn();</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> normalFilter->AutoOrientNormalsOn(); </b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> normalFilter->SplittingOff();</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> </b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b><i><span style="color:rgb(0,111,201)"> // Make sure that we have a clean triangle polydata using the </span></i></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b><span style="color:rgb(0,111,201)"><i> // vtkTriangleFilter which generates triangles from input polygons.</i></span></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b><i><span style="color:rgb(0,111,201)"> // Only needed if the input polygons are not flat.</span> </i></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> vtkNew<vtkTriangleFilter> triangle;</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> triangle->SetInputConnection(normalFilter->GetOutputPort());</b></span></div>
<div><b><br>
</b></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> <span style="color:rgb(0,111,201)">
<i>// Convert polydata to stencil</i></span></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> vtkNew<vtkPolyDataToImageStencil> polyDataToImageStencil;</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> polyDataToImageStencil->SetInputConnection(triangle->GetOutputPort());</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> polyDataToImageStencil->SetOutputSpacing(binaryLabelMap->GetSpacing());</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> polyDataToImageStencil->SetOutputOrigin(binaryLabelMap->GetOrigin());</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> polyDataToImageStencil->SetOutputWholeExtent(binaryLabelMap->GetExtent());</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> polyDataToImageStencil->Update();</b></span></div>
<div><b><br>
</b></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> <i><span style="color:rgb(0,111,201)">// Convert stencil to image</span></i></b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> vtkNew<vtkImageStencilToImage> imageStencilToImage;</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> imageStencilToImage->SetInputConnection(polyDataToImageStencil->GetOutputPort());</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> imageStencilToImage->SetOutsideValue(0);</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> imageStencilToImage->SetInsideValue(1);</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> imageStencilToImage->SetOutput(binaryLabelMap);</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> imageStencilToImage->Update();</b></span></div>
<div><b><br>
</b></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b> return true;</b></span></div>
<div><span style="font-family:"Courier New",monospace; font-size:9pt"><b>}</b></span></div>
<div><br>
</div>
<br>
</div>
<div style="">Thanks again for everything.</div>
<div style=""><br>
</div>
<div style="">Cheers,</div>
<div style=""><br>
</div>
<div style="">Berti</div>
<div style=""><br>
</div>
<div style=""><br>
</div>
<div style=""><br>
</div>
<br>
<p></p>
<br>
<br>
<div style="color:rgb(0,0,0)">
<hr style="display:inline-block; width:98%" tabindex="-1">
<div id="x_divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" color="#000000" style="font-size:11pt"><b>Von:</b> David Gobbi <david.gobbi@gmail.com><br>
<b>Gesendet:</b> Dienstag, 25. September 2018 10:20<br>
<b>An:</b> Berti Krüger<br>
<b>Cc:</b> Csaba Pinter; VTK Users; Bill Lorensen<br>
<b>Betreff:</b> Re: [vtkusers] Solid Voxelization with VTK</font>
<div> </div>
</div>
<meta content="text/html; charset=utf-8">
<div>
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">Hi Berti,
<div><br>
</div>
<div>Just a few extra comments about the three "preprocessing" steps that you apply in your sample code:</div>
<div><br>
</div>
<div>For vtkPolyDataNormals, you might want to add normalsFilter->AutoOrientNormalsOn(), since this option is specifically designed to fix inside-out shapes like the Eiffel tower model. And normalsFilter->SplittingOff() will make this filter work faster.
It would also be good if the comment mentioned that the purpose of the filter is to enforce consistent orientation of the polygons, and that the filter is optional if all the polygons are already correctly oriented.</div>
<div><br>
</div>
<div>The vtkStripper should be removed, unless you actually saw that it provides some benefit. The vtkPolyDataToImageStencil class should give exactly the same results for triangles as for strips. And vtkTriangleFilter is only needed if the input polygons
are not flat.</div>
<div><br>
</div>
<div>Thanks again for the code,</div>
<div> - David</div>
<div><br>
</div>
<div><br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>