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