[vtkusers] Placing volumes exactly adjacent to each other

Elvis Stansvik elvis.stansvik at orexplore.com
Sun Sep 11 10:48:07 EDT 2016


2016-09-11 16:17 GMT+02:00 Elvis Stansvik <elvis.stansvik at orexplore.com>:

> 2016-09-09 11:08 GMT+02:00 Elvis Stansvik <elvis.stansvik at orexplore.com>:
>
>> 2016-09-09 11:04 GMT+02:00 Elvis Stansvik <elvis.stansvik at orexplore.com>:
>>
>>> Hi all,
>>>
>>> I have a hopefully simple question:
>>>
>>> Since the bounds of a vtkImageData start and end in the center of the
>>> corner voxels, if I want to place two volumes in the world adjacent (right
>>> next to eachother) using SetPosition, will I have to compensate for this,
>>> to avoid the volumes overlapping by 0.5*spacing_of_first_volume +
>>> 0.5*spacing_of_second_volume ?
>>>
>>
>> I guess this is really two questions:
>>
>> 1) Is the (visual, in world) size of a volume in the first dimension
>> (extent[1] - extent[0]) * spacing[2] or (extent[1] - extent[0] + 1) *
>> spacing[2].
>> 2) Will SetPosition move the volume such that the center of the corner
>> voxel is at the given world position?
>>
>
> Okay, I made the following small test program:
>
> #include <iostream>
>
> #include <vtkColorTransferFunction.h>
> #include <vtkGPUVolumeRayCastMapper.h>
> #include <vtkPiecewiseFunction.h>
> #include <vtkRenderer.h>
> #include <vtkRenderWindow.h>
> #include <vtkRenderWindowInteractor.h>
> #include <vtkSmartPointer.h>
> #include <vtkVolume.h>
> #include <vtkVolumeProperty.h>
> #include <vtkXMLImageDataReader.h>
> #include <vtkCubeAxesActor.h>
> #include <vtkTextProperty.h>
>
> int main(int argc, char* argv[])
> {
>   if (argc != 2) {
>     std::cerr << "Usage: " << argv[0] << "<file>" << std::endl;
>     return 1;
>   }
>
>   auto reader = vtkSmartPointer<vtkXMLImageDataReader>::New();
>   reader->SetFileName(argv[1]);
>   reader->Update();
>
>   auto mapper = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
>   mapper->SetInputConnection(reader->GetOutputPort());
>
>   auto color = vtkSmartPointer<vtkColorTransferFunction>::New();
>   color->AddRGBPoint(0.0, 0.0, 0.0, 1.0); // blue
>   color->AddRGBPoint(1.0, 0.0, 0.0, 1.0); // blue
>
>   auto opacity = vtkSmartPointer<vtkPiecewiseFunction>::New();
>   opacity->AddPoint(0.0, 0.4);
>   opacity->AddPoint(1.0, 0.4);
>
>   auto property = vtkSmartPointer<vtkVolumeProperty>::New();
>   property->SetColor(color);
>   property->SetScalarOpacity(opacity);
>
>   auto volume = vtkSmartPointer<vtkVolume>::New();
>   volume->SetMapper(mapper);
>   volume->SetProperty(property);
>   volume->SetPosition(0, 0, 0);
>
>   auto renderer = vtkSmartPointer<vtkRenderer>::New();
>   renderer->AddVolume(volume);
>
>   // Cube axes actor
>   auto cubeAxesActor = vtkSmartPointer<vtkCubeAxesActor>::New();
>   cubeAxesActor->SetBounds(0, 4, 0, 4, 0, 4);
>   cubeAxesActor->SetCamera(renderer->GetActiveCamera());
>   cubeAxesActor->GetTitleTextProperty(0)->SetColor(1.0, 0.0, 0.0);
>   cubeAxesActor->GetLabelTextProperty(0)->SetColor(1.0, 0.0, 0.0);
>   cubeAxesActor->GetTitleTextProperty(1)->SetColor(0.0, 1.0, 0.0);
>   cubeAxesActor->GetLabelTextProperty(1)->SetColor(0.0, 1.0, 0.0);
>   cubeAxesActor->GetTitleTextProperty(2)->SetColor(0.0, 0.0, 1.0);
>   cubeAxesActor->GetLabelTextProperty(2)->SetColor(0.0, 0.0, 1.0);
>   cubeAxesActor->DrawXGridlinesOn();
>   cubeAxesActor->DrawYGridlinesOn();
>   cubeAxesActor->DrawZGridlinesOn();
>   cubeAxesActor->SetGridLineLocation(VTK_GRID_LINES_FURTHEST);
>   renderer->AddActor(cubeAxesActor);
>
>   renderer->ResetCamera();
>
>   auto renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
>   renderWindow->AddRenderer(renderer);
>
>   auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
>   interactor->SetRenderWindow(renderWindow);
>   interactor->Initialize();
>
>   interactor->Start();
>
>   return EXIT_SUCCESS;
> }
>
> And then loaded each of the following three files, containing a 2x2x2
> (extent: 0 1 0 1 0 1), a 3x3x3 (extent: 0 2 0 2 0 2) and a 4x4x4 (extent: 0
> 3 0 3 0 3) image, all of them with spacing 1.0 1.0 1.0:
>
> <!-- 2x2x2 image -->
> <VTKFile type="ImageData" version="0.1" byte_order="LittleEndian">
>     <ImageData WholeExtent="0 1 0 1 0 1" Origin="0 0 0" Spacing="1.0 1.0
> 1.0">
>         <Piece Extent="0 1 0 1 0 1">
>             <PointData Scalars="density">
>                 <DataArray type="Float32" Name="density" format="ascii">
>                     1.0 1.0
>                     1.0 1.0
>                     1.0 1.0
>                     1.0 1.0
>                     1.0 1.0
>                     1.0 1.0
>                     1.0 1.0
>                     1.0 1.0
>                 </DataArray>
>             </PointData>
>         </Piece>
>     </ImageData>
> </VTKFile>
>
> <!-- 3x3x3 image -->
> <VTKFile type="ImageData" version="0.1" byte_order="LittleEndian">
>     <ImageData WholeExtent="0 2 0 2 0 2" Origin="0 0 0" Spacing="1.0 1.0
> 1.0">
>         <Piece Extent="0 2 0 2 0 2">
>             <PointData Scalars="density">
>                 <DataArray type="Float32" Name="density" format="ascii">
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                 </DataArray>
>             </PointData>
>         </Piece>
>     </ImageData>
> </VTKFile>
>
> <!-- 4x4x4 image -->
> <VTKFile type="ImageData" version="0.1" byte_order="LittleEndian">
>     <ImageData WholeExtent="0 3 0 3 0 3" Origin="0 0 0" Spacing="1.0 1.0
> 1.0">
>         <Piece Extent="0 3 0 3 0 3">
>             <PointData Scalars="density">
>                 <DataArray type="Float32" Name="density" format="ascii">
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                     1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
>                 </DataArray>
>             </PointData>
>         </Piece>
>     </ImageData>
> </VTKFile>
>
> I'm attaching the result.
>
> As you can see, the 2x2x2 volume has a visual dimension of 1x1x1, the
> 3x3x3 a visual dimension of 2x2x2 and the 4x4x4 a visual dimension of
> 3x3x3, so one less than what I would have expected.
>
> I thought that with e.g. a 2x2x2 volume with spacing 1.0 1.0 1.0, I would
> get 2x2x2 area occupied when the volume is mapped into the world.
>
> If someone could clarify what is going on here, it would be much
> appreciated.
>
> I understand now that to "stack" my volumes adjacently on top of each
> other, I should add extent[5] * spacing[2], not (extent[5] + 1) *
> spacing[2] (I don't have access to the vtkVolume at that point, so can't
> use GetBounds), and that it's precisely this position I should give to
> SetPosition (no need to "compensate" for the half spacing to the voxel
> center).
>
> But I'm still surprised that a volume containing 2x2x2 voxels values gives
> a 1x1x1 visual rendering.
>

Okay, I think I understand now: The voxel values are mapped to grid
intersections in the world. So in the 2x2x2 case, the 8 scalar values are
mapped to (0,0,0), (0,0,1), (0,1,0), (0,1,1), (1,0,0), (1,0,1), (1,1,0) and
(1,1,1) in world coordinates, and the visual representation of that is a
cube with corners in those points, colored according to scalars. When I
played around with the 2x2x2 example and colored it in alternating red/blue
it helped me understand. Quite interesting to see how it calculates the
colors based on how you look at that little volume actually :)

Elvis


> Elvis
>
>
>> Elvis
>>
>>
>>> Thanks in advance,
>>> Elvis
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/vtkusers/attachments/20160911/0e4da42c/attachment.html>


More information about the vtkusers mailing list