1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: TestDijkstraImageGeodesicPath.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15
16 #include "vtkSmartPointer.h"
17
18 #include "vtkContourWidget.h"
19 #include "vtkDijkstraImageContourLineInterpolator.h"
20 #include "vtkDijkstraImageGeodesicPath.h"
21 #include "vtkImageActor.h"
22 #include "vtkImageActorPointPlacer.h"
23 #include "vtkImageAnisotropicDiffusion2D.h"
24 #include "vtkImageData.h"
25 #include "vtkImageGradientMagnitude.h"
26 #include "vtkImageMapToWindowLevelColors.h"
27 #include "vtkImageMapper3D.h"
28 #include "vtkImageShiftScale.h"
29 #include "vtkInteractorStyleImage.h"
30 #include "vtkOrientedGlyphContourRepresentation.h"
31 #include "vtkPNGReader.h"
32 #include "vtkProperty.h"
33 #include "vtkRenderWindow.h"
34 #include "vtkRenderWindowInteractor.h"
35 #include "vtkRenderer.h"
36 #include "vtkTestUtilities.h"
37 #include "vtkTesting.h"
38
39 const char TestDijkstraImageGeodesicPathLog[] = "# StreamVersion 1 i\n"
40 "RenderEvent 0 0 0 0 0 0 0 i\n"
41 "EnterEvent 399 96 0 0 0 0 0 i\n"
42 "MouseMoveEvent 321 96 0 0 0 0 0 i\n"
43 "RightButtonPressEvent 321 96 0 0 0 0 0 i\n"
44 "StartInteractionEvent 321 96 0 0 0 0 0 i\n"
45 "MouseMoveEvent 321 97 0 0 0 0 0 i\n"
46 "RenderEvent 321 97 0 0 0 0 0 i\n"
47 "MouseMoveEvent 316 169 0 0 0 0 0 i\n"
48 "RenderEvent 316 169 0 0 0 0 0 i\n"
49 "RightButtonReleaseEvent 316 169 0 0 0 0 0 i\n"
50 "EndInteractionEvent 316 169 0 0 0 0 0 i\n"
51 "RenderEvent 316 169 0 0 0 0 0 i\n"
52 "MouseMoveEvent 190 356 0 0 0 0 0 i\n"
53 "LeftButtonPressEvent 190 356 0 0 0 0 0 i\n"
54 "RenderEvent 190 356 0 0 0 0 0 i\n"
55 "LeftButtonReleaseEvent 190 356 0 0 0 0 0 i\n"
56 "MouseMoveEvent 61 226 0 0 0 0 0 i\n"
57 "LeftButtonPressEvent 61 226 0 0 0 0 0 i\n"
58 "RenderEvent 61 226 0 0 0 0 0 i\n"
59 "MouseMoveEvent 62 226 0 0 0 0 0 i\n"
60 "LeftButtonReleaseEvent 62 226 0 0 0 0 0 i\n"
61 "MouseMoveEvent 131 49 0 0 0 0 0 i\n"
62 "LeftButtonPressEvent 131 49 0 0 0 0 0 i\n"
63 "RenderEvent 131 49 0 0 0 0 0 i\n"
64 "MouseMoveEvent 131 50 0 0 0 0 0 i\n"
65 "LeftButtonReleaseEvent 131 50 0 0 0 0 0 i\n"
66 "MouseMoveEvent 292 69 0 0 0 0 0 i\n"
67 "LeftButtonPressEvent 292 69 0 0 0 0 0 i\n"
68 "RenderEvent 292 69 0 0 0 0 0 i\n"
69 "LeftButtonReleaseEvent 292 69 0 0 0 0 0 i\n"
70 "MouseMoveEvent 347 189 0 0 0 0 0 i\n"
71 "LeftButtonPressEvent 347 189 0 0 0 0 0 i\n"
72 "RenderEvent 347 189 0 0 0 0 0 i\n"
73 "MouseMoveEvent 347 190 0 0 0 0 0 i\n"
74 "LeftButtonReleaseEvent 347 190 0 0 0 0 0 i\n"
75 "MouseMoveEvent 300 302 0 0 0 0 0 i\n"
76 "LeftButtonPressEvent 300 302 0 0 0 0 0 i\n"
77 "RenderEvent 300 302 0 0 0 0 0 i\n"
78 "LeftButtonReleaseEvent 300 302 0 0 0 0 0 i\n"
79 "MouseMoveEvent 191 354 0 0 0 0 0 i\n"
80 "RightButtonPressEvent 191 354 0 0 0 0 0 i\n"
81 "RenderEvent 191 354 0 0 0 0 0 i\n"
82 "RightButtonReleaseEvent 191 354 0 0 0 0 0 i\n"
83 "MouseMoveEvent 63 225 0 0 0 0 0 i\n"
84 "LeftButtonPressEvent 63 225 0 0 0 0 0 i\n"
85 "MouseMoveEvent 63 226 0 0 0 0 0 i\n"
86 "RenderEvent 63 226 0 0 0 0 0 i\n"
87 "MouseMoveEvent 63 238 0 0 0 0 0 i\n"
88 "RenderEvent 63 238 0 0 0 0 0 i\n"
89 "MouseMoveEvent 63 239 0 0 0 0 0 i\n"
90 "RenderEvent 63 239 0 0 0 0 0 i\n"
91 "LeftButtonReleaseEvent 63 239 0 0 0 0 0 i\n"
92 "MouseMoveEvent 127 47 0 0 0 0 0 i\n"
93 "KeyPressEvent 127 47 0 0 0 1 Delete i\n"
94 "RenderEvent 127 47 0 0 0 1 Delete i\n"
95 "KeyReleaseEvent 127 47 0 0 0 1 Delete i\n"
96 "MouseMoveEvent 286 71 0 0 0 0 Delete i\n"
97 "RenderEvent 286 71 0 0 0 0 Delete i\n"
98 "MouseMoveEvent 287 68 0 0 0 0 Delete i\n"
99 "KeyPressEvent 287 68 0 0 0 1 Delete i\n"
100 "RenderEvent 287 68 0 0 0 1 Delete i\n"
101 "KeyReleaseEvent 287 68 0 0 0 1 Delete i\n"
102 "MouseMoveEvent 179 218 0 0 0 0 Delete i\n"
103 "LeftButtonPressEvent 179 218 0 0 0 0 Delete i\n"
104 "MouseMoveEvent 78 122 0 0 0 0 Delete i\n"
105 "RenderEvent 78 122 0 0 0 0 Delete i\n"
106 "LeftButtonReleaseEvent 78 122 0 0 0 0 Delete i\n"
107 "MouseMoveEvent 154 106 0 0 0 0 Delete i\n"
108 "KeyPressEvent 154 106 0 0 113 1 q i\n"
109 "CharEvent 154 106 0 0 113 1 q i\n"
110 "ExitEvent 154 106 0 0 113 1 q i\n";
111
TestDijkstraImageGeodesicPath(int argc,char * argv[])112 int TestDijkstraImageGeodesicPath(int argc, char* argv[])
113 {
114 bool followCursor = false;
115 for (int i = 0; i < argc; i++)
116 {
117 followCursor |= (strcmp("--FollowCursor", argv[i]) == 0);
118 }
119
120 char* fname = vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/fullhead15.png");
121
122 vtkSmartPointer<vtkPNGReader> reader = vtkSmartPointer<vtkPNGReader>::New();
123 reader->SetFileName(fname);
124 delete[] fname;
125
126 // Smooth the image
127 vtkSmartPointer<vtkImageAnisotropicDiffusion2D> diffusion =
128 vtkSmartPointer<vtkImageAnisotropicDiffusion2D>::New();
129 diffusion->SetInputConnection(reader->GetOutputPort());
130 diffusion->SetDiffusionFactor(1.0);
131 diffusion->SetDiffusionThreshold(200.0);
132 diffusion->SetNumberOfIterations(5);
133
134 // Gradient magnitude for edges
135 vtkSmartPointer<vtkImageGradientMagnitude> grad =
136 vtkSmartPointer<vtkImageGradientMagnitude>::New();
137 grad->SetDimensionality(2);
138 grad->HandleBoundariesOn();
139 grad->SetInputConnection(diffusion->GetOutputPort());
140 grad->Update();
141
142 double* range = grad->GetOutput()->GetScalarRange();
143
144 // Invert the gradient magnitude so that low costs are
145 // associated with strong edges and scale from 0 to 1
146 vtkSmartPointer<vtkImageShiftScale> gradInvert = vtkSmartPointer<vtkImageShiftScale>::New();
147 gradInvert->SetShift(-1.0 * range[1]);
148 gradInvert->SetScale(1.0 / (range[0] - range[1]));
149 gradInvert->SetOutputScalarTypeToFloat();
150 gradInvert->SetInputConnection(grad->GetOutputPort());
151 gradInvert->Update();
152
153 vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
154 vtkSmartPointer<vtkRenderWindow> renWin = vtkSmartPointer<vtkRenderWindow>::New();
155 renWin->AddRenderer(renderer);
156 vtkSmartPointer<vtkRenderWindowInteractor> iren =
157 vtkSmartPointer<vtkRenderWindowInteractor>::New();
158 iren->SetRenderWindow(renWin);
159 vtkSmartPointer<vtkInteractorStyleImage> style = vtkSmartPointer<vtkInteractorStyleImage>::New();
160 iren->SetInteractorStyle(style);
161
162 // The color map will accept any scalar image type and convert to
163 // unsigned char for the image actor
164 vtkSmartPointer<vtkImageMapToWindowLevelColors> colorMap =
165 vtkSmartPointer<vtkImageMapToWindowLevelColors>::New();
166 colorMap->SetInputConnection(gradInvert->GetOutputPort());
167
168 range = gradInvert->GetOutput()->GetScalarRange();
169 colorMap->SetWindow(1.0);
170 colorMap->SetLevel(0.5);
171
172 vtkSmartPointer<vtkImageActor> actor = vtkSmartPointer<vtkImageActor>::New();
173 actor->GetMapper()->SetInputConnection(colorMap->GetOutputPort());
174 actor->SetDisplayExtent(0, 255, 0, 255, 0, 0);
175
176 renderer->AddActor(actor);
177
178 renderer->SetBackground(0.2, 0.2, 1);
179 renWin->SetSize(400, 400);
180
181 // Contour widget for interactive path definition
182 vtkSmartPointer<vtkContourWidget> contourWidget = vtkSmartPointer<vtkContourWidget>::New();
183 contourWidget->SetInteractor(iren);
184
185 vtkSmartPointer<vtkOrientedGlyphContourRepresentation> rep =
186 vtkSmartPointer<vtkOrientedGlyphContourRepresentation>::New();
187 contourWidget->SetRepresentation(rep);
188 contourWidget->SetFollowCursor(followCursor);
189
190 rep->GetLinesProperty()->SetColor(1, 0.2, 0);
191 rep->GetProperty()->SetColor(0, 0.2, 1);
192 rep->GetLinesProperty()->SetLineWidth(3);
193
194 // The contour rep requires a suitable point placer
195 vtkSmartPointer<vtkImageActorPointPlacer> placer =
196 vtkSmartPointer<vtkImageActorPointPlacer>::New();
197 placer->SetImageActor(actor);
198 rep->SetPointPlacer(placer);
199
200 // The line interpolator defines how intermediate points are
201 // generated between the representations nodes. This
202 // interpolator uses Dijkstra's shortest path algorithm.
203 vtkSmartPointer<vtkDijkstraImageContourLineInterpolator> interpolator =
204 vtkSmartPointer<vtkDijkstraImageContourLineInterpolator>::New();
205 interpolator->SetCostImage(gradInvert->GetOutput());
206
207 vtkDijkstraImageGeodesicPath* path = interpolator->GetDijkstraImageGeodesicPath();
208 path->StopWhenEndReachedOn();
209 // prevent contour segments from overlapping
210 path->RepelPathFromVerticesOn();
211 // weights are scaled from 0 to 1 as are associated cost
212 // components
213 path->SetCurvatureWeight(0.15);
214 path->SetEdgeLengthWeight(0.8);
215 path->SetImageWeight(1.0);
216
217 rep->SetLineInterpolator(interpolator);
218 contourWidget->EnabledOn();
219
220 renWin->Render();
221 renderer->ResetCamera();
222 iren->Initialize();
223
224 return vtkTesting::InteractorEventLoop(argc, argv, iren, TestDijkstraImageGeodesicPathLog);
225 }
226