Hi Tim,<br><br>I was wondering .<br>since you used vtkRearrangeFields to move the point data to cell data , will you get a similar result if you directly use vtkPointDataToCellData to move attributes ?<br><br>Regards<br>Darshan<br>
<br><div class="gmail_quote">On Fri, Jun 8, 2012 at 6:29 PM, Tim Hutton <span dir="ltr"><<a href="mailto:tim.hutton@gmail.com" target="_blank">tim.hutton@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I've finally found a way to achieve Minecraft-style voxel rendering in<br>
a VTK pipeline. The hard bit is moving the image point data to cell<br>
data. One trick is that vtkMergeFilter won't pass data through unless<br>
the target geometry is the right size, so use vtkRearrangeFields<br>
first. Another trick is that vtkMergeFilter only passes through the<br>
active attributes, so use vtkAssignAttribute to set them.<br>
<br>
I'm not sure if it wouldn't be better if vtkMergeFilter was less strict?<br>
<br>
Here's the code, for the long tail:<br>
<div class="im"><br>
vtkSmartPointer<vtkImageWrapPad> pad = vtkSmartPointer<vtkImageWrapPad>::New();<br>
pad->SetInput(image);<br>
pad->SetOutputWholeExtent(extent[0],extent[1]+1,extent[2],extent[3]+1,extent[4],extent[5]+1);<br>
<br>
</div>// move the pixel values (stored in the point data) to cell data<br>
vtkSmartPointer<vtkRearrangeFields> prearrange_fields =<br>
vtkSmartPointer<vtkRearrangeFields>::New();<br>
prearrange_fields->SetInput(image);<br>
prearrange_fields->AddOperation(vtkRearrangeFields::MOVE,vtkDataSetAttributes::SCALARS,<br>
vtkRearrangeFields::POINT_DATA,vtkRearrangeFields::CELL_DATA);<br>
<br>
// mark the new cell data array as the active attribute<br>
vtkSmartPointer<vtkAssignAttribute> assign_attribute =<br>
vtkSmartPointer<vtkAssignAttribute>::New();<br>
assign_attribute->SetInputConnection(prearrange_fields->GetOutputPort());<br>
assign_attribute->Assign("ImageScalars",<br>
vtkDataSetAttributes::SCALARS, vtkAssignAttribute::CELL_DATA);<br>
<br>
vtkSmartPointer<vtkMergeFilter> merge_datasets =<br>
vtkSmartPointer<vtkMergeFilter>::New();<br>
merge_datasets->SetGeometryConnection(pad->GetOutputPort());<br>
merge_datasets->SetScalarsConnection(assign_attribute->GetOutputPort());<br>
<br>
vtkSmartPointer<vtkThreshold> threshold = vtkSmartPointer<vtkThreshold>::New();<br>
threshold->SetInputConnection(merge_datasets->GetOutputPort());<br>
threshold->SetInputArrayToProcess(0, 0, 0,<br>
vtkDataObject::FIELD_ASSOCIATION_CELLS,<br>
vtkDataSetAttributes::SCALARS);<br>
threshold->ThresholdByUpper(contour_level);<br>
<div class="im"><br>
vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();<br>
transform->Translate (-.5, -.5, -.5);<br>
vtkSmartPointer<vtkTransformFilter> transformModel =<br>
vtkSmartPointer<vtkTransformFilter>::New();<br>
transformModel->SetTransform(transform);<br>
</div>transformModel->SetInputConnection(threshold->GetOutputPort());<br>
<div class="im"><br>
vtkSmartPointer<vtkGeometryFilter> geometry =<br>
vtkSmartPointer<vtkGeometryFilter>::New();<br>
geometry->SetInputConnection(transformModel->GetOutputPort());<br>
</div>mapper->SetInputConnection(geometry->GetOutputPort());<br>
<div class="HOEnZb"><div class="h5"><br>
<br>
On 2 April 2012 11:22, Tim Hutton <<a href="mailto:tim.hutton@gmail.com">tim.hutton@gmail.com</a>> wrote:<br>
> A follow-up question: Is there a way to do this as a VTK pipeline? At<br>
> the moment it needs a manual call to pad->Update() and<br>
> pad->GetOutput()->GetCellData()->SetScalars(image->GetPointData()->GetScalars())<br>
> every time the image changes (full code below). This is a problem for<br>
> my application where I've been keeping the rendering pipeline separate<br>
> from the image-updating code, and where the user can choose how the<br>
> pipeline is set up.<br>
><br>
> // Adapted from GenerateCubesFromLabels.cxx (can use the same CMakeLists.txt)<br>
> #include <vtkImageWrapPad.h><br>
> #include <vtkThreshold.h><br>
> #include <vtkTransformFilter.h><br>
> #include <vtkGeometryFilter.h><br>
> #include <vtkSmartPointer.h><br>
> #include <vtkTransform.h><br>
> #include <vtkImageData.h><br>
> #include <vtkPointData.h><br>
> #include <vtkCellData.h><br>
> #include <vtkRenderer.h><br>
> #include <vtkRenderWindow.h><br>
> #include <vtkRenderWindowInteractor.h><br>
> #include <vtkPolyDataMapper.h><br>
><br>
> int* vtk_at(int* origin,int x,int y,int z,int X,int Y)<br>
> {<br>
> // single-component vtkImageData scalars are stored as:<br>
> int,int,... for consecutive x, then y, then z<br>
> return origin + x + X*(y + Y*z);<br>
> }<br>
><br>
> int main ()<br>
> {<br>
> const int X=30,Y=25,Z=20;<br>
> vtkSmartPointer<vtkImageData> image = vtkSmartPointer<vtkImageData>::New();<br>
> image->SetExtent(0,X-1,0,Y-1,0,Z-1);<br>
> image->SetScalarTypeToInt();<br>
> image->SetNumberOfScalarComponents(1);<br>
> image->AllocateScalars();<br>
><br>
> int* image_data = static_cast<int*>(image->GetScalarPointer());<br>
><br>
> // add 4 cubes in a simple pattern<br>
> for(int i=0;i<X*Y*Z;i++) image_data[i] = 0; // (clear the image)<br>
> *vtk_at(image_data,10,10,10,X,Y) = 1;<br>
> *vtk_at(image_data,15,10,10,X,Y) = 1;<br>
> *vtk_at(image_data,10,15,10,X,Y) = 1;<br>
> *vtk_at(image_data,10,10,15,X,Y) = 1;<br>
><br>
> // Pad the volume so that we can change the point data into cell data.<br>
> int *extent = image->GetExtent();<br>
> vtkSmartPointer<vtkImageWrapPad> pad =<br>
> vtkSmartPointer<vtkImageWrapPad>::New();<br>
> pad->SetInput(image);<br>
> pad->SetOutputWholeExtent(extent[0], extent[1] + 1,<br>
> extent[2], extent[3] + 1,<br>
> extent[4], extent[5] + 1);<br>
> pad->Update();<br>
><br>
> // Copy the scalar point data of the volume into the scalar cell data<br>
> pad->GetOutput()->GetCellData()->SetScalars(image->GetPointData()->GetScalars());<br>
><br>
> vtkSmartPointer<vtkThreshold> selector =<br>
> vtkSmartPointer<vtkThreshold>::New();<br>
> selector->SetInputArrayToProcess(0, 0, 0,<br>
> vtkDataObject::FIELD_ASSOCIATION_CELLS,<br>
> vtkDataSetAttributes::SCALARS);<br>
> selector->SetInputConnection(pad->GetOutputPort());<br>
> selector->ThresholdByUpper(0.5);<br>
> selector->Update();<br>
><br>
> // Shift the geometry by 1/2<br>
> vtkSmartPointer<vtkTransform> transform =<br>
> vtkSmartPointer<vtkTransform>::New();<br>
> transform->Translate (-.5, -.5, -.5);<br>
><br>
> vtkSmartPointer<vtkTransformFilter> transformModel =<br>
> vtkSmartPointer<vtkTransformFilter>::New();<br>
> transformModel->SetTransform(transform);<br>
> transformModel->SetInputConnection(selector->GetOutputPort());<br>
><br>
> vtkSmartPointer<vtkGeometryFilter> geometry =<br>
> vtkSmartPointer<vtkGeometryFilter>::New();<br>
> geometry->SetInputConnection(transformModel->GetOutputPort());<br>
><br>
> vtkSmartPointer<vtkPolyDataMapper> mapper =<br>
> vtkSmartPointer<vtkPolyDataMapper>::New();<br>
> mapper->SetInputConnection(geometry->GetOutputPort());<br>
> mapper->ScalarVisibilityOff();<br>
><br>
> vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();<br>
> actor->SetMapper(mapper);<br>
><br>
> vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();<br>
> vtkSmartPointer<vtkRenderWindow> renderWindow =<br>
> vtkSmartPointer<vtkRenderWindow>::New();<br>
> renderWindow->AddRenderer(renderer);<br>
> vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor<br>
> = vtkSmartPointer<vtkRenderWindowInteractor>::New();<br>
> renderWindowInteractor->SetRenderWindow(renderWindow);<br>
><br>
> renderer->AddActor(actor);<br>
> renderer->SetBackground(.1, .2, .3);<br>
><br>
> renderWindow->Render();<br>
> renderWindowInteractor->Start(); // we'll start the animation<br>
> after the user hits 'q'<br>
><br>
> // test whether we can change the underlying image and just update<br>
> the pipeline<br>
> for(int iFrame=0;iFrame<X;iFrame++)<br>
> {<br>
> // add 4 cubes in a simple pattern that moves each frame<br>
> for(int i=0;i<X*Y*Z;i++) image_data[i] = 0; // (clear the image)<br>
> *vtk_at(image_data,(10+iFrame)%X,10,10,X,Y) = 1;<br>
> *vtk_at(image_data,(15+iFrame)%X,10,10,X,Y) = 1;<br>
> *vtk_at(image_data,(10+iFrame)%X,15,10,X,Y) = 1;<br>
> *vtk_at(image_data,(10+iFrame)%X,10,15,X,Y) = 1;<br>
> image->Modified();<br>
><br>
> // PROBLEM: need these two lines else the pipeline doesn't work<br>
> pad->Update();<br>
> pad->GetOutput()->GetCellData()->SetScalars(image->GetPointData()->GetScalars());<br>
><br>
> renderer->ResetCameraClippingRange();<br>
> renderWindow->Render();<br>
> }<br>
><br>
> renderWindowInteractor->Start();<br>
> return EXIT_SUCCESS;<br>
> }<br>
><br>
> On 29 March 2012 18:03, Tim Hutton <<a href="mailto:tim.hutton@gmail.com">tim.hutton@gmail.com</a>> wrote:<br>
>> Thanks Bill,<br>
>><br>
>> Yes, vtkImageData -> vtkThreshold -> vtkGeometryFilter was what I was<br>
>> looking for.<br>
>><br>
>> On 29 March 2012 17:15, Bill Lorensen <<a href="mailto:bill.lorensen@gmail.com">bill.lorensen@gmail.com</a>> wrote:<br>
>>> Tim,<br>
>>><br>
>>> Take a look at this example:<br>
>>> <a href="http://www.vtk.org/Wiki/VTK/Examples/Cxx/Medical/GenerateCubesFromLabels" target="_blank">http://www.vtk.org/Wiki/VTK/Examples/Cxx/Medical/GenerateCubesFromLabels</a><br>
>>><br>
>>> The output of transformModel may be what you want.<br>
>>><br>
>>> Bill<br>
>>><br>
>>> On Thu, Mar 29, 2012 at 8:40 AM, Tim Hutton <<a href="mailto:tim.hutton@gmail.com">tim.hutton@gmail.com</a>> wrote:<br>
>>>> Hello,<br>
>>>><br>
>>>> I've got a 3d images (vtkImageData) containing values 0 and 1. I'd<br>
>>>> like to render this as blocky voxels - rendered with cubes like in<br>
>>>> Minecraft.<br>
>>>><br>
>>>> I've tried vtkContourFilter and vtkDiscreteMarchingCubes but these<br>
>>>> both show angled surfaces - e.g. an octahedron for an isolated voxel.<br>
>>>><br>
>>>> I tried vtkGeometryFilter but this just gives me the outer surface of<br>
>>>> the volume. And vtkImageThreshold just changes the pixel values.<br>
>>>><br>
>>>> I tried vtkImageDataGeometryFilter but this doesn't seem to support<br>
>>>> thresholding in 3D?<br>
>>>><br>
>>>> Thanks for your help,<br>
>>>><br>
>>>> Tim<br>
>>>><br>
>>>> --<br>
>>>> Tim Hutton - <a href="http://www.sq3.org.uk" target="_blank">http://www.sq3.org.uk</a> - <a href="http://profiles.google.com/tim.hutton/" target="_blank">http://profiles.google.com/tim.hutton/</a><br>
>>>> _______________________________________________<br>
>>>> Powered by <a href="http://www.kitware.com" target="_blank">www.kitware.com</a><br>
>>>><br>
>>>> Visit other Kitware open-source projects at <a href="http://www.kitware.com/opensource/opensource.html" target="_blank">http://www.kitware.com/opensource/opensource.html</a><br>
>>>><br>
>>>> Please keep messages on-topic and check the VTK FAQ at: <a href="http://www.vtk.org/Wiki/VTK_FAQ" target="_blank">http://www.vtk.org/Wiki/VTK_FAQ</a><br>
>>>><br>
>>>> Follow this link to subscribe/unsubscribe:<br>
>>>> <a href="http://www.vtk.org/mailman/listinfo/vtkusers" target="_blank">http://www.vtk.org/mailman/listinfo/vtkusers</a><br>
>>><br>
>>><br>
>>><br>
>>> --<br>
>>> Unpaid intern in BillsBasement at noware dot com<br>
>><br>
>><br>
>><br>
>> --<br>
>> Tim Hutton - <a href="http://www.sq3.org.uk" target="_blank">http://www.sq3.org.uk</a> - <a href="http://profiles.google.com/tim.hutton/" target="_blank">http://profiles.google.com/tim.hutton/</a><br>
><br>
><br>
><br>
> --<br>
> Tim Hutton - <a href="http://www.sq3.org.uk" target="_blank">http://www.sq3.org.uk</a> - <a href="http://profiles.google.com/tim.hutton/" target="_blank">http://profiles.google.com/tim.hutton/</a><br>
<br>
<br>
<br>
--<br>
Tim Hutton - <a href="http://www.sq3.org.uk" target="_blank">http://www.sq3.org.uk</a> - <a href="http://profiles.google.com/tim.hutton/" target="_blank">http://profiles.google.com/tim.hutton/</a><br>
_______________________________________________<br>
Powered by <a href="http://www.kitware.com" target="_blank">www.kitware.com</a><br>
<br>
Visit other Kitware open-source projects at <a href="http://www.kitware.com/opensource/opensource.html" target="_blank">http://www.kitware.com/opensource/opensource.html</a><br>
<br>
Please keep messages on-topic and check the VTK FAQ at: <a href="http://www.vtk.org/Wiki/VTK_FAQ" target="_blank">http://www.vtk.org/Wiki/VTK_FAQ</a><br>
<br>
Follow this link to subscribe/unsubscribe:<br>
<a href="http://www.vtk.org/mailman/listinfo/vtkusers" target="_blank">http://www.vtk.org/mailman/listinfo/vtkusers</a><br>
</div></div></blockquote></div><br>