Discussion:
[vtkusers] add circles & sphere to DICOM slices & 3D viewer
mbcx9rb9
2015-01-09 10:03:12 UTC
Permalink
I currently have 3 orthogonal views and an isosurface 3D of a DICOM. I would
like that when the user clicks on a point on one of the 3 orthogonal views,
a sphere is created at that point. This would be displayed as circles on the
3 orthogonal views (naturally, the cirlces wouldn't be visible all the time,
as one view could be looking at a different slice/section of the DICOM) and
a sphere on the 3D viewer.

So far, I have created a custom interactor which passes the x- y-coordinates
(via GetEventPoisition()) to a function and the z-coordinate is obtained
through imageViewer->getSlice().

After that, I create a circle/sphere with vtkRegularPolygonSources (with
high number of sides) and vtkSphereSoure. They then get added to the render
with ui->qvtkWidget->GetRenderWindow()->AddRenderer(circle or sphere
renderer).

All well and good, however, I have two problems:
1. the coordinates returned by the interactor use the Display coordinate
system, so they depend on the window size, zoom, rotation, etc. of the
viewer - can I get it to return the nearest DICOM world(?) coordinate such
that, for a DICOM of 500 x 500 x 500 slices, I return x, y, z coordinates
between 0 and 500?

2. When I draw the circle or sphere, it removes the previous slice or 3D
render. I saw in this example
<http://vtk.1045678.n5.nabble.com/render-a-sphere-at-a-point-in-a-volume-td1246875.html#a1246876>
, he added both actors at the same time. Short of redrawing everything I
can't do that - it seems that adding one in later removes the previous
render?

Thanks in advance for the help!
Richard



--
View this message in context: http://vtk.1045678.n5.nabble.com/add-circles-sphere-to-DICOM-slices-3D-viewer-tp5730043.html
Sent from the VTK - Users mailing list archive at Nabble.com.
_______________________________________________
Powered by www.kitware.com

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Please keep messages on-topic and check the VTK FAQ at: http://www.vtk.org/Wiki/VTK_FAQ

Search the list archives at: http://markmail.org/search/?q=vtkusers

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/vtkusers
chasank
2015-01-09 11:45:02 UTC
Permalink
Hi Richard

1) You may convert display coordinates into world coordinates using
vtkCellPicker

double *displayPoint = renderer->GetDisplayPoint();

vtkCellPicker *picker = vtkCellPicker::New();
picker->PickFromListOn();
picker->AddPickList(vtkPropInstance);
picker->Pick(displayPoint[0], displayPoint[1], 0, renderer);

double *worldCoordinates = picker->GetPickPosition();


2) Use vtkImageProperty for opacity issues between overlapped planes. Play
with ambient, diffuse and opacity

vtkImagePropery *imageProperty = vtkImagePropery::New();
imageProperty->SetInterpolationTypeToLinear();
imageProperty->SetAmbient(1.0);
imageProperty->SetDiffuse(1.0);
imageProperty->SetOpacity(1.0);

imageSlice->SetProperty(imageProperty);

Best regards.



--
View this message in context: http://vtk.1045678.n5.nabble.com/add-circles-sphere-to-DICOM-slices-3D-viewer-tp5730043p5730044.html
Sent from the VTK - Users mailing list archive at Nabble.com.
_______________________________________________
Powered by www.kitware.com

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Please keep messages on-topic and check the VTK FAQ at: http://www.vtk.org/Wiki/VTK_FAQ

Search the list archives at: http://markmail.org/search/?q=vtkusers

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/vtkusers
David Gobbi
2015-01-09 13:05:27 UTC
Permalink
Post by mbcx9rb9
1. the coordinates returned by the interactor use the Display coordinate
system, so they depend on the window size, zoom, rotation, etc. of the
viewer - can I get it to return the nearest DICOM world(?) coordinate such
that, for a DICOM of 500 x 500 x 500 slices, I return x, y, z coordinates
between 0 and 500?
The vtkCellPicker can do this. With it, you can do a "Pick" at your display
coordinates, and then you can call GetPointIJK() to get the i,j,k
coordinates.
The "IJK" coordinates are what VTK calls "structured coordinates" and they
are what you want.

2. When I draw the circle or sphere, it removes the previous slice or 3D
Post by mbcx9rb9
render. I saw in this example
<
http://vtk.1045678.n5.nabble.com/render-a-sphere-at-a-point-in-a-volume-td1246875.html#a1246876
, he added both actors at the same time. Short of redrawing everything I
can't do that - it seems that adding one in later removes the previous
render?
The way you are describing this suggests that you don't yet understand
how VTK rendering works... drawing the sphere cannot "remove" the slice.

All of the actors exist in the scene at the same time. If you can't see an
actor, it probably just means that (a) it is hidden underneath another
actor, or (b) it is not within the viewing frustum.

I think that what you want to do is show just the outline of where the
sphere
intersects the slice. This can be done by applying vtkCutter to the sphere.

- David
mbcx9rb9
2015-01-12 14:54:53 UTC
Permalink
Chasank, David,

Thanks for the advice.

David, I think you're right about my lack of understanding of the rendering
process - amongst many other aspects.

The circle, for example, always appears in the centre of the rendered screen
and is always the same size. If I go to the 0th slice and click the bottom
left pixel, the circle then jumps up in the middle of the screen. Using the
GetPointIJK structured coordinates, do I need to convert the selected point
to a different coordinate system for the sphere/cutting plane?

I also haven't managed to see both the circle and the DICOM image at the
same time, despite what feels like every combination of setOpacity,
setAmbient, etc. When I set the background of the newly cut circle to green,
everything goes green, so I think it might be that the background of the
circle is masking the DICOM slice, can I set it to have a transparent
background?

Lastly, when I can draw the circle in the correct place, the correct size
and can see the DICOM underneath, I need to fill the middle of the circle
in. I saw on this
<http://vtk.1045678.n5.nabble.com/Filling-vtkCutter-output-td1244798.html#a1244800>
thread some suggestions, but neither vtkTriangleFilter nor
vtkLinearExtrusionFilter did the trick for me. Any ideas?

Thanks



--
View this message in context: http://vtk.1045678.n5.nabble.com/add-circles-sphere-to-DICOM-slices-3D-viewer-tp5730043p5730081.html
Sent from the VTK - Users mailing list archive at Nabble.com.
_______________________________________________
Powered by www.kitware.com

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Please keep messages on-topic and check the VTK FAQ at: http://www.vtk.org/Wiki/VTK_FAQ

Search the list archives at: http://markmail.org/search/?q=vtkusers

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/vtkusers
David Gobbi
2015-01-12 16:27:12 UTC
Permalink
Post by mbcx9rb9
The circle, for example, always appears in the centre of the rendered screen
and is always the same size.
If you don't set the FocalPoint, Position, ViewUp, and ViewAngle of the
vtkCamera,
then the vtkCamera will set these automatically so that the the actors are
within
view. To get an idea of what is going on, you should try setting these
parameters
manually. Also, search google for "opengl camera" because there are tons
of well-
written documents about the camera metaphor that is used for 3D graphics.

If I go to the 0th slice and click the bottom
Post by mbcx9rb9
left pixel, the circle then jumps up in the middle of the screen. Using the
GetPointIJK structured coordinates, do I need to convert the selected point
to a different coordinate system for the sphere/cutting plane?
Get GetPointIJK gives the i,j,k (row, col, slice) indices into the image,
i.e. integers.
VTK uses floating-point x,y,z coords for its data coords, which implicitly
use units
of "mm" when dealing with DICOM files. The picker's GetMapperPosition() and
GetPickPosition() methods return the latter.
Post by mbcx9rb9
I also haven't managed to see both the circle and the DICOM image at the
same time, despite what feels like every combination of setOpacity,
setAmbient, etc. When I set the background of the newly cut circle to green,
everything goes green, so I think it might be that the background of the
circle is masking the DICOM slice, can I set it to have a transparent
background?
There is no way to set the background for a single actor, AFAIK the only
way to
set the background is in the vtkRenderer, in which case you are setting the
background
for everything, and the background will therefore be behind everything and
cannot
ever be in front of something. Can you explain in more detail what you are
doing?

Lastly, when I can draw the circle in the correct place, the correct size
Post by mbcx9rb9
and can see the DICOM underneath, I need to fill the middle of the circle
in. I saw on this
<
http://vtk.1045678.n5.nabble.com/Filling-vtkCutter-output-td1244798.html#a1244800
thread some suggestions, but neither vtkTriangleFilter nor
vtkLinearExtrusionFilter did the trick for me. Any ideas?
Try vtkContourTriangulator.

- David
Richard Brown
2015-01-13 13:24:58 UTC
Permalink
Thanks, vtkContourTriangulator worked well and I’ll continue to work my way through your first two points.
Post by mbcx9rb9
I also haven't managed to see both the circle and the DICOM image at the
same time, despite what feels like every combination of setOpacity,
setAmbient, etc. When I set the background of the newly cut circle to green,
everything goes green, so I think it might be that the background of the
circle is masking the DICOM slice, can I set it to have a transparent
background?
There is no way to set the background for a single actor, AFAIK the only way to
set the background is in the vtkRenderer, in which case you are setting the background
for everything, and the background will therefore be behind everything and cannot
ever be in front of something. Can you explain in more detail what you are doing?
Beneath I’ve copied the code that I’ve been trying. worldCoords is the point returned by the user’s click using GetIJK (by the way, the difference between GetIJK and GetPickPosition & GetMapperPosition is IJK is the rounded to int, the values are otherwise the same?). I try to add the newly cut circle to the QVTKWidget already containing the DICOM slice using GetRenderindow()->AddRenderer(renderer) at the end, and the output is a semi-transparent red circle (because opacity is 40%) on a bright green background. I can’t for the life of me figure out where I need to point the camera to see the DICOM slice again.

Cheers for the help,
Richard

P.S. I know the vtkCamera settings are nonsensical, I am just messing about with them at this stage.

vtkSmartPointer<vtkSphereSource> sphere = vtkSmartPointer<vtkSphereSource>::New();
sphere->SetCenter(mmCoords);
sphere->SetPhiResolution(30);
sphere->SetThetaResolution(30);
sphere->SetRadius(5);
sphere->Update();

vtkSmartPointer<vtkPlane> plane = vtkSmartPointer<vtkPlane>::New();
plane->SetOrigin(worldCoords[0], worldCoords[1], worldCoords[2]);
plane->SetNormal(0, 0, 1);

vtkSmartPointer<vtkContourTriangulator> triangles = vtkSmartPointer<vtkContourTriangulator>::New();
triangles->SetInputConnection(sphereCutter->GetOutputPort());

// Visualize
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(triangles->GetOutputPort());

vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetColor(1.0, 0.0, 0.0);
actor->GetProperty()->EdgeVisibilityOff();
actor->GetProperty()->SetAmbient(1.0);
actor->GetProperty()->SetDiffuse(1.0);
actor->GetProperty()->SetOpacity(0.4);


vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();
camera->SetPosition(worldCoords[0], worldCoords[1], worldCoords[2]+50);
camera->SetFocalPoint(worldCoords[0], worldCoords[1], worldCoords[2]);

vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(actor);
renderer->SetBackground(0,1,0);
renderer->SetActiveCamera(camera);

ui->qvtk->GetRenderWindow()->AddRenderer(renderer);
David Gobbi
2015-01-13 14:35:48 UTC
Permalink
Hi Richard,

The "IJK" coordinates are not just data coordinates rounded to int. Pixel
spacing must also be taken into account. To properly display images with
VTK, you should become familiar with how VTK images utilize the Spacing and
Origin information that is stored with the images.

With regards to the your code, if the sphere and the image each has its own
renderer, then that is the source of your problems. They should be in the
same renderer, and getting them to coincide is going to require that you
learn, in a fair bit of detail, (1) how VTK deals with coordinate systems,
and (2) how DICOM deals with coordinate systems.

- David
Thanks, vtkContourTriangulator worked well and I'll continue to work my
way through your first two points.
I also haven't managed to see both the circle and the DICOM image at the
Post by mbcx9rb9
same time, despite what feels like every combination of setOpacity,
setAmbient, etc. When I set the background of the newly cut circle to green,
everything goes green, so I think it might be that the background of the
circle is masking the DICOM slice, can I set it to have a transparent
background?
There is no way to set the background for a single actor, AFAIK the only way to
set the background is in the vtkRenderer, in which case you are setting the background
for everything, and the background will therefore be behind everything and cannot
ever be in front of something. Can you explain in more detail what you are doing?
Beneath I've copied the code that I've been trying. worldCoords is the
point returned by the user's click using GetIJK (by the way, the difference
between GetIJK and GetPickPosition & GetMapperPosition is IJK is the
rounded to int, the values are otherwise the same?). I try to add the newly
cut circle to the QVTKWidget already containing the DICOM slice using
GetRenderindow()->AddRenderer(renderer) at the end, and the output is a
semi-transparent red circle (because opacity is 40%) on a bright green
background. I can't for the life of me figure out where I need to point the
camera to see the DICOM slice again.
Cheers for the help,
Richard
P.S. I know the vtkCamera settings are nonsensical, I am just messing
about with them at this stage.
vtkSmartPointer<vtkSphereSource> sphere = vtkSmartPointer<vtkSphereSource>::New();
sphere->SetCenter(mmCoords);
sphere->SetPhiResolution(30);
sphere->SetThetaResolution(30);
sphere->SetRadius(5);
sphere->Update();
vtkSmartPointer<vtkPlane> plane = vtkSmartPointer<vtkPlane>::New();
plane->SetOrigin(worldCoords[0], worldCoords[1], worldCoords[2]);
plane->SetNormal(0, 0, 1);
vtkSmartPointer<vtkContourTriangulator> triangles = vtkSmartPointer<vtkContourTriangulator>::New();
triangles->SetInputConnection(sphereCutter->GetOutputPort());
// Visualize
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(triangles->GetOutputPort());
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetColor(1.0, 0.0, 0.0);
actor->GetProperty()->EdgeVisibilityOff();
actor->GetProperty()->SetAmbient(1.0);
actor->GetProperty()->SetDiffuse(1.0);
actor->GetProperty()->SetOpacity(0.4);
vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();
camera->SetPosition(worldCoords[0], worldCoords[1], worldCoords[2]+50);
camera->SetFocalPoint(worldCoords[0], worldCoords[1], worldCoords[2]);
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(actor);
renderer->SetBackground(0,1,0);
renderer->SetActiveCamera(camera);
ui->qvtk->GetRenderWindow()->AddRenderer(renderer);
Loading...