1 /*=========================================================================
2
3 Program: GDCM (Grassroots DICOM). A DICOM library
4
5 Copyright (c) 2006-2011 Mathieu Malaterre
6 All rights reserved.
7 See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
8
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the above copyright notice for more information.
12
13 =========================================================================*/
14 /*
15 * TODO: vtkPlaybackWidget would be cool for 4D images...
16 * should I do it here, or a specified 4Dviewer application that will reexecute the reader (TIME*
17 * stuff in vtk)
18 */
19 #include "vtkGDCMImageReader.h"
20
21 #include "vtkVersion.h"
22 #include "vtkErrorCode.h"
23 #include "vtkMedicalImageProperties.h"
24 #include "vtkXMLImageDataWriter.h"
25 #include "vtkInteractorStyleImage.h"
26 #include "vtkCornerAnnotation.h"
27 #include "vtkPNGWriter.h"
28 #include "vtkImageShiftScale.h"
29 #include "vtkOutlineFilter.h"
30 #include "vtkMath.h"
31 #include "vtkPolyDataMapper2D.h"
32 #include "vtkImageReslice.h"
33 #include "vtkRenderWindowInteractor.h"
34 #include "vtkRenderWindow.h"
35 #include "vtkPointData.h"
36 #include "vtkImageMapToColors.h"
37 #include "vtkLookupTable.h"
38 #include "vtkActor2D.h"
39 #include "vtkImageMapToWindowLevelColors.h"
40 #include "vtkImageActor.h"
41 #include "vtkWindowToImageFilter.h"
42 #if VTK_MAJOR_VERSION >= 6 || (VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0)
43 #include "vtkImageMapToColors16.h"
44 #include "vtkBalloonWidget.h"
45 #include "vtkBalloonRepresentation.h"
46 #include "vtkLogoWidget.h"
47 #include "vtkLogoRepresentation.h"
48 #include "vtkAngleWidget.h"
49 #include "vtkAngleRepresentation2D.h"
50 #include "vtkBiDimensionalWidget.h"
51 #include "vtkBiDimensionalRepresentation2D.h"
52 #include "vtkDistanceWidget.h"
53 #include "vtkContourWidget.h"
54 #include "vtkOrientedGlyphContourRepresentation.h"
55 #include "vtkPointHandleRepresentation2D.h"
56 #include "vtkDistanceRepresentation2D.h"
57 #include "vtkLegendScaleActor.h"
58 #include "vtkProperty2D.h"
59 #else
60 class vtkLogoWidget;
61 class vtkBiDimensionalWidget;
62 class vtkDistanceWidget;
63 class vtkLogoRepresentation;
64 class vtkContourWidget;
65 class vtkAngleWidget;
66 #endif
67 #if VTK_MAJOR_VERSION >= 5
68 #include "vtkImageYBRToRGB.h"
69 #include "vtkImageColorViewer.h"
70 #else
71 #include "vtkImageViewer2.h"
72 #endif
73 #include "vtkImageData.h"
74 #include "vtkCommand.h"
75 #include "vtkRenderer.h"
76 #include "vtkStringArray.h"
77 #include "vtkDebugLeaks.h"
78 #include "vtkWorldPointPicker.h"
79 #include "vtkMultiThreader.h"
80
81 #include "gdcmFilename.h"
82 #include "gdcmSystem.h"
83 #include "gdcmDirectory.h"
84 #include "gdcmImageHelper.h"
85 #include "gdcmReader.h"
86 #include "gdcmTrace.h"
87 #include "gdcmVersion.h"
88
89 #include <getopt.h>
90 #include <assert.h>
91
92 #ifndef vtkFloatingPointType
93 #define vtkFloatingPointType double
94 #endif
95
96 #if VTK_MAJOR_VERSION >= 5
97 #else
98 class vtkImageColorViewer : public vtkImageViewer2
99 {
100 public:
101 vtkTypeMacro(vtkImageColorViewer,vtkImageViewer2);
102
New()103 static vtkImageColorViewer *New()
104 {
105 #ifdef VTK_DEBUG_LEAKS
106 vtkDebugLeaks::ConstructClass("vtkImageColorViewer");
107 #endif
108 return new vtkImageColorViewer;
109 }
vtkImageColorViewer()110 vtkImageColorViewer() {
111 OverlayImageActor = vtkImageActor::New();
112 }
~vtkImageColorViewer()113 ~vtkImageColorViewer() {
114 OverlayImageActor->Delete();
115 }
GetOverlayVisibility()116 double GetOverlayVisibility() { return 0; }
SetOverlayVisibility(double vis)117 void SetOverlayVisibility(double vis) {}
AddInput(vtkImageData * input)118 void AddInput(vtkImageData * input)
119 {
120 vtkRenderWindow *renwin = this->GetRenderWindow ();
121 renwin->SetNumberOfLayers(2);
122 vtkRenderer *Renderer = vtkRenderer::New();
123 Renderer->SetLayer(0);
124 //OverlayImageActor->SetOpacity(0.5);
125 //OverlayImageActor->GetProperty()->SetOpacity(1.0);
126 vtkImageMapToWindowLevelColors *WindowLevel = vtkImageMapToWindowLevelColors::New();
127 WindowLevel->SetInput(input);
128 OverlayImageActor->SetInput(WindowLevel->GetOutput());
129 Renderer->AddProp(OverlayImageActor);
130 OverlayImageActor->SetVisibility(1);
131
132 renwin->AddRenderer(Renderer);
133 Renderer->Delete();
134 WindowLevel->Delete();
135 }
136 private:
137 vtkImageActor *OverlayImageActor;
138 };
139 //vtkCxxRevisionMacro(vtkImageColorViewer, "$Revision: 1.30 $")
140 vtkInstantiatorNewMacro(vtkImageColorViewer)
141 #endif
142
143 //----------------------------------------------------------------------------
144 // Callback for the interaction
145 template <typename TViewer>
146 class vtkGDCMObserver : public vtkCommand
147 {
148 public:
New()149 static vtkGDCMObserver *New()
150 {
151 return new vtkGDCMObserver;
152 }
vtkGDCMObserver()153 vtkGDCMObserver()
154 {
155 ImageViewer = NULL;
156 IconWidget = NULL;
157 DistanceWidget = NULL;
158 BiDimWidget = NULL;
159 AngleWidget = NULL;
160 ContourWidget = NULL;
161 picker = vtkWorldPointPicker::New();
162 }
~vtkGDCMObserver()163 ~vtkGDCMObserver()
164 {
165 picker->Delete();
166 }
Execute(vtkObject * caller,unsigned long event,void *)167 virtual void Execute(vtkObject *caller, unsigned long event, void* /*calldata*/)
168 {
169 if ( this->ImageViewer )
170 {
171 vtkRenderWindowInteractor * rwi = vtkRenderWindowInteractor::SafeDownCast( caller );
172 if ( event == vtkCommand::CharEvent )
173 {
174 char keycode = 0;
175 if( rwi ) keycode = rwi->GetKeyCode();
176 // 'o' is a special key for overlay visibility
177 if ( keycode == 'o' )
178 {
179 ImageViewer->SetOverlayVisibility( 1 - ImageViewer->GetOverlayVisibility() );
180 ImageViewer->Render();
181 //std::cerr << ImageViewer->GetOverlayVisibility() << std::endl;
182 }
183 else if ( keycode == 's' )
184 {
185 vtkPNGWriter * writer = vtkPNGWriter::New();
186 vtkWindowToImageFilter * w2i = vtkWindowToImageFilter::New();
187 w2i->SetInput( rwi->GetRenderWindow() );
188 #if VTK_MAJOR_VERSION >= 6
189 writer->SetInputConnection( w2i->GetOutputPort() );
190 #else
191 writer->SetInput( w2i->GetOutput() );
192 #endif
193 writer->SetFileName( "snapshot.png" );
194 writer->Write();
195 writer->Delete();
196 w2i->Delete();
197 //std::cerr << "Screenshort saved to snapshot.png" << std::endl;
198 }
199 #if VTK_MAJOR_VERSION >= 6 || (VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0)
200 else if ( keycode == 'l' )
201 {
202 IconWidget->Off();
203 }
204 else if ( keycode == 'a' )
205 {
206 AngleWidget->On();
207 }
208 else if ( keycode == 'b' )
209 {
210 BiDimWidget->On();
211 }
212 else if ( keycode == 'c' )
213 {
214 ContourWidget->On();
215 }
216 else if ( keycode == 'd' )
217 {
218 DistanceWidget->On();
219 }
220 else if ( keycode == 'p' )
221 {
222 }
223 #endif
224 else
225 {
226 #if VTK_MAJOR_VERSION >= 5 || (VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5)
227 int max = ImageViewer->GetSliceMax();
228 int slice = (ImageViewer->GetSlice() + 1) % ++max;
229 ImageViewer->SetSlice( slice );
230 ImageViewer->GetRenderer()->ResetCamera();
231 #else
232 int max = ImageViewer->GetWholeZMax();
233 int slice = (ImageViewer->GetZSlice() + 1 ) % ++max;
234 ImageViewer->SetZSlice( slice );
235 ImageViewer->GetRenderer()->ResetCameraClippingRange();
236 #endif
237 ImageViewer->Render();
238 }
239 }
240 else if ( event == vtkCommand::EndPickEvent )
241 {
242 //std::cerr << "EndPickEvent" << std::endl;
243 int *pick = rwi->GetEventPosition();
244 vtkRenderer *ren1 = ImageViewer->GetRenderer();
245 picker->Pick((double)pick[0], (double)pick[1], 0.0, ren1);
246 vtkFloatingPointType *pos = picker->GetPickPosition ();
247 std::cout << pos[0] << "," << pos[1] << "," << pos[2] << std::endl;
248 }
249 else
250 {
251 std::cerr << "Unhandled even:" << event << std::endl;
252 }
253 }
254 }
255 TViewer *ImageViewer;
256 vtkWorldPointPicker *picker;
257 vtkLogoWidget *IconWidget;
258 vtkDistanceWidget *DistanceWidget;
259 vtkAngleWidget *AngleWidget;
260 vtkBiDimensionalWidget *BiDimWidget;
261 vtkContourWidget *ContourWidget;
262
263 };
264
265 int verbose;
266
267 #if VTK_MAJOR_VERSION >= 6 || (VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0)
268 class vtkBalloonCallback : public vtkCommand
269 {
270 public:
New()271 static vtkBalloonCallback *New()
272 { return new vtkBalloonCallback; }
Execute(vtkObject * caller,unsigned long,void *)273 virtual void Execute(vtkObject *caller, unsigned long, void*)
274 {
275 vtkBalloonWidget *balloonWidget = reinterpret_cast<vtkBalloonWidget*>(caller);
276 if ( balloonWidget->GetCurrentProp() != NULL )
277 {
278 cout << "Prop selected\n";
279 }
280 }
281 };
282 #endif
283
FillCornerFromMedProp(vtkCornerAnnotation * ca,vtkMedicalImageProperties * medprop)284 void FillCornerFromMedProp( vtkCornerAnnotation *ca, vtkMedicalImageProperties *medprop )
285 {
286 std::string bottomleft = "S: ";
287 if( medprop->GetSeriesNumber() )
288 bottomleft += medprop->GetSeriesNumber();
289 bottomleft += "\nI: ";
290 if( medprop->GetImageNumber() )
291 bottomleft += medprop->GetImageNumber();
292 bottomleft += "\n<window_level>";
293 ca->SetText(0, bottomleft.c_str());
294 if( medprop->GetStationName() )
295 {
296 const std::string bottomright = medprop->GetStationName();
297 ca->SetText(1, bottomright.c_str());
298 }
299 std::string topleft;
300 if( medprop->GetInstitutionName() )
301 topleft += medprop->GetInstitutionName();
302 topleft += "\n";
303 if( medprop->GetPatientName() )
304 topleft += medprop->GetPatientName();
305 ca->SetText(2, topleft.c_str());
306 std::string topright;
307 if( medprop->GetStudyDate() )
308 topright += medprop->GetStudyDate();
309 topright += "\n";
310 if( medprop->GetAcquisitionTime() )
311 topright += medprop->GetAcquisitionTime();
312 ca->SetText(3, topright.c_str());
313 }
314
315 // A feature in VS6 make it painfull to write template code
316 // that do not contain the template parameter in the function
317 // signature. Thus always pass parameter in the function:
318 template <typename TViewer>
ExecuteViewer(TViewer * viewer,vtkStringArray * filenames)319 void ExecuteViewer(TViewer *viewer, vtkStringArray *filenames)
320 {
321 vtkGDCMImageReader *reader = vtkGDCMImageReader::New();
322 if( filenames->GetSize() == 1 ) // Backward compatible...
323 {
324 reader->SetFileName( filenames->GetValue(0) );
325 }
326 else
327 {
328 reader->SetFileNames( filenames );
329 }
330
331 vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
332 // For a single medical image, it would be more efficient to use
333 // 0028|1050 [DS] [Window Center]
334 // 0028|1051 [DS] [Window Width]
335 // but gdcmviewer doesn't know about them :-(
336
337 //reader->FileLowerLeftOn();
338 reader->Update();
339 if( reader->GetErrorCode() )
340 {
341 std::cerr << "There was an error: " << vtkErrorCode::
342 GetStringFromErrorCode(reader->GetErrorCode()) << std::endl;
343 return;
344 }
345
346 //reader->Print( cout );
347 if( verbose )
348 reader->GetOutput()->Print( cout );
349 //reader->GetOutput(1)->Print( cout );
350 vtkFloatingPointType range[2];
351 reader->GetOutput()->GetScalarRange(range);
352 #if (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 )
353 viewer->SetInputConnection ( reader->GetOutputPort(0) );
354 // Technically we could just simple always call AddInputConnection on the overlay
355 // but there is something wrong going on, when overlay visibility is set to 0 at startup
356 // thus we need to make it visible by default which is annoying, so activate only
357 // if overlays are found:
358 if( reader->GetNumberOfOverlays() )
359 {
360 // Add first overlay:
361 // WARNING: gdcmviewer2 only !
362 viewer->AddInputConnection ( reader->GetOverlayPort(0) );
363 }
364 // TODO: Icon can be added using the vtkLogoWidget
365 #if VTK_MAJOR_VERSION >= 6 || (VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0)
366 vtkPointHandleRepresentation2D *handle = vtkPointHandleRepresentation2D::New();
367 handle->GetProperty()->SetColor(1,0,0);
368 vtkDistanceRepresentation2D *drep = vtkDistanceRepresentation2D::New();
369 drep->SetHandleRepresentation(handle);
370 handle->Delete();
371
372 vtkDistanceWidget *dwidget = vtkDistanceWidget::New();
373 dwidget->SetInteractor(iren);
374 dwidget->CreateDefaultRepresentation();
375 dwidget->SetRepresentation(drep);
376 drep->Delete();
377
378 vtkAngleRepresentation2D *anglerep = vtkAngleRepresentation2D::New();
379 vtkAngleWidget *anglewidget = vtkAngleWidget::New();
380 anglewidget->SetInteractor(iren);
381 anglewidget->SetRepresentation(anglerep);
382 anglerep->Delete();
383
384 vtkBiDimensionalRepresentation2D *brep = vtkBiDimensionalRepresentation2D::New();
385 vtkBiDimensionalWidget *bwidget = vtkBiDimensionalWidget::New();
386 bwidget->SetInteractor(iren);
387 bwidget->SetRepresentation(brep);
388 brep->Delete();
389
390 vtkOrientedGlyphContourRepresentation *contourRep = vtkOrientedGlyphContourRepresentation::New();
391 vtkContourWidget *contourWidget = vtkContourWidget::New();
392 contourWidget->SetInteractor(iren);
393 contourWidget->SetRepresentation(contourRep);
394 contourRep->Delete();
395
396 vtkBalloonRepresentation *balloonrep = vtkBalloonRepresentation::New();
397 balloonrep->SetBalloonLayoutToImageRight();
398
399 vtkBalloonWidget *balloonwidget = vtkBalloonWidget::New();
400 balloonwidget->SetInteractor(iren);
401 balloonwidget->SetRepresentation(balloonrep);
402 balloonrep->Delete();
403 //balloonwidget->AddBalloon(viewer->GetImageActor(),"This is a DICOM image",NULL);
404
405 vtkBalloonCallback *cbk = vtkBalloonCallback::New();
406 balloonwidget->AddObserver(vtkCommand::WidgetActivateEvent,cbk);
407
408 vtkLogoWidget * iconwidget = 0;
409 if( reader->GetNumberOfIconImages() )
410 {
411 vtkLogoRepresentation *rep = vtkLogoRepresentation::New();
412 rep->SetImage(reader->GetIconImage());
413 //reader->GetIconImage()->Print( std::cout );
414 if( reader->GetIconImage()->GetPointData()->GetScalars()
415 && reader->GetIconImage()->GetPointData()->GetScalars()->GetLookupTable() )
416 {
417 vtkLookupTable *lut = reader->GetIconImage()->GetPointData()->GetScalars()->GetLookupTable();
418 vtkImageMapToColors *map = vtkImageMapToColors::New ();
419 #if (VTK_MAJOR_VERSION >= 6)
420 map->SetInputData(reader->GetIconImage());
421 #else
422 map->SetInput (reader->GetIconImage());
423 #endif
424 map->SetLookupTable ( lut );
425 //FIXME there is no way to know the type of LUT the icon is using:
426 //if( reader->GetImageFormat() == VTK_LOOKUP_TABLE )
427 {
428 map->SetOutputFormatToRGB();
429 }
430 //else if( reader->GetImageFormat() == VTK_INVERSE_LUMINANCE )
431 // {
432 // map->SetOutputFormatToLuminance();
433 // }
434 map->Update();
435 //map->GetOutput()->GetScalarRange(range);
436 //viewer->SetInput( map->GetOutput() );
437 //map->GetOutput()->Print( std::cout );
438 rep->SetImage( map->GetOutput() );
439 map->Delete();
440
441 //vtkPNGWriter *iconw = vtkPNGWriter::New();
442 //iconw->SetInput( map->GetOutput() );
443 //iconw->SetFileName( "/tmp/icon.png" );
444 //iconw->Write();
445 //iconw->Delete();
446
447 }
448
449 //reader->GetIconImage()->Print( std::cout );
450
451 //vtkPropCollection *pc = vtkPropCollection::New();
452 //rep->GetActors2D(pc);
453 //balloonwidget->AddBalloon(pc->GetLastProp(),"This is a DICOM thumbnail image",NULL);
454
455 vtkLogoWidget *widget = vtkLogoWidget::New();
456 widget->SetInteractor(iren);
457 widget->SetRepresentation(rep);
458 iconwidget = widget;
459 //widget->Delete();
460 rep->Delete();
461
462 //viewer->AddInputConnection ( reader->GetIconImagePort() );
463 }
464 #endif
465 #else
466 viewer->SetInput( reader->GetOutput(0) );
467 if( reader->GetNumberOfOverlays() )
468 {
469 viewer->AddInput( reader->GetOverlay(0) );
470 }
471 #endif /*(VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION > 5 )*/
472
473 // IconImage:
474 //if( reader->GetNumberOfIconImages() )
475 // {
476 // std::cerr << "NumberOfIconImages:" << reader->GetNumberOfIconImages() << std::endl;
477 // reader->GetIconImage()->Print( std::cerr );
478 // vtkPNGWriter *writer = vtkPNGWriter::New();
479 // writer->SetInput( reader->GetIconImage() );
480 // writer->SetFileName( "icon.png" );
481 // //writer->Write();
482 // writer->Delete();
483 // }
484
485 // In case of palette color, let's tell VTK to map color:
486 // MONOCHROME1 is also implemented with a lookup table
487 if( reader->GetImageFormat() == VTK_LOOKUP_TABLE || reader->GetImageFormat() == VTK_INVERSE_LUMINANCE )
488 {
489 #if VTK_MAJOR_VERSION >= 6 || (VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0)
490 assert( reader->GetOutput()->GetPointData()->GetScalars()
491 && reader->GetOutput()->GetPointData()->GetScalars()->GetLookupTable() );
492 #endif
493 //convert to color:
494 vtkLookupTable *lut = reader->GetOutput()->GetPointData()->GetScalars()->GetLookupTable();
495 if( !lut )
496 {
497 // This must be a Segmented Palette and on VTK 4.4 this is not supported
498 std::cerr << "Not implemented. You will not see the Color LUT" << std::endl;
499 }
500 #if VTK_MAJOR_VERSION >= 6 || (VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0)
501 if( lut->IsA( "vtkLookupTable16" ) )
502 {
503 vtkImageMapToColors16 *map = vtkImageMapToColors16::New ();
504 #if VTK_MAJOR_VERSION >= 6
505 map->SetInputConnection (reader->GetOutputPort());
506 #else
507 map->SetInput (reader->GetOutput());
508 #endif
509 map->SetLookupTable (reader->GetOutput()->GetPointData()->GetScalars()->GetLookupTable());
510 if( reader->GetImageFormat() == VTK_LOOKUP_TABLE )
511 {
512 map->SetOutputFormatToRGB();
513 }
514 else if( reader->GetImageFormat() == VTK_INVERSE_LUMINANCE )
515 {
516 map->SetOutputFormatToLuminance();
517 }
518 map->Update();
519 map->GetOutput()->GetScalarRange(range);
520 #if VTK_MAJOR_VERSION >= 6
521 viewer->SetInputConnection( map->GetOutputPort() );
522 #else
523 viewer->SetInput( map->GetOutput() );
524 #endif
525 map->Delete();
526 }
527 else
528 #endif
529 {
530 vtkImageMapToColors *map = vtkImageMapToColors::New ();
531 #if VTK_MAJOR_VERSION >= 6
532 map->SetInputConnection (reader->GetOutputPort());
533 #else
534 map->SetInput (reader->GetOutput());
535 #endif
536 map->SetLookupTable (reader->GetOutput()->GetPointData()->GetScalars()->GetLookupTable());
537 if( reader->GetImageFormat() == VTK_LOOKUP_TABLE )
538 {
539 map->SetOutputFormatToRGB();
540 }
541 else if( reader->GetImageFormat() == VTK_INVERSE_LUMINANCE )
542 {
543 map->SetOutputFormatToLuminance();
544 }
545 map->Update();
546 map->GetOutput()->GetScalarRange(range);
547 #if VTK_MAJOR_VERSION >= 6
548 viewer->SetInputConnection( map->GetOutputPort() );
549 #else
550 viewer->SetInput( map->GetOutput() );
551 #endif
552 map->Delete();
553 }
554 }
555 else if( reader->GetImageFormat() == VTK_YBR )
556 {
557 #if VTK_MAJOR_VERSION >= 5
558 vtkImageYBRToRGB *filter = vtkImageYBRToRGB::New();
559 #if VTK_MAJOR_VERSION >= 6
560 filter->SetInputConnection( reader->GetOutputPort() );
561 #else
562 filter->SetInput( reader->GetOutput() );
563 #endif
564 filter->Update();
565 filter->GetOutput()->GetScalarRange(range);
566 #if VTK_MAJOR_VERSION >= 6
567 viewer->SetInputConnection( filter->GetOutputPort() );
568 #else
569 viewer->SetInput( filter->GetOutput() );
570 #endif
571 filter->Delete();
572 #else
573 std::cerr << "Not implemented" << std::endl;
574 #endif
575 }
576 else if( reader->GetImageFormat() == VTK_RGB
577 || reader->GetImageFormat() == VTK_RGBA )
578 {
579 // easy case !
580 }
581 // vtkImageShiftScale *ss = vtkImageShiftScale::New();
582 // ss->SetInput( reader->GetOutput() );
583 // ss->SetShift( -1024 );
584 // ss->SetOutputScalarTypeToShort();
585 // ss->Update();
586 // ss->GetOutput()->GetScalarRange(range);
587 // viewer->SetInput( ss->GetOutput() );
588 // ss->Delete();
589
590 if( reader->GetCurve() )
591 {
592 vtkPolyDataMapper2D * rectMapper = vtkPolyDataMapper2D::New();
593 #if VTK_MAJOR_VERSION >= 6
594 rectMapper->SetInputData( reader->GetCurve() );
595 #else
596 rectMapper->SetInput( reader->GetCurve() );
597 #endif
598
599 vtkActor2D * rectActor = vtkActor2D::New();
600 rectActor->SetMapper( rectMapper );
601 viewer->GetRenderer()->AddActor2D( rectActor );
602 rectActor->Delete();
603 rectMapper->Delete();
604 }
605
606 #if 0
607 vtkImageReslice * slicer = vtkImageReslice::New();
608 slicer->SetInput( reader->GetOutput() );
609 slicer->InterpolateOn();
610 //slicer->SetResliceAxesOrigin(0, 0, 0);
611 //slicer->SetResliceAxesOrigin( reader->GetImagePositionPatient() );
612 //slicer->SetResliceAxes( reader->GetDirectionCosines() );
613 const double *dircos = reader->GetImageOrientationPatient();
614 double dcos[9];
615 for(int i=0;i<6;++i)
616 dcos[i] = dircos[i];
617 dcos[6] = dircos[1] * dircos[5] - dircos[2] * dircos[4];
618 dcos[7] = dircos[2] * dircos[3] - dircos[0] * dircos[5];
619 dcos[8] = dircos[0] * dircos[4] - dircos[3] * dircos[1];
620 double dummy[3];
621 double dot = vtkMath::Dot(dircos, dircos+3);
622 std::cout << dot << std::endl;
623 vtkMath::Cross(dircos, dircos+3, dummy);
624 std::cout << dcos[6] << "," << dcos[7] << "," << dcos[8] << std::endl;
625 std::cout << dummy[0] << "," << dummy[1] << "," << dummy[2] << std::endl;
626 dot = vtkMath::Dot(dircos, dummy);
627 std::cout << dot << std::endl;
628 dot = vtkMath::Dot(dircos+3, dummy);
629 std::cout << dot << std::endl;
630 slicer->SetResliceAxesDirectionCosines(dcos);
631 slicer->Update();
632 slicer->GetOutput()->Print( std::cout );
633 //viewer->SetInput( slicer->GetOutput() );
634 vtkOutlineFilter * outline = vtkOutlineFilter::New();
635 outline->SetInput( slicer->GetOutput() );
636 outline->GetOutput()->Print( std::cout );
637 //slicer->AddInput( (vtkPolyData*)outline->GetOutput() );
638 #endif
639
640 // Always overwriting default is not always nice looking...
641 viewer->SetColorLevel (0.5 * (range[1] + range[0]));
642 viewer->SetColorWindow (range[1] - range[0]);
643 if( verbose )
644 std::cout << "Range: " << range[0] << " " << range[1] << std::endl;
645
646 viewer->SetupInteractor (iren);
647
648 // vtkInteractorStyleImage *is = viewer->GetInteractorStyle();
649 // viewer->GetInteractorStyle()->AutoAdjustCameraClippingRangeOn();
650 vtkCornerAnnotation * ca = vtkCornerAnnotation::New();
651 ca->SetImageActor( viewer->GetImageActor() );
652 ca->SetWindowLevel( (vtkImageMapToWindowLevelColors*)viewer->GetWindowLevel() );
653 vtkMedicalImageProperties * medprop = reader->GetMedicalImageProperties();
654 FillCornerFromMedProp( ca, medprop );
655 #if VTK_MAJOR_VERSION >= 5
656 viewer->GetRenderer()->AddViewProp( ca );
657 #else
658 viewer->GetRenderer()->AddProp( ca );
659 #endif
660
661 int dims[3];
662 reader->GetOutput()->GetDimensions(dims);
663 // Make sure to display on most screen
664 dims[0] = (dims[0] < 600 ) ? dims[0] : 600;
665 dims[1] = (dims[1] < 600 ) ? dims[1] : 600;
666 viewer->Render(); // EXTREMELY IMPORTANT for vtkImageViewer2
667 viewer->GetRenderer()->ResetCamera();
668
669 viewer->SetSize( dims );
670
671 // Here is where we setup the observer,
672 vtkGDCMObserver<TViewer> *obs = vtkGDCMObserver<TViewer>::New();
673 obs->ImageViewer = viewer;
674 #if VTK_MAJOR_VERSION >= 6 || (VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0)
675 if(iconwidget) iconwidget->On();
676 obs->IconWidget = iconwidget;
677 obs->DistanceWidget = dwidget;
678 obs->AngleWidget = anglewidget;
679 obs->BiDimWidget = bwidget;
680 obs->ContourWidget = contourWidget;
681 balloonwidget->On();
682 #endif
683 iren->AddObserver(vtkCommand::CharEvent,obs);
684 iren->AddObserver(vtkCommand::EndPickEvent,obs);
685 obs->Delete();
686
687 //vtkLegendScaleActor *legend = vtkLegendScaleActor::New();
688 //viewer->GetRenderer()->AddActor( legend );
689
690 iren->Initialize();
691 iren->Start();
692
693 //if you wish you can export dicom to a vtk file
694 #if 0
695 vtkXMLImageDataWriter *writer = vtkXMLImageDataWriter::New();
696 writer->SetInputConnection( reader->GetOutputPort());
697 writer->SetFileName( "debug.vtk" );
698 writer->SetDataModeToBinary();
699 writer->Write();
700 writer->Delete();
701 #endif
702
703 #if 0
704 vtkPNGWriter *writer = vtkPNGWriter::New();
705 //writer->SetInputConnection( reader->GetOutputPort() );
706 writer->SetInputConnection( reader->GetOutputPort(1) );
707 //range = overlay->GetScalarRange();
708 //std::cerr << "Range: " << range[0] << " " << range[1] << std::endl;
709 //overlay->Print( std::cout );
710 //writer->SetInput( overlay );
711 writer->SetFileName( "debug.png" );
712 writer->Write();
713 writer->Delete();
714 #endif
715
716 reader->Delete();
717 #if VTK_MAJOR_VERSION >= 6 || (VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION > 0)
718 cbk->Delete();
719 dwidget->Off();
720 balloonwidget->Off();
721 balloonwidget->Delete();
722 dwidget->Delete();
723 anglewidget->Off();
724 anglewidget->Delete();
725 bwidget->Off();
726 bwidget->Delete();
727 contourWidget->Off();
728 contourWidget->Delete();
729 if( iconwidget )
730 {
731 iconwidget->Off();
732 iconwidget->Delete();
733 }
734 #endif
735 iren->Delete();
736 viewer->Delete();
737 }
738
PrintVersion()739 void PrintVersion()
740 {
741 std::cout << "gdcmviewer: gdcm " << gdcm::Version::GetVersion() << " ";
742 const char date[] = "$Date$";
743 std::cout << date << std::endl;
744 //std::cout << " VTK " << vtkVersion::GetVTKVersion() << std::endl;
745 std::cout << " " << vtkVersion::GetVTKSourceVersion() << std::endl;
746 }
747
PrintHelp()748 void PrintHelp()
749 {
750 PrintVersion();
751 std::cout << "Usage: gdcmviewer [OPTION] filename1.dcm [filename2.dcm...]" << std::endl;
752 std::cout << "or : gdcmviewer [OPTION] directory" << std::endl;
753 std::cout << "Display a DICOM image file.\n";
754 std::cout << "Options:" << std::endl;
755 std::cout << " --force-rescale force rescale." << std::endl;
756 std::cout << " --force-spacing force spacing." << std::endl;
757 std::cout << " -r --recursive Recursively descend directory." << std::endl;
758 std::cout << "General Options:" << std::endl;
759 std::cout << " -V --verbose more verbose (warning+error)." << std::endl;
760 std::cout << " -W --warning print warning info." << std::endl;
761 std::cout << " -D --debug print debug info." << std::endl;
762 std::cout << " -E --error print error info." << std::endl;
763 std::cout << " -h --help print help." << std::endl;
764 std::cout << " -v --version print version." << std::endl;
765 }
766
767
main(int argc,char * argv[])768 int main(int argc, char *argv[])
769 {
770 int c;
771 //int digit_optind = 0;
772
773 std::vector<std::string> filenames;
774 int forcerescale = 0;
775 int forcespacing = 0;
776 int recursive = 0;
777
778 verbose = 0;
779 int warning = 0;
780 int debug = 0;
781 int error = 0;
782 int help = 0;
783 int version = 0;
784
785 while (1) {
786 //int this_option_optind = optind ? optind : 1;
787 int option_index = 0;
788 static struct option long_options[] = {
789 {"force-rescale", 0, &forcerescale, 1},
790 {"force-spacing", 0, &forcespacing, 1},
791 {"recursive", 0, &recursive, 1},
792
793 // General options !
794 {"verbose", 0, &verbose, 1},
795 {"warning", 0, &warning, 1},
796 {"debug", 0, &debug, 1},
797 {"error", 0, &error, 1},
798 {"help", 0, &help, 1},
799 {"version", 0, &version, 1},
800
801 {0, 0, 0, 0}
802 };
803
804 c = getopt_long (argc, argv, "rVWDEhv",
805 long_options, &option_index);
806 if (c == -1)
807 {
808 break;
809 }
810
811 switch (c)
812 {
813 case 0:
814 {
815 const char *s = long_options[option_index].name; (void)s;
816 //printf ("option %s", s);
817 if (optarg)
818 {
819 if( option_index == 0 ) /* input */
820 {
821 assert( strcmp(s, "input") == 0 );
822 //assert( filename.empty() );
823 //filename = optarg;
824 }
825 printf (" with arg %s", optarg);
826 }
827 //printf ("\n");
828 }
829 break;
830
831 case 'r':
832 recursive = 1;
833 break;
834
835 case 'V':
836 verbose = 1;
837 break;
838
839 case 'W':
840 warning = 1;
841 break;
842
843 case 'D':
844 debug = 1;
845 break;
846
847 case 'E':
848 error = 1;
849 break;
850
851 case 'h':
852 help = 1;
853 break;
854
855 case 'v':
856 version = 1;
857 break;
858
859 case '?':
860 break;
861
862 default:
863 printf ("?? getopt returned character code 0%o ??\n", c);
864 }
865 }
866
867 if (optind < argc)
868 {
869 //printf ("non-option ARGV-elements: ");
870 while (optind < argc)
871 {
872 //printf ("%s ", argv[optind]);
873 filenames.push_back( argv[optind++] );
874 }
875 //printf ("\n");
876 }
877
878 if( version )
879 {
880 //std::cout << "version" << std::endl;
881 PrintVersion();
882 return 0;
883 }
884
885 if( help )
886 {
887 //std::cout << "help" << std::endl;
888 PrintHelp();
889 return 0;
890 }
891
892 // Debug is a little too verbose
893 gdcm::Trace::SetDebug( debug );
894 gdcm::Trace::SetWarning( warning );
895 gdcm::Trace::SetError( error );
896 // when verbose is true, make sure warning+error are turned on:
897 if( verbose )
898 {
899 gdcm::Trace::SetWarning( verbose );
900 gdcm::Trace::SetError( verbose);
901 }
902
903 //vtkMultiThreader::SetGlobalMaximumNumberOfThreads(1);
904 gdcm::ImageHelper::SetForceRescaleInterceptSlope(forcerescale);
905 gdcm::ImageHelper::SetForcePixelSpacing(forcespacing);
906
907 if( filenames.empty() )
908 {
909 PrintHelp();
910 return 1;
911 }
912 gdcm::Reader testreader;
913 vtkStringArray *names = vtkStringArray::New();
914 {
915 // Is it a single directory ? If so loop over all files contained in it:
916 //const char *filename = argv[1];
917 if( filenames.size() == 1 && gdcm::System::FileIsDirectory( filenames[0].c_str() ) )
918 {
919 if( verbose )
920 std::cout << "Loading directory: " << filenames[0] << std::endl;
921 gdcm::Directory d;
922 d.Load(filenames[0].c_str(), recursive);
923 gdcm::Directory::FilenamesType const &files = d.GetFilenames();
924 for( gdcm::Directory::FilenamesType::const_iterator it = files.begin(); it != files.end(); ++it )
925 {
926 testreader.SetFileName( it->c_str() );
927 if( testreader.CanRead() )
928 {
929 names->InsertNextValue( it->c_str() );
930 }
931 else
932 {
933 if(verbose)
934 std::cerr << "Discarding non DICOM file: " << it->c_str() << std::endl;
935 }
936 }
937 }
938 else // list of files passed directly on the cmd line:
939 // discard non-existing or directory
940 {
941 //for(int i=1; i < argc; ++i)
942 for(std::vector<std::string>::const_iterator it = filenames.begin(); it != filenames.end(); ++it)
943 {
944 //filename = argv[i];
945 const std::string & filename = *it;
946 if( gdcm::System::FileExists( filename.c_str() ) )
947 {
948 if( gdcm::System::FileIsDirectory( filename.c_str() ) )
949 {
950 if(verbose)
951 std::cerr << "Discarding directory: " << filename << std::endl;
952 }
953 else
954 {
955 testreader.SetFileName( filename.c_str() );
956 if( testreader.CanRead() )
957 {
958 names->InsertNextValue( filename.c_str() );
959 }
960 else
961 {
962 if(verbose)
963 std::cerr << "Discarding non DICOM file: " << filename.c_str() << std::endl;
964 }
965 }
966 }
967 else
968 {
969 if(verbose)
970 std::cerr << "Discarding non existing file: " << filename << std::endl;
971 }
972 }
973 }
974 //names->Print( std::cout );
975 }
976
977 vtkImageColorViewer *viewer = vtkImageColorViewer::New();
978 ExecuteViewer<vtkImageColorViewer>(viewer, names);
979
980 names->Delete();
981
982 return 0;
983 }
984