]> Creatis software - cpMesh.git/blob - appli/InteractiveDeformableMeshSegmentation/MainWnd.cxx
bbb9080259e440d90b8cb61e27c95472e76b0bc4
[cpMesh.git] / appli / InteractiveDeformableMeshSegmentation / MainWnd.cxx
1 #include "MainWnd.h"
2 #include "ui_MainWnd.h"
3
4 #include <algorithm>
5 #include <cctype>
6 #include <fstream>
7
8 #include <QFileDialog>
9 #include <QMessageBox>
10
11 #include <vtkAnnotatedCubeActor.h>
12 #include <vtkAxesActor.h>
13 #include <vtkPropAssembly.h>
14 #include <vtkProperty.h>
15 #include <vtkRenderWindow.h>
16
17 #include <cpPlugins/Interface/Image.h>
18
19 // -------------------------------------------------------------------------
20 #define IDMS_QT_ACTION( name )                                         \
21   QObject::connect(                                                    \
22     this->m_UI->action##name, SIGNAL( triggered( ) ),                  \
23     this, SLOT( _triggered_action##name( ) )                           \
24     )
25
26 // -------------------------------------------------------------------------
27 MainWnd::MainWnd( QWidget* parent )
28   : QMainWindow( parent ),
29     m_UI( new Ui::MainWnd ),
30     m_InputImage( NULL ),
31     m_SegmentedImage( NULL )
32 {
33   this->m_UI->setupUi( this );
34
35   // Configuration files
36   this->m_ApplicationPreferencesFile = "idms.config";
37   this->m_PluginsConfigurationFile = "idms.plugins";
38   this->_LoadApplicationPreferences( );
39
40   // Create and associate renderers
41   this->m_3DRenderer = vtkSmartPointer< vtkRenderer >::New( );
42   this->m_XPlaneRenderer = vtkSmartPointer< vtkRenderer >::New( );
43   this->m_YPlaneRenderer = vtkSmartPointer< vtkRenderer >::New( );
44   this->m_ZPlaneRenderer = vtkSmartPointer< vtkRenderer >::New( );
45   this->m_AuxRenderer = vtkSmartPointer< vtkRenderer >::New( );
46   this->m_3DRenderer->SetBackground( 0.2, 0.2, 0.2 );
47   this->m_XPlaneRenderer->SetBackground( 0.1, 0.3, 0.8 );
48   this->m_YPlaneRenderer->SetBackground( 0.1, 0.3, 0.8 );
49   this->m_ZPlaneRenderer->SetBackground( 0.1, 0.3, 0.8 );
50   this->m_AuxRenderer->SetBackground( 0.1, 0.3, 0.8 );
51   this->m_UI->m_3DVTK->GetRenderWindow( )->
52     AddRenderer( this->m_3DRenderer );
53   this->m_UI->m_XPlaneVTK->GetRenderWindow( )->
54     AddRenderer( this->m_XPlaneRenderer );
55   this->m_UI->m_YPlaneVTK->GetRenderWindow( )->
56     AddRenderer( this->m_YPlaneRenderer );
57   this->m_UI->m_ZPlaneVTK->GetRenderWindow( )->
58     AddRenderer( this->m_ZPlaneRenderer );
59   this->m_UI->m_AuxVTK->GetRenderWindow( )->
60     AddRenderer( this->m_AuxRenderer );
61
62   // Configure MPR actors
63   this->m_ImageActors = vtkSmartPointer< idms::VolumeActors >::New( );
64
65   // Interaction styles
66   this->m_XStyle = vtkSmartPointer< idms::InteractorStyleImage >::New( );
67   this->m_YStyle = vtkSmartPointer< idms::InteractorStyleImage >::New( );
68   this->m_ZStyle = vtkSmartPointer< idms::InteractorStyleImage >::New( );
69   this->m_XStyle->Configure( this->m_ImageActors, 0 );
70   this->m_YStyle->Configure( this->m_ImageActors, 1 );
71   this->m_ZStyle->Configure( this->m_ImageActors, 2 );
72   this->m_UI->m_XPlaneVTK->GetInteractor( )->
73     SetInteractorStyle( this->m_XStyle );
74   this->m_UI->m_YPlaneVTK->GetInteractor( )->
75     SetInteractorStyle( this->m_YStyle );
76   this->m_UI->m_ZPlaneVTK->GetInteractor( )->
77     SetInteractorStyle( this->m_ZStyle );
78
79   // Orientation marks
80   vtkSmartPointer< vtkAnnotatedCubeActor > oCube =
81     vtkSmartPointer< vtkAnnotatedCubeActor >::New( );
82   oCube->GetCubeProperty( )->SetColor( 0.9, 0.7, 0.2 );
83   oCube->GetTextEdgesProperty( )->SetLineWidth( 1 );
84   oCube->GetTextEdgesProperty( )->SetDiffuse( 0 );
85   oCube->GetTextEdgesProperty( )->SetAmbient( 1 );
86   oCube->GetTextEdgesProperty( )->SetColor( 0.18, 0.28, 0.23 );
87   oCube->GetXPlusFaceProperty( )->SetColor( 1, 0, 0 );
88   oCube->GetXPlusFaceProperty( )->SetInterpolationToFlat( );
89   oCube->GetXMinusFaceProperty( )->SetColor( 1, 0, 0 );
90   oCube->GetXMinusFaceProperty( )->SetInterpolationToFlat( );
91   oCube->GetYPlusFaceProperty( )->SetColor( 0, 1, 0 );
92   oCube->GetYPlusFaceProperty( )->SetInterpolationToFlat( );
93   oCube->GetYMinusFaceProperty( )->SetColor( 0, 1, 0 );
94   oCube->GetYMinusFaceProperty( )->SetInterpolationToFlat( );
95   oCube->GetZPlusFaceProperty( )->SetColor( 0, 0, 1 );
96   oCube->GetZPlusFaceProperty( )->SetInterpolationToFlat( );
97   oCube->GetZMinusFaceProperty( )->SetColor( 0, 0, 1 );
98   oCube->GetZMinusFaceProperty( )->SetInterpolationToFlat( );
99
100   vtkSmartPointer< vtkAxesActor > oAxes =
101     vtkSmartPointer< vtkAxesActor >::New( );
102   oAxes->AxisLabelsOff( );
103   oAxes->SetShaftTypeToCylinder( );
104   oAxes->SetTotalLength( 2.5, 2.5, 2.5 );
105
106   vtkSmartPointer< vtkPropAssembly > oActors =
107     vtkSmartPointer< vtkPropAssembly >::New( );
108   oActors->AddPart( oCube );
109   oActors->AddPart( oAxes );
110
111   this->m_3DOrientationWidget =
112     vtkSmartPointer< vtkOrientationMarkerWidget >::New( );
113   this->m_3DOrientationWidget->SetOutlineColor( 0.93, 0.57, 0.13 );
114   this->m_3DOrientationWidget->SetOrientationMarker( oActors );
115   this->m_3DOrientationWidget->SetViewport( 0.0, 0.0, 0.2, 0.2 );
116
117   // Add actors, widgets, stuff, ...
118   this->m_3DOrientationWidget->
119     SetInteractor( this->m_UI->m_3DVTK->GetInteractor( ) );
120   this->m_3DOrientationWidget->SetEnabled( 1 );
121   this->m_3DOrientationWidget->InteractiveOff( );
122
123   // Qt signals <-> slots
124   IDMS_QT_ACTION( ReloadPlugins );
125   IDMS_QT_ACTION( OpenInputImage );
126   IDMS_QT_ACTION( OpenSegmentedImage );
127   QObject::connect(
128     this->m_UI->actionNavigation, SIGNAL( triggered( ) ),
129     this, SLOT( _triggered_actionSwitchMode( ) )
130     );
131   QObject::connect(
132     this->m_UI->actionSegmentationInteractiveDeformation,
133     SIGNAL( triggered( ) ),
134     this, SLOT( _triggered_actionSwitchMode( ) )
135     );
136
137   // Historic configuration
138   this->m_LastOpenedFile = ".";
139
140   // Start: load all disponible plugins
141   this->_triggered_actionReloadPlugins( );
142 }
143
144 // -------------------------------------------------------------------------
145 MainWnd::
146 ~MainWnd( )
147 {
148   // Close all connections
149   this->m_Plugins.UnloadAll( );
150
151   // Delete objects
152   delete this->m_UI;
153   if( this->m_InputImage != NULL ) delete this->m_InputImage;
154   if( this->m_SegmentedImage != NULL ) delete this->m_SegmentedImage;
155 }
156
157 // -------------------------------------------------------------------------
158 void MainWnd::
159 _LoadApplicationPreferences( )
160 {
161   this->m_ApplicationPreferences.clear( );
162   std::ifstream in( this->m_ApplicationPreferencesFile.c_str( ) );
163   if( in )
164   {
165     std::string line;
166     std::getline( in, line );
167     while( !( in.eof( ) ) )
168     {
169       long pos = line.find_last_of( "=" );
170       std::string key = line.substr( 0, pos );
171       std::string value = line.substr( pos + 1 );
172       key.erase(
173         std::remove_if( key.begin( ), key.end( ), isspace ), key.end( )
174         );
175       value.erase(
176         std::remove_if( value.begin( ), value.end( ), isspace ), value.end( )
177         );
178       this->m_ApplicationPreferences[ key ] = value;
179       std::getline( in, line );
180
181     } // elihw
182   }
183   else
184   {
185     this->m_ApplicationPreferences[ "data_dimensions" ] = "3";
186     this->m_ApplicationPreferences[ "input_image_type" ]  = "short";
187     this->m_ApplicationPreferences[ "segmented_image_type" ]  = "uchar";
188     this->m_ApplicationPreferences[ "mesh_type" ]  = "double";
189
190   } // fi
191   in.close( );
192 }
193
194 // -------------------------------------------------------------------------
195 MainWnd::
196 TPluginData* MainWnd::
197 _LoadImage( const std::string& image_type, const std::string& image_dim )
198 {
199 /*
200   // Show dialog and check if it was accepted
201   QFileDialog dialog( this );
202   dialog.setFileMode( QFileDialog::ExistingFiles );
203   dialog.setDirectory( tr( this->m_LastOpenedFile.c_str( ) ) );
204   dialog.setNameFilter(
205     tr( "Medical image files (*.mhd *.bin *.dcm);;All files (*)" )
206     );
207   dialog.setDefaultSuffix( tr( "mhd" ) );
208   if( !( dialog.exec( ) ) )
209     return( NULL );
210
211   TPluginData* ret = NULL;
212   unsigned int nFiles = dialog.selectedFiles( ).size( );
213   if( nFiles == 1 )
214   {
215     if( this->m_ImageReaderClassName == "" )
216     {
217       QMessageBox::critical(
218         this,
219         tr( "No plugin to read a single image file found!" ),
220         tr( "No plugin to read a single image file found!" )
221         );
222       return( ret );
223
224     } // fi
225
226     std::string fname = dialog.selectedFiles( ).at( 0 ).toStdString( );
227     this->m_LastOpenedFile = fname;
228
229     TPlugin* reader =
230       dynamic_cast< TPlugin* >(
231       this->m_Plugins.CreateObject( this->m_ImageReaderClassName )
232         );
233
234     TParameters reader_params = reader->GetDefaultParameters( );
235     reader_params[ "FileName" ].second = fname;
236     reader_params[ "PixelType" ].second = image_type;
237     reader_params[ "ImageDimension" ].second = image_dim;
238     reader_params[ "IsColorImage" ].second = "0";
239     reader->SetParameters( reader_params );
240     std::string err = reader->Update( );
241
242     if( err == "" )
243     {
244       ret = reader->GetOutput( 0 );
245       reader->DisconnectOutputs( );
246     }
247     else
248       QMessageBox::critical(
249         this,
250         tr( "Error reading single image" ),
251         tr( err.c_str( ) )
252         );
253     delete reader;
254     return( ret );
255   }
256   else if( nFiles > 1 )
257   {
258     if( this->m_ImageSeriesReaderClassName == "" )
259     {
260       QMessageBox::critical(
261         this,
262         tr( "No plugin to read an image series found!" ),
263         tr( "No plugin to read an image series found!" )
264         );
265       return( ret );
266
267     } // fi
268        std::string fname = dialog.selectedFiles( ).at( 0 ).toStdString( );
269        this->m_LastOpenedFile = fname;
270     return( ret );
271
272   } // fi
273   return( ret );
274 */
275 }
276
277 // -------------------------------------------------------------------------
278 void MainWnd::
279 _UpdateEnabledFlags( )
280 {
281   bool img = ( this->m_InputImage != NULL );
282   this->m_UI->menuSegmentInputImage->setEnabled( img );
283   this->m_UI->actionOpenSegmentedImage->setEnabled( img );
284   this->m_UI->m_3DVTK->setEnabled( img );
285   this->m_UI->m_XPlaneVTK->setEnabled( img );
286   this->m_UI->m_YPlaneVTK->setEnabled( img );
287   this->m_UI->m_ZPlaneVTK->setEnabled( img );
288   this->m_UI->m_AuxVTK->setEnabled( img );
289
290   /* TODO
291      bool seg = this->m_Segmentation.IsNotNull( );
292      this->m_UI->menuFilterSegmentedImage->setEnabled( seg );
293      this->m_UI->menuExtractMesh->setEnabled( seg );
294      this->m_UI->actionOpenMesh->setEnabled( seg );
295
296      this->m_UI->actionNavigation->setEnabled( img && seg );
297      this->m_UI->actionSegmentationInteractiveDeformation->
298      setEnabled( img && seg );
299   */
300 }
301
302 // -------------------------------------------------------------------------
303 void MainWnd::
304 _triggered_actionReloadPlugins( )
305 {
306   if( this->_LoadPlugins( ) )
307   {
308     this->_UpdateEnabledFlags( );
309   }
310   else
311   {
312     QMessageBox::critical(
313       this,
314       tr( "Could not load plugins from given file." ),
315       tr( "Could not load plugins from given file." )
316       );
317
318   } // fi
319   /*
320     this->m_Plugins.UnloadAll( );
321
322     this->m_ImageReaderClassName = "";
323     this->m_ImageSeriesReaderClassName = "";
324     this->m_ImageWriterClassName = "";
325
326     std::ifstream in( this->m_PluginsConfigurationFile.c_str( ) );
327     if( in )
328     {
329     std::string plugin;
330     std::getline( in, plugin );
331     while( !( in.eof( ) ) )
332     {
333     if( this->m_Plugins.Load( plugin ) )
334     {
335     TPluginsInterface::TClassesIterator cIt =
336     this->m_Plugins.GetClasses( ).begin( );
337     TPluginsInterface::TClassesIterator end_cIt =
338     this->m_Plugins.GetClasses( ).end( );
339     for( ; cIt != end_cIt; ++cIt )
340     {
341     std::string c_name = cIt->first;
342     c_name = c_name.substr( c_name.find_last_of( ":" ) + 1 );
343     if( c_name == "ImageReader" )
344     {
345             this->m_ImageReaderClassName = cIt->first;
346           }
347           else if( c_name == "ImageSeriesReader" )
348           {
349             this->m_ImageSeriesReaderClassName = cIt->first;
350           }
351           else if( c_name == "ImageWriter" )
352           {
353             this->m_ImageWriterClassName = cIt->first;
354           }
355           else
356           {
357           } // fi
358           
359         } // rof
360
361            TFilterPlugins::TClassesIterator cIt =
362            this->m_Plugins.BeginClasses( );
363            for( ; cIt != this->m_Plugins.EndClasses( ); ++cIt )
364            {
365            TFilterObject* filter =
366            this->m_Plugins.CreateObject( cIt->first );
367            if( filter == NULL )
368            continue;
369            std::string cat = filter->GetCategory( );
370            std::string catType = cat.substr( cat.find_last_of( ":" ) );
371            if( catType == ":BinaryImageToBinaryImageFilter" )
372            {
373            QAction* action = this->m_UI->menuFilterSegmentedImage->
374            addAction( QString( cIt->first.c_str( ) ) );
375            QObject::connect(
376            action, SIGNAL( triggered( ) ),
377            this, SLOT( triggered_aFilterSegmentedImage( ) )
378            );
379            }
380            else if( catType == ":ImageToMeshFilter" )
381            {
382            QAction* action = this->m_UI->menuExtractMesh->
383            addAction( QString( cIt->first.c_str( ) ) );
384            QObject::connect(
385            action, SIGNAL( triggered( ) ),
386            this, SLOT( triggered_aSegmentedImageToMesh( ) )
387            );
388
389            } // fi
390            delete filter;
391            } // rof
392       }
393       else
394       {
395         QMessageBox::warning(
396           this,
397           tr( "Ignoring plugin" ),
398           tr( plugin.c_str( ) )
399           );
400
401       } // fi
402       std::getline( in, plugin );
403
404     } // elihw
405   }
406   else
407   {
408     QMessageBox::critical(
409       this,
410       tr( "No plugins file loaded!" ),
411       tr( this->m_PluginsConfigurationFile.c_str( ) )
412       );
413
414   } // fi
415   in.close( );
416
417   if( this->m_ImageReaderClassName == "" )
418   {
419     QMessageBox::critical(
420       this,
421       tr( "No ImageReader found in plugins!" ),
422       tr( this->m_PluginsConfigurationFile.c_str( ) )
423       );
424
425   } // fi
426
427   if( this->m_ImageWriterClassName == "" )
428   {
429     QMessageBox::critical(
430       this,
431       tr( "No ImageWriter found in plugins!" ),
432       tr( this->m_PluginsConfigurationFile.c_str( ) )
433       );
434
435   } // fi
436   this->_UpdateEnabledFlags( );
437   */
438 }
439
440 // -------------------------------------------------------------------------
441 void MainWnd::
442 _triggered_actionOpenInputImage( )
443 {
444   if( this->m_InputImage != NULL )
445     delete this->m_InputImage;
446   this->m_InputImage =
447     this->_LoadImage(
448       this->m_ApplicationPreferences[ "input_image_type" ],
449       this->m_ApplicationPreferences[ "data_dimensions" ]
450       );
451   if( this->m_InputImage != NULL )
452   {
453     cpPlugins::Interface::Image* img = 
454       dynamic_cast< cpPlugins::Interface::Image* >( this->m_InputImage );
455     this->m_ImageActors->Configure(
456       img->GetVTKImageData( ),
457       this->m_UI->m_XPlaneVTK->GetInteractor( ),
458       this->m_UI->m_YPlaneVTK->GetInteractor( ),
459       this->m_UI->m_ZPlaneVTK->GetInteractor( )
460       );
461     this->m_ImageActors->
462       AddAuxiliaryInteractor( this->m_UI->m_3DVTK->GetInteractor( ) );
463
464     // Associate actors
465     this->m_3DRenderer->AddActor(
466       this->m_ImageActors->GetImageOutlineActor( )
467       );
468     this->m_3DRenderer->AddActor(
469       this->m_ImageActors->GetXBoundsActor( )
470       );
471     this->m_3DRenderer->AddActor(
472       this->m_ImageActors->GetYBoundsActor( )
473       );
474     this->m_3DRenderer->AddActor(
475       this->m_ImageActors->GetZBoundsActor( )
476       );
477
478     // Reset all cameras
479     this->m_3DRenderer->ResetCamera( );
480     this->m_ImageActors->ResetCameras( );
481
482     // Ok, start!
483     this->m_UI->m_3DVTK->GetRenderWindow( )->Render( );
484     this->m_UI->m_XPlaneVTK->GetRenderWindow( )->Render( );
485     this->m_UI->m_YPlaneVTK->GetRenderWindow( )->Render( );
486     this->m_UI->m_ZPlaneVTK->GetRenderWindow( )->Render( );
487
488     // Update activations
489     this->_UpdateEnabledFlags( );
490     this->m_UI->actionNavigation->setChecked( true );
491     this->_triggered_actionSwitchMode( );
492
493   } // fi
494 }
495
496 // -------------------------------------------------------------------------
497 void MainWnd::
498 _triggered_actionOpenSegmentedImage( )
499 {
500   if( this->m_SegmentedImage != NULL )
501     delete this->m_SegmentedImage;
502   this->m_SegmentedImage =
503     this->_LoadImage(
504       this->m_ApplicationPreferences[ "segmented_image_type" ],
505       this->m_ApplicationPreferences[ "data_dimensions" ]
506       );
507   if( this->m_SegmentedImage != NULL )
508   {
509     cpPlugins::Interface::Image* img = 
510       dynamic_cast< cpPlugins::Interface::Image* >( this->m_SegmentedImage );
511     this->m_ImageActors->SetSegmentation( img->GetVTKImageData( ) );
512
513     // Ok, start!
514     this->m_UI->m_XPlaneVTK->GetRenderWindow( )->Render( );
515     this->m_UI->m_YPlaneVTK->GetRenderWindow( )->Render( );
516     this->m_UI->m_ZPlaneVTK->GetRenderWindow( )->Render( );
517     this->_UpdateEnabledFlags( );
518
519   } // fi
520 }
521
522 // -------------------------------------------------------------------------
523 void MainWnd::
524 _triggered_actionSwitchMode( )
525 {
526   QAction* snd = dynamic_cast< QAction* >( this->sender( ) );
527   if( snd == this->m_UI->actionNavigation )
528   {
529     this->m_UI->actionSegmentationInteractiveDeformation->setChecked(
530       !( this->m_UI->actionNavigation->isChecked( ) )
531       );
532   }
533   else if( snd == this->m_UI->actionSegmentationInteractiveDeformation )
534   {
535     this->m_UI->actionNavigation->setChecked(
536       !( this->m_UI->actionSegmentationInteractiveDeformation->isChecked( ) )
537       );
538   }
539   else
540   {
541     this->m_UI->actionNavigation->setChecked( true );
542     this->m_UI->actionSegmentationInteractiveDeformation->setChecked( false );
543
544   } // fi
545
546   /* TODO
547      if( this->m_UI->aNavigation->isChecked( ) )
548      {
549      this->m_XStyle->SetModeToNavigation( );
550      this->m_YStyle->SetModeToNavigation( );
551      this->m_ZStyle->SetModeToNavigation( );
552      this->m_ImageActors->HideRegion( 0 );
553      this->m_ImageActors->HideRegion( 1 );
554      this->m_ImageActors->HideRegion( 2 );
555      this->m_3DRenderer->RemoveActor(
556      this->m_ImageActors->GetCursorActor( )
557      );
558      this->m_3DRenderer->RemoveActor(
559      this->m_ImageActors->GetRegionActor( )
560      );
561      this->m_UI->m_3DVTK->GetRenderWindow( )->Render( );
562      }
563      else if( this->m_UI->aSegmentationInteractiveDeformation->isChecked( ) )
564      {
565      this->m_XStyle->SetModeToDeformation( );
566      this->m_YStyle->SetModeToDeformation( );
567      this->m_ZStyle->SetModeToDeformation( );
568      this->m_ImageActors->ShowRegion( 0 );
569      this->m_ImageActors->ShowRegion( 1 );
570      this->m_ImageActors->ShowRegion( 2 );
571      this->m_3DRenderer->AddActor(
572      this->m_ImageActors->GetCursorActor( )
573      );
574      this->m_3DRenderer->AddActor(
575      this->m_ImageActors->GetRegionActor( )
576      );
577      this->m_UI->m_3DVTK->GetRenderWindow( )->Render( );
578
579      } // fi
580   */
581 }
582
583 // -------------------------------------------------------------------------
584 /* TODO
585
586 // -------------------------------------------------------------------------
587 bool MainWnd::
588 _ParametersDialog( TParameters& parameters )
589 {
590   QDialog dlg( this );
591   QGridLayout gridLayout( &dlg );
592   QVBoxLayout verticalLayout;
593
594   // Put values
595   typedef std::map< std::string, QWidget* > _TWidgets;
596   _TWidgets widgets;
597   TParameters::const_iterator pIt = parameters.begin( );
598   for( ; pIt != parameters.end( ); ++pIt )
599   {
600     unsigned long pos = pIt->first.find_last_of( ":" );
601     std::string v_name = pIt->first.substr( 0, pos );
602     std::string v_type = pIt->first.substr( pos + 1 );
603
604     QHBoxLayout* horizontalLayout = new QHBoxLayout( );
605     QLabel* label = new QLabel( &dlg );
606     label->setText( QString( v_name.c_str( ) ) );
607     horizontalLayout->addWidget( label );
608     if( v_type == "real" )
609     {
610       QDoubleSpinBox* v_double = new QDoubleSpinBox( &dlg );
611       v_double->setDecimals( 3 );
612       v_double->setMinimum( -( std::numeric_limits< double >::max( ) ) );
613       v_double->setMaximum( std::numeric_limits< double >::max( ) );
614       v_double->setValue( std::atof( pIt->second.c_str( ) ) );
615       horizontalLayout->addWidget( v_double );
616       widgets[ pIt->first ] = v_double;
617     }
618     else if( v_type == "atomic_real" )
619     {
620       if( v_name == "MeshType" )
621       {
622         QLabel* info = new QLabel( &dlg );
623         if( typeid( TScalar ) == typeid( float ) )
624           info->setText( QString( "float" ) );
625         else if( typeid( TScalar ) == typeid( double ) )
626           info->setText( QString( "double" ) );
627         horizontalLayout->addWidget( info );
628         widgets[ pIt->first ] = info;
629
630       } // fi
631
632     } // fi
633     verticalLayout.addLayout( horizontalLayout );
634
635   } // rof
636   gridLayout.addLayout( &verticalLayout, 0, 0, 1, 1 );
637
638   // Buttons box
639   QDialogButtonBox buttonBox( &dlg );
640   buttonBox.setOrientation( Qt::Horizontal );
641   buttonBox.setStandardButtons(
642     QDialogButtonBox::Cancel | QDialogButtonBox::Ok
643     );
644   gridLayout.addWidget( &buttonBox, 1, 0, 1, 1 );
645   QObject::connect(
646     &buttonBox, SIGNAL( accepted( ) ),
647     &dlg, SLOT( accept( ) )
648     );
649   QObject::connect(
650     &buttonBox, SIGNAL( rejected( ) ),
651     &dlg, SLOT( reject( ) )
652     );
653   QMetaObject::connectSlotsByName( &dlg );
654
655   // Execute dialog
656   if( dlg.exec( ) == QDialog::Accepted )
657   {
658     _TWidgets::const_iterator wIt = widgets.begin( );
659     for( ; wIt != widgets.end( ); ++wIt )
660     {
661       unsigned long pos = wIt->first.find_last_of( ":" );
662       std::string v_name = wIt->first.substr( 0, pos );
663       std::string v_type = wIt->first.substr( pos + 1 );
664       std::stringstream sstr;
665       if( v_type == "real" )
666       {
667         QDoubleSpinBox* v_double =
668           dynamic_cast< QDoubleSpinBox* >( wIt->second );
669         if( v_double != NULL )
670           sstr << v_double->value( );
671       }
672       else if( v_type == "atomic_real" )
673       {
674         if( v_name == "MeshType" )
675         {
676           QLabel* info = dynamic_cast< QLabel* >( wIt->second );
677           if( info != NULL )
678             sstr << info->text( ).toStdString( );
679
680         } // fi
681
682       } // fi
683       parameters[ wIt->first ] = sstr.str( );
684
685     } // rof
686     return( true );
687   }
688   return( false );
689   }
690
691   // -------------------------------------------------------------------------
692   template< class I >
693   bool MainWnd::
694   _LoadImage( typename I::Pointer& image )
695   {
696   QStringList qList =
697   QFileDialog::getOpenFileNames(
698   this,
699   tr( "Open an image" ),
700   tr( this->m_LastOpenedFile.c_str( ) ),
701   tr( "Medical image files (*.mhd *.bin *.dcm);;All files (*)" )
702   );
703   if( qList.size( ) == 0 )
704   return( false );
705
706   bool ret = true;
707   QStringList::Iterator fIt = qList.begin( );
708   if( qList.size( ) == 1 )
709   {
710   // Read a single image
711   std::string fn = fIt->toStdString( );
712   this->m_LastOpenedFile = fn;
713
714   typename itk::ImageFileReader< I >::Pointer reader =
715   itk::ImageFileReader< I >::New( );
716   reader->SetFileName( fn );
717   try
718   {
719   reader->Update( );
720   }
721   catch( itk::ExceptionObject& err )
722   {
723   QMessageBox::critical(
724   this,
725   tr( "Error opening single image!" ),
726   tr( err.GetDescription( ) )
727   );
728   ret = false;
729
730   } // yrt
731   image = reader->GetOutput( );
732   image->DisconnectPipeline( );
733   }
734   else if( qList.size( ) > 1 )
735   {
736   typedef std::set< std::string > _TOrderedStringList;
737
738   // Read a slice set
739   _TOrderedStringList filenames;
740   for( ; fIt != qList.end( ); ++fIt )
741   filenames.insert( fIt->toStdString( ) );
742   typename itk::ImageSeriesReader< I >::Pointer reader =
743   itk::ImageSeriesReader< I >::New( );
744   reader->SetImageIO( itk::GDCMImageIO::New( ) );
745   _TOrderedStringList::const_iterator oIt = filenames.begin( );
746   for( ; oIt != filenames.end( ); ++oIt )
747   {
748   reader->AddFileName( *oIt );
749   this->m_LastOpenedFile = *oIt;
750
751   } // rof
752   try
753   {
754   reader->Update( );
755   }
756   catch( itk::ExceptionObject& err )
757   {
758   QMessageBox::critical(
759   this,
760   tr( "Error opening image series!" ),
761   tr( err.GetDescription( ) )
762   );
763   ret = false;
764
765   } // yrt
766   image = reader->GetOutput( );
767   image->DisconnectPipeline( );
768
769   } // fi
770   return( ret );
771   }
772
773 // -------------------------------------------------------------------------
774 void MainWnd::
775 triggered_aReloadPlugins( )
776 {
777 }
778
779 // -------------------------------------------------------------------------
780 void MainWnd::
781 triggered_aOpenInputImage( )
782 {
783   if( this->_LoadImage< TImage >( this->m_Image ) )
784   {
785     // Connect image to VTK
786     this->m_VTKImage = TVTKImage::New( );
787     this->m_VTKImage->SetInput( this->m_Image );
788     this->m_VTKImage->Update( );
789
790     this->m_ImageActors->Configure(
791       this->m_VTKImage->GetOutput( ),
792       this->m_UI->m_XPlaneVTK->GetInteractor( ),
793       this->m_UI->m_YPlaneVTK->GetInteractor( ),
794       this->m_UI->m_ZPlaneVTK->GetInteractor( )
795       );
796     this->m_ImageActors->
797       AddAuxiliaryInteractor( this->m_UI->m_3DVTK->GetInteractor( ) );
798
799     // Associate actors
800     this->m_3DRenderer->AddActor(
801       this->m_ImageActors->GetImageOutlineActor( )
802       );
803     this->m_3DRenderer->AddActor(
804       this->m_ImageActors->GetXBoundsActor( )
805       );
806     this->m_3DRenderer->AddActor(
807       this->m_ImageActors->GetYBoundsActor( )
808       );
809     this->m_3DRenderer->AddActor(
810       this->m_ImageActors->GetZBoundsActor( )
811       );
812
813     // Reset all cameras
814     this->m_3DRenderer->ResetCamera( );
815     this->m_ImageActors->ResetCameras( );
816
817     // Ok, start!
818     this->m_UI->m_3DVTK->GetRenderWindow( )->Render( );
819     this->m_UI->m_XPlaneVTK->GetRenderWindow( )->Render( );
820     this->m_UI->m_YPlaneVTK->GetRenderWindow( )->Render( );
821     this->m_UI->m_ZPlaneVTK->GetRenderWindow( )->Render( );
822     this->_UpdateEnabledFlags( );
823     this->m_UI->aNavigation->setChecked( true );
824     this->triggered_aSwitchMode( );
825
826   } // fi
827 }
828
829 // -------------------------------------------------------------------------
830 void MainWnd::
831 triggered_aOpenSegmentedImage( )
832 {
833   if( this->_LoadImage< TImage >( this->m_Segmentation ) )
834   {
835     // Connect image to VTK
836     this->m_VTKSegmentation = TVTKImage::New( );
837     this->m_VTKSegmentation->SetInput( this->m_Segmentation );
838     this->m_VTKSegmentation->Update( );
839
840     this->m_ImageActors->SetSegmentation(
841       this->m_VTKSegmentation->GetOutput( )
842       );
843
844     // Ok, start!
845     this->m_UI->m_XPlaneVTK->GetRenderWindow( )->Render( );
846     this->m_UI->m_YPlaneVTK->GetRenderWindow( )->Render( );
847     this->m_UI->m_ZPlaneVTK->GetRenderWindow( )->Render( );
848     this->_UpdateEnabledFlags( );
849
850   } // fi
851 }
852
853 // -------------------------------------------------------------------------
854 void MainWnd::
855 triggered_aFilterSegmentedImage( )
856 {
857   // Get filter name
858   if( this->m_Segmentation.IsNull( ) )
859     return;
860   QAction* action = dynamic_cast< QAction* >( this->sender( ) );
861   if( action == NULL )
862     return;
863   std::string filter_name = action->text( ).toStdString( );
864
865   // Create filter
866   TFilterObject* filter = this->m_Plugins.CreateObject( filter_name );
867   if( filter == NULL )
868     return;
869
870   TParameters parameters = filter->GetDefaultParameters( );
871   if( !( this->_ParametersDialog( parameters ) ) )
872     return;
873   filter->SetInput( this->m_Segmentation );
874   filter->SetParameters( parameters );
875   std::string result = filter->Update( );
876
877   // Get modified segmentation
878      this->m_Mesh = filter->GetCastedOutput< TMesh >( );
879      if( this->m_Mesh.IsNotNull( ) )
880      {
881      this->m_Mesh->DisconnectPipeline( );
882
883      } // fi
884   // Ok, it seems to have runned fine
885   delete filter;
886 }
887
888 // -------------------------------------------------------------------------
889 void MainWnd::
890 triggered_aSegmentedImageToMesh( )
891 {
892   // Get filter name
893   if( this->m_Segmentation.IsNull( ) )
894     return;
895   QAction* action = dynamic_cast< QAction* >( this->sender( ) );
896   if( action == NULL )
897     return;
898   std::string filter_name = action->text( ).toStdString( );
899
900   // Create filter
901   TFilterObject* filter = this->m_Plugins.CreateObject( filter_name );
902   if( filter == NULL )
903     return;
904
905   TParameters parameters = filter->GetDefaultParameters( );
906   if( !( this->_ParametersDialog( parameters ) ) )
907     return;
908   filter->SetInput( this->m_Segmentation );
909   filter->SetParameters( parameters );
910   std::string result = filter->Update( );
911
912   // Get mesh
913   this->m_Mesh = filter->GetCastedOutput< TMesh >( );
914   if( this->m_Mesh.IsNotNull( ) )
915   {
916     this->m_Mesh->DisconnectPipeline( );
917
918   } // fi
919
920   // Ok, it seems to have runned fine
921   delete filter;
922 }
923 */
924
925 // -------------------------------------------------------------------------
926 /*
927   void MainWnd::
928   _SliceMesh( int axis )
929   {
930   TCutter* cutter = NULL;
931   if( axis == 2 ) cutter = this->m_ZCutter;
932
933   if( cutter == NULL )
934   return;
935
936   vtkPlane* vplane = this->m_ImageActors->GetSlicePlane( axis );
937   double vorigin[ 3 ], vnormal[ 3 ];
938   vplane->GetOrigin( vorigin );
939   vplane->GetNormal( vnormal );
940
941   TCutter::TVector corigin, cnormal;
942   corigin[ 0 ] = TScalar( vorigin[ 0 ] );
943   corigin[ 1 ] = TScalar( vorigin[ 1 ] );
944   corigin[ 2 ] = TScalar( vorigin[ 2 ] );
945   cnormal[ 0 ] = TScalar( vnormal[ 0 ] );
946   cnormal[ 1 ] = TScalar( vnormal[ 1 ] );
947   cnormal[ 2 ] = TScalar( vnormal[ 2 ] );
948
949   cutter->SetPlanePoint( corigin );
950   cutter->SetPlaneNormal( cnormal );
951   cutter->Update( );
952   }
953
954   // -------------------------------------------------------------------------
955   void MainWnd::
956   _SliceEventCallback(
957   vtkObject* caller,
958   long unsigned int eventId,
959   void* clientData, void* callData
960   )
961   {
962   if( clientData == NULL || callData == NULL )
963   return;
964   MainWnd* wnd = reinterpret_cast< MainWnd* >( clientData );
965   int axis = *( reinterpret_cast< int* >( callData ) );
966   if( wnd == NULL )
967   return;
968   if( eventId == idms::InteractorStyleImage::SliceEvent )
969   wnd->_SliceMesh( axis );
970   }
971
972   // -------------------------------------------------------------------------
973   void MainWnd::
974   triggered_aLoadImage( )
975   {
976   if( this->_LoadImage< TImage >( this->m_Image ) )
977   {
978   // Connect image to VTK
979   this->m_VTKImage->SetInput( this->m_Image );
980   this->m_VTKImage->Update( );
981   this->m_ImageActors->Configure(
982   this->m_VTKImage->GetOutput( ),
983   this->m_UI->m_XPlaneVTK->GetInteractor( ),
984   this->m_UI->m_YPlaneVTK->GetInteractor( ),
985   this->m_UI->m_ZPlaneVTK->GetInteractor( )
986   );
987   this->m_ImageActors->
988   AddAuxiliaryInteractor( this->m_UI->m_3DVTK->GetInteractor( ) );
989
990   // Associate actors
991   this->m_3DRenderer->AddActor(
992   this->m_ImageActors->GetImageOutlineActor( )
993   );
994   this->m_3DRenderer->AddActor(
995   this->m_ImageActors->GetXBoundsActor( )
996   );
997   this->m_3DRenderer->AddActor(
998   this->m_ImageActors->GetYBoundsActor( )
999   );
1000   this->m_3DRenderer->AddActor(
1001   this->m_ImageActors->GetZBoundsActor( )
1002   );
1003
1004   // Reset all cameras
1005   this->m_3DRenderer->ResetCamera( );
1006   this->m_ImageActors->ResetCameras( );
1007
1008   // Ok, start!
1009   this->m_UI->m_3DVTK->GetRenderWindow( )->Render( );
1010   this->m_UI->m_XPlaneVTK->GetRenderWindow( )->Render( );
1011   this->m_UI->m_YPlaneVTK->GetRenderWindow( )->Render( );
1012   this->m_UI->m_ZPlaneVTK->GetRenderWindow( )->Render( );
1013
1014   // Activate controls
1015   this->m_UI->aLoadSegmentedImage->setEnabled( true );
1016   this->m_UI->aSegmentImage->setEnabled( true );
1017   this->m_UI->m_3DVTK->setEnabled( true );
1018   this->m_UI->m_XPlaneVTK->setEnabled( true );
1019   this->m_UI->m_YPlaneVTK->setEnabled( true );
1020   this->m_UI->m_ZPlaneVTK->setEnabled( true );
1021
1022   } // fi
1023   }
1024
1025   // -------------------------------------------------------------------------
1026   void MainWnd::
1027   triggered_aLoadSegmentedImage( )
1028   {
1029   if( this->m_Mesh.IsNotNull( ) )
1030   {
1031   QMessageBox::critical(
1032   this,
1033   tr( "Mesh already loaded!" ),
1034   tr( "Mesh already loaded!" )
1035   );
1036   return;
1037
1038   } // fi
1039
1040   if( this->_LoadImage< TImage >( this->m_Segmentation ) )
1041   {
1042   // Compute segmentation values
1043   itk::MinimumMaximumImageCalculator< TImage >::Pointer minmax =
1044   itk::MinimumMaximumImageCalculator< TImage >::New( );
1045   minmax->SetImage( this->m_Segmentation );
1046   minmax->Compute( );
1047   TPixel min_v = minmax->GetMinimum( );
1048   TPixel max_v = minmax->GetMaximum( );
1049   double thr = double( max_v + min_v ) / double( 2 );
1050
1051   typedef itk::Image< TScalar, Dimension > _TScalarImage;
1052   typedef
1053   itk::BinaryMinMaxCurvatureFlowImageFilter< TImage, _TScalarImage >
1054   _TFilter;
1055   typedef _TFilter::TimeStepType    _TTimeStep;
1056   typedef _TFilter::RadiusValueType _TRadius;
1057
1058   _TFilter::Pointer filter = _TFilter::New( );
1059   filter->SetInput( this->m_Segmentation );
1060   filter->SetTimeStep( _TTimeStep( 0.0625 ) );
1061   filter->SetNumberOfIterations( 10 );
1062   filter->SetStencilRadius( _TRadius( 3 ) );
1063   filter->SetThreshold( thr );
1064   filter->Update( );
1065
1066   itk::ImageFileWriter< _TScalarImage >::Pointer w =
1067   itk::ImageFileWriter< _TScalarImage >::New( );
1068   w->SetInput( filter->GetOutput( ) );
1069   w->SetFileName( "no_noise.mhd" );
1070   w->Update( );
1071   std::exit( 1 );
1072
1073   typedef
1074   itk::LaplacianRecursiveGaussianImageFilter< TImage, _TScalarImage >
1075   _TFilter;
1076   _TFilter::Pointer filter = _TFilter::New( );
1077   filter->SetInput( this->m_Segmentation );
1078   filter->SetSigma( 3 ); // in spacing units
1079   filter->SetNormalizeAcrossScale( false );
1080
1081   typedef itk::ThresholdImageFilter< _TScalarImage > _TThreshold;
1082   _TThreshold::Pointer threshold = _TThreshold::New( );
1083   threshold->SetInput( filter->GetOutput( ) );
1084   threshold->ThresholdAbove( TScalar( 0 ) );
1085   threshold->InPlaceOff( );
1086   threshold->Update( );
1087
1088   itk::MinimumMaximumImageCalculator< _TScalarImage >::Pointer t_minmax =
1089   itk::MinimumMaximumImageCalculator< _TScalarImage >::New( );
1090   t_minmax->SetImage( threshold->GetOutput( ) );
1091   t_minmax->Compute( );
1092   TScalar min_t = t_minmax->GetMinimum( );
1093
1094   std::cout << min_t << " " << t_minmax->GetMaximum( ) << std::endl;
1095
1096   itk::SubtractImageFilter< _TScalarImage >::Pointer subtract =
1097   itk::SubtractImageFilter< _TScalarImage >::New( );
1098   subtract->SetInput1( threshold->GetOutput( ) );
1099   subtract->SetConstant2( min_t );
1100
1101   itk::ImageFileWriter< _TScalarImage >::Pointer w =
1102   itk::ImageFileWriter< _TScalarImage >::New( );
1103   w->SetInput( subtract->GetOutput( ) );
1104   w->SetFileName( "no_noise_laplace_2.mhd" );
1105   w->Update( );
1106   std::exit( 1 );
1107
1108   // Pass segmentation to VTK
1109   this->m_VTKSegmentation = TVTKImage::New( );
1110   this->m_VTKSegmentation->SetInput( this->m_Segmentation );
1111   this->m_VTKSegmentation->Update( );
1112
1113   // Use VTK's marching cubes (it is smoother)
1114   vtkSmartPointer< vtkImageMarchingCubes > segmentation_mc =
1115   vtkSmartPointer< vtkImageMarchingCubes >::New( );
1116   segmentation_mc->SetInputData( this->m_VTKSegmentation->GetOutput( ) );
1117   segmentation_mc->SetValue( 0, thr );
1118   segmentation_mc->Update( );
1119
1120   // Go back to ITK world
1121   typedef cpm::VTK::PolyDataToMeshFilter< TTriangulation > _TVTKPDataToMesh;
1122   _TVTKPDataToMesh::Pointer itk_mc = _TVTKPDataToMesh::New( );
1123   itk_mc->SetInput( segmentation_mc->GetOutput( ) );
1124   itk_mc->Update( );
1125   this->m_Mesh = itk_mc->GetOutput( );
1126   this->m_Mesh->DisconnectPipeline( );
1127
1128   this->m_MeshMapper = vtkSmartPointer< TTriangulationMapper >::New( );
1129   this->m_MeshActor = vtkSmartPointer< vtkActor >::New( );
1130
1131   this->m_MeshMapper->SetInputData( this->m_Mesh );
1132   this->m_MeshActor->SetMapper( this->m_MeshMapper );
1133   this->m_MeshActor->GetProperty( )->SetColor( 1, 1, 0 );
1134   this->m_MeshActor->GetProperty( )->SetRepresentationToWireframe( );
1135   this->m_3DRenderer->AddActor( this->m_MeshActor );
1136   this->m_3DRenderer->ResetCamera( );
1137   this->m_UI->m_3DVTK->GetRenderWindow( )->Render( );
1138
1139   unsigned int reduction = 20;
1140
1141   typedef TImage::SpacingType::ValueType _TValue;
1142
1143
1144   // Compute downsize parameters
1145   TImage::SizeType o_size =
1146   segmentation->GetLargestPossibleRegion( ).GetSize( );
1147   TImage::SpacingType o_spac = segmentation->GetSpacing( );
1148   _TValue min_spac = std::numeric_limits< _TValue >::max( );
1149   for( unsigned int d = 0; d < Dimension; ++d )
1150   min_spac = ( o_spac[ d ] < min_spac )? o_spac[ d ]: min_spac;
1151   min_spac *= _TValue( reduction );
1152   TImage::SpacingType n_spac( min_spac );
1153   TImage::SizeType n_size;
1154   for( unsigned int d = 0; d < Dimension; ++d )
1155   n_size[ d ] = ( unsigned long )(
1156   _TValue( o_size[ d ] ) * o_spac[ d ] / min_spac
1157   );
1158
1159   // Downsize image
1160   typedef itk::Image< TScalar, Dimension > _TScalarImage;
1161   typedef itk::IdentityTransform< TScalar, Dimension > _TTransform;
1162   typedef
1163   itk::LinearInterpolateImageFunction< TImage, TScalar >
1164   _TInterpolator;
1165   typedef
1166   itk::ResampleImageFilter< TImage, _TScalarImage, TScalar, TScalar >
1167   _TResample;
1168   _TResample::Pointer resample = _TResample::New( );
1169   resample->SetInput( segmentation );
1170   resample->SetSize( n_size );
1171   resample->SetOutputDirection( segmentation->GetDirection( ) );
1172   resample->SetOutputOrigin( segmentation->GetOrigin( ) );
1173   resample->SetOutputSpacing( n_spac );
1174   resample->SetTransform( _TTransform::New( ) );
1175   resample->SetInterpolator( _TInterpolator::New( ) );
1176   resample->UpdateLargestPossibleRegion( );
1177
1178   // Try to smooth
1179   typedef
1180   itk::SignedDanielssonDistanceMapImageFilter< _TScalarImage, _TScalarImage >
1181   _TDanielsson;
1182   _TDanielsson::Pointer danielsson = _TDanielsson::New( );
1183   danielsson->SetInput( resample->GetOutput( ) );
1184   danielsson->Update( );
1185
1186   // Go back to ITK world
1187   typedef cpm::VTK::PolyDataToMeshFilter< TTriangulation > TVTKPDataToMesh;
1188   TVTKPDataToMesh::Pointer itk_mc = TVTKPDataToMesh::New( );
1189   itk_mc->SetInput( danielsson_mc->GetOutput( ) );
1190   itk_mc->Update( );
1191   this->m_Mesh = itk_mc->GetOutput( );
1192   this->m_Mesh->DisconnectPipeline( );
1193
1194   this->m_ZCutter = TCutter::New( );
1195   this->m_ZCutter->SetInput( this->m_Mesh );
1196
1197   this->m_MeshMapper = vtkSmartPointer< TTriangulationMapper >::New( );
1198   this->m_MeshActor = vtkSmartPointer< vtkActor >::New( );
1199
1200   this->m_MeshMapper->SetInputData( this->m_Mesh );
1201   this->m_MeshActor->SetMapper( this->m_MeshMapper );
1202   this->m_MeshActor->GetProperty( )->SetColor( 1, 1, 0 );
1203   this->m_MeshActor->GetProperty( )->SetRepresentationToWireframe( );
1204   this->m_3DRenderer->AddActor( this->m_MeshActor );
1205   this->m_3DRenderer->ResetCamera( );
1206   this->m_UI->m_3DVTK->GetRenderWindow( )->Render( );
1207
1208   } // fi
1209   }
1210 */
1211
1212 // eof - $RCSfile$