1 /*=========================================================================
2 *
3 * Copyright Insight Software Consortium
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0.txt
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *=========================================================================*/
18 #include "QuickView.h"
19
20 #include "itkRescaleIntensityImageFilter.h"
21 #include "itkVectorRescaleIntensityImageFilter.h"
22 #include "itkRGBToVectorImageAdaptor.h"
23 #include "itkFlipImageFilter.h"
24
25 #include "vtkVersion.h"
26
27 #include "vtkRenderWindowInteractor.h"
28 #include "vtkImageMapper3D.h"
29 #include "vtkImageActor.h"
30 #include "vtkActor2D.h"
31 #include "vtkInteractorStyleImage.h"
32 #include "vtkRenderer.h"
33 #include "vtkCamera.h"
34 #include "vtkTextProperty.h"
35 #include "vtkTextMapper.h"
36
37 #include "vtkCaptureScreen.h"
38 #include "vtkPNGWriter.h"
39 #include "vtkJPEGWriter.h"
40 #include "vtkBMPWriter.h"
41 #include "vtkTIFFWriter.h"
42
43 #include "itkImageToVTKImageFilter.h"
44
45
46 using UnsignedCharRGBImageType = itk::Image<itk::RGBPixel<unsigned char>, 2>;
47 using FloatRGBImageType = itk::Image<itk::RGBPixel<float>, 2>;
48
49 using UnsignedCharImageType = itk::Image<unsigned char, 2>;
50 using CharImageType = itk::Image<char, 2>;
51 using UnsignedShortImageType = itk::Image<unsigned short, 2>;
52 using ShortImageType = itk::Image<short, 2>;
53 using UnsignedIntImageType = itk::Image<unsigned int, 2>;
54 using IntImageType = itk::Image<int, 2>;
55 using UnsignedLongImageType = itk::Image<unsigned long, 2>;
56 using LongImageType = itk::Image<long, 2>;
57 using FloatImageType = itk::Image<float, 2>;
58 using DoubleImageType = itk::Image<double, 2>;
59
60 template void ITKVtkGlue_EXPORT QuickView::AddImage<CharImageType>(
61 CharImageType *image,
62 bool FlipVertical,
63 std::string Description);
64 template void ITKVtkGlue_EXPORT QuickView::AddImage<UnsignedShortImageType>(
65 UnsignedShortImageType *image,
66 bool FlipVertical,
67 std::string Description);
68 template void ITKVtkGlue_EXPORT QuickView::AddImage<ShortImageType>(
69 ShortImageType *image,
70 bool FlipVertical,
71 std::string Description);
72 template void ITKVtkGlue_EXPORT QuickView::AddImage<UnsignedIntImageType>(
73 UnsignedIntImageType *image,
74 bool FlipVertical,
75 std::string Description);
76 template void ITKVtkGlue_EXPORT QuickView::AddImage<IntImageType>(
77 IntImageType *image,
78 bool FlipVertical,
79 std::string Description);
80 template void ITKVtkGlue_EXPORT QuickView::AddImage<UnsignedLongImageType>(
81 UnsignedLongImageType *image,
82 bool FlipVertical,
83 std::string Description);
84 template void ITKVtkGlue_EXPORT QuickView::AddImage<LongImageType>(
85 LongImageType *image,
86 bool FlipVertical,
87 std::string Description);
88 template void ITKVtkGlue_EXPORT QuickView::AddImage<FloatImageType>(
89 FloatImageType *image,
90 bool FlipVertical,
91 std::string Description);
92 template void ITKVtkGlue_EXPORT QuickView::AddImage<DoubleImageType>(
93 DoubleImageType *image,
94 bool FlipVertical,
95 std::string Description);
96
97 template< >
AddImage(UnsignedCharImageType * image,bool FlipVertical,std::string Description)98 void ITKVtkGlue_EXPORT QuickView::AddImage<UnsignedCharImageType>(
99 UnsignedCharImageType *image,
100 bool FlipVertical,
101 std::string Description)
102 {
103 if (FlipVertical)
104 {
105 using FlipFilterType = itk::FlipImageFilter< UnsignedCharImageType>;
106 FlipFilterType::Pointer flipper = FlipFilterType::New();
107 bool flipAxes[3] = { false, true, false };
108 flipper = FlipFilterType::New();
109 flipper->SetFlipAxes(flipAxes);
110 flipper->SetInput(image);
111 flipper->Update();
112 ImageInfo myImage(flipper->GetOutput(), Description);
113 this->Images.push_back(myImage);
114 }
115 else
116 {
117 ImageInfo myImage(image, Description);
118 this->Images.push_back(myImage);
119 }
120 }
121
122 template<typename TImage>
AddImage(TImage * image,bool FlipVertical,std::string Description)123 void ITKVtkGlue_EXPORT QuickView::AddImage(
124 TImage *image,
125 bool FlipVertical,
126 std::string Description)
127 {
128 using rescaleFilterType =
129 itk::RescaleIntensityImageFilter<TImage, UnsignedCharImageType >;
130
131 typename rescaleFilterType::Pointer rescaler = rescaleFilterType::New();
132 rescaler->SetOutputMinimum(0);
133 rescaler->SetOutputMaximum(255);
134 rescaler->SetInput(image);
135 rescaler->Update();
136
137 this->AddImage(rescaler->GetOutput(), FlipVertical, Description);
138 }
139
140 template< >
AddImage(UnsignedCharRGBImageType * image,bool FlipVertical,std::string Description)141 void ITKVtkGlue_EXPORT QuickView::AddImage<UnsignedCharRGBImageType>(
142 UnsignedCharRGBImageType *image,
143 bool FlipVertical,
144 std::string Description)
145 {
146 if (FlipVertical)
147 {
148 using FlipFilterType = itk::FlipImageFilter< UnsignedCharRGBImageType>;
149 FlipFilterType::Pointer flipper = FlipFilterType::New();
150 bool flipAxes[3] = { false, true, false };
151 flipper = FlipFilterType::New();
152 flipper->SetFlipAxes(flipAxes);
153 flipper->SetInput(image);
154 flipper->Update();
155 RGBImageInfo myImage(flipper->GetOutput(), Description);
156 this->RGBImages.push_back(myImage);
157 }
158 else
159 {
160 RGBImageInfo myImage(image, Description);
161 this->RGBImages.push_back(myImage);
162 }
163 }
164
165 template< >
AddRGBImage(UnsignedCharRGBImageType * image,bool FlipVertical,std::string Description)166 void ITKVtkGlue_EXPORT QuickView::AddRGBImage<UnsignedCharRGBImageType>(
167 UnsignedCharRGBImageType *image,
168 bool FlipVertical,
169 std::string Description)
170 {
171 if (FlipVertical)
172 {
173 using FlipFilterType = itk::FlipImageFilter< UnsignedCharRGBImageType>;
174 FlipFilterType::Pointer flipper = FlipFilterType::New();
175 bool flipAxes[3] = { false, true, false };
176 flipper = FlipFilterType::New();
177 flipper->SetFlipAxes(flipAxes);
178 flipper->SetInput(image);
179 flipper->Update();
180 RGBImageInfo myImage(flipper->GetOutput(), Description);
181 this->RGBImages.push_back(myImage);
182 }
183 else
184 {
185 RGBImageInfo myImage(image, Description);
186 this->RGBImages.push_back(myImage);
187 }
188 }
189
190 template< >
AddRGBImage(FloatRGBImageType * image,bool FlipVertical,std::string Description)191 void ITKVtkGlue_EXPORT QuickView::AddRGBImage<FloatRGBImageType>(
192 FloatRGBImageType *image,
193 bool FlipVertical,
194 std::string Description)
195 {
196 using AdaptorType = itk::RGBToVectorImageAdaptor<FloatRGBImageType>;
197 AdaptorType::Pointer adaptor = AdaptorType::New();
198 adaptor->SetImage(image);
199
200 using rescaleFilterType = itk::VectorRescaleIntensityImageFilter<AdaptorType, UnsignedCharRGBImageType >;
201 rescaleFilterType::Pointer rescaler = rescaleFilterType::New();
202 rescaler->SetOutputMaximumMagnitude(255);
203 rescaler->SetInput(adaptor);
204 rescaler->Update();
205 this->AddRGBImage(rescaler->GetOutput(), FlipVertical, Description);
206 }
207
208 template< >
AddImage(FloatRGBImageType * image,bool FlipVertical,std::string Description)209 void ITKVtkGlue_EXPORT QuickView::AddImage<FloatRGBImageType>(
210 FloatRGBImageType *image,
211 bool FlipVertical,
212 std::string Description)
213 {
214 using AdaptorType = itk::RGBToVectorImageAdaptor<FloatRGBImageType>;
215 AdaptorType::Pointer adaptor = AdaptorType::New();
216 adaptor->SetImage(image);
217
218 using rescaleFilterType = itk::VectorRescaleIntensityImageFilter<AdaptorType, UnsignedCharRGBImageType >;
219 rescaleFilterType::Pointer rescaler = rescaleFilterType::New();
220 rescaler->SetOutputMaximumMagnitude(255);
221 rescaler->SetInput(adaptor);
222 rescaler->Update();
223 this->AddRGBImage(rescaler->GetOutput(), FlipVertical, Description);
224 }
225
Visualize(bool interact)226 void QuickView::Visualize(bool interact)
227 {
228 unsigned int rendererSize = this->m_ViewPortSize;
229 unsigned int numberOfImages = this->Images.size() + this->RGBImages.size();
230 unsigned int numberOfRows = (numberOfImages - 1) / this->m_NumberOfColumns + 1;
231 unsigned int numberOfColumns = numberOfImages / (numberOfRows) + 1;
232 if (numberOfColumns > numberOfImages)
233 {
234 numberOfColumns = numberOfImages;
235 }
236
237 // Setup the render window and interactor
238 vtkSmartPointer<vtkRenderWindow> renderWindow =
239 vtkSmartPointer<vtkRenderWindow>::New();
240 renderWindow->SetSize(rendererSize * numberOfColumns,
241 rendererSize * numberOfRows);
242
243 vtkSmartPointer<vtkRenderWindowInteractor> interactor =
244 vtkSmartPointer<vtkRenderWindowInteractor>::New();
245 interactor->SetRenderWindow(renderWindow);
246
247 // Render all of the images
248 std::vector<double*> viewports;
249
250 using ConnectorType =
251 itk::ImageToVTKImageFilter<itk::Image<unsigned char, 2> >;
252 using RGBConnectorType =
253 itk::ImageToVTKImageFilter<itk::Image<itk::RGBPixel<unsigned char>, 2> >;
254 std::vector<ConnectorType::Pointer> connectors; // Force the connectors to persist (not lose scope) after each iteration of the loop
255 std::vector<RGBConnectorType::Pointer> RGBconnectors; // Force the connectors to persist after each iteration of the loop
256
257 double background[6] = {.4, .5, .6, .6, .5, .4};
258
259 vtkSmartPointer<vtkCamera> sharedCamera =
260 vtkSmartPointer<vtkCamera>::New();
261
262 for(unsigned int row = 0; row < numberOfRows; ++row)
263 {
264 for(unsigned int col = 0; col < numberOfColumns; ++col)
265 {
266 size_t i = row * numberOfColumns + col;
267 // (xmin, ymin, xmax, ymax)
268 double viewport[4] =
269 {static_cast<double>(col) * rendererSize / (numberOfColumns * rendererSize),
270 static_cast<double>(numberOfRows - (row+1)) * rendererSize / (numberOfRows * rendererSize),
271 static_cast<double>(col+1)*rendererSize / (numberOfColumns * rendererSize),
272 static_cast<double>(numberOfRows - row) * rendererSize / (numberOfRows * rendererSize)};
273 viewports.push_back(viewport);
274
275 // Grayscale images
276 if (i < this->Images.size())
277 {
278 ConnectorType::Pointer connector = ConnectorType::New();
279 connectors.push_back(connector);
280 connector->SetInput(this->Images[i].m_Image);
281
282 vtkSmartPointer<vtkImageActor> actor =
283 vtkSmartPointer<vtkImageActor>::New();
284 #if VTK_MAJOR_VERSION <= 5
285 actor->SetInput(connector->GetOutput());
286 #else
287 connector->Update();
288 actor->GetMapper()->SetInputData(connector->GetOutput());
289 #endif
290
291 // Setup renderer
292 vtkSmartPointer<vtkRenderer> renderer =
293 vtkSmartPointer<vtkRenderer>::New();
294 renderWindow->AddRenderer(renderer);
295 renderer->SetViewport(viewports[i]);
296 renderer->SetBackground(background);
297 if (m_ShareCamera)
298 {
299 renderer->SetActiveCamera(sharedCamera);
300 }
301 else
302 {
303 vtkSmartPointer<vtkCamera> aCamera =
304 vtkSmartPointer<vtkCamera>::New();
305 renderer->SetActiveCamera(aCamera);
306 }
307 std::rotate(background, background + 1, background + 6);
308
309 if (this->Images[i].m_Description != "")
310 {
311 vtkSmartPointer<vtkTextProperty> textProperty =
312 vtkSmartPointer<vtkTextProperty>::New();
313 textProperty->SetFontSize(10);
314 textProperty->SetFontFamilyToCourier();
315 textProperty->SetJustificationToCentered();
316
317 vtkSmartPointer<vtkTextMapper> textMapper =
318 vtkSmartPointer<vtkTextMapper>::New();
319 textMapper->SetTextProperty(textProperty);
320 textMapper->SetInput(this->Images[i].m_Description.c_str());
321
322 vtkSmartPointer<vtkActor2D> textActor =
323 vtkSmartPointer<vtkActor2D>::New();
324 textActor->SetMapper(textMapper);
325 textActor->SetPosition(rendererSize/2, 16);
326 renderer->AddActor(textActor);
327 }
328 if (m_Interpolate)
329 {
330 actor->InterpolateOn();
331 }
332 else
333 {
334 actor->InterpolateOff();
335 }
336 renderer->AddActor(actor);
337 renderer->ResetCamera();
338 }
339 // RGB Images
340 else if (i >= this->Images.size() && i < numberOfImages)
341 {
342 unsigned int j = row * numberOfColumns + col - this->Images.size();
343 RGBConnectorType::Pointer connector = RGBConnectorType::New();
344 RGBconnectors.push_back(connector);
345 connector->SetInput(this->RGBImages[j].m_Image);
346
347 vtkSmartPointer<vtkImageActor> actor =
348 vtkSmartPointer<vtkImageActor>::New();
349 #if VTK_MAJOR_VERSION <= 5
350 actor->SetInput(connector->GetOutput());
351 #else
352 connector->Update();
353 actor->GetMapper()->SetInputData(connector->GetOutput());
354 #endif
355
356 // Setup renderer
357 vtkSmartPointer<vtkRenderer> renderer =
358 vtkSmartPointer<vtkRenderer>::New();
359 renderWindow->AddRenderer(renderer);
360 renderer->SetViewport(viewports[i]);
361 renderer->SetBackground(background);
362 if (m_ShareCamera)
363 {
364 renderer->SetActiveCamera(sharedCamera);
365 }
366 else
367 {
368 vtkSmartPointer<vtkCamera> aCamera =
369 vtkSmartPointer<vtkCamera>::New();
370 renderer->SetActiveCamera(aCamera);
371 }
372 std::rotate(background, background + 1, background + 6);
373
374 if (this->RGBImages[j].m_Description != "")
375 {
376 vtkSmartPointer<vtkTextProperty> textProperty =
377 vtkSmartPointer<vtkTextProperty>::New();
378 textProperty->SetFontSize(10);
379 textProperty->SetFontFamilyToCourier();
380 textProperty->SetJustificationToCentered();
381
382 vtkSmartPointer<vtkTextMapper> textMapper =
383 vtkSmartPointer<vtkTextMapper>::New();
384 textMapper->SetTextProperty(textProperty);
385 textMapper->SetInput(this->RGBImages[j].m_Description.c_str());
386
387 vtkSmartPointer<vtkActor2D> textActor =
388 vtkSmartPointer<vtkActor2D>::New();
389 textActor->SetMapper(textMapper);
390 textActor->SetPosition(rendererSize/2, 16);
391 renderer->AddActor(textActor);
392 }
393
394 if (m_Interpolate)
395 {
396 actor->InterpolateOn();
397 }
398 else
399 {
400 actor->InterpolateOff();
401 }
402 renderer->AddActor(actor);
403 renderer->ResetCamera();
404 }
405 else
406 {
407 // Fill empty viewports
408 vtkSmartPointer<vtkRenderer> renderer =
409 vtkSmartPointer<vtkRenderer>::New();
410 renderWindow->AddRenderer(renderer);
411 renderer->SetViewport(viewports[i]);
412 renderer->SetBackground(background);
413 continue;
414 }
415 }
416 }
417 renderWindow->Render();
418
419 if( m_Snapshot )
420 {
421 std::string filename;
422 std::stringstream temp;
423 temp << m_SnapshotPath << m_SnapshotPrefix << m_Counter << ".";
424 filename = temp.str();
425 filename.append( m_SnapshotExtension );
426
427 if( m_SnapshotExtension == "png" )
428 {
429 vtkCaptureScreen< vtkPNGWriter > capture( renderWindow );
430 capture( filename );
431 }
432 if( ( m_SnapshotExtension == "jpg" ) || ( m_SnapshotExtension == "jpeg" ) )
433 {
434 vtkCaptureScreen< vtkJPEGWriter > capture( renderWindow );
435 capture( filename );
436 }
437 if( m_SnapshotExtension == "bmp" )
438 {
439 vtkCaptureScreen< vtkBMPWriter > capture( renderWindow );
440 capture( filename );
441 }
442 if( ( m_SnapshotExtension == "tif" ) || ( m_SnapshotExtension == "tiff" ) )
443 {
444 vtkCaptureScreen< vtkTIFFWriter > capture( renderWindow );
445 capture( filename );
446 }
447 m_Counter++;
448 }
449
450 vtkSmartPointer<vtkInteractorStyleImage> style =
451 vtkSmartPointer<vtkInteractorStyleImage>::New();
452 interactor->SetInteractorStyle(style);
453
454 if (interact)
455 {
456 interactor->Start();
457 }
458 }
459