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