00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <vtkRenderWindowInteractor.h>
00035 #include <vtkImageViewer2.h>
00036 #include <vtkStructuredPoints.h>
00037 #include <vtkStructuredPointsWriter.h>
00038 #include <vtkCommand.h>
00039 #include <vtkRenderer.h>
00040 #include <vtkImageMapToColors.h>
00041 #include <vtkLookupTable.h>
00042
00043 #include "vtkGdcmReader.h"
00044 #include "gdcmDocument.h"
00045 #include "gdcmSerieHelper.h"
00046 #include "gdcmDebug.h"
00047 #include "gdcmDataEntry.h"
00048
00049 #include "gdcmArgMgr.h"
00050 #include <string.h>
00051 #ifndef vtkFloatingPointType
00052 #define vtkFloatingPointType float
00053 #endif
00054
00055 void userSuppliedMirrorFunction (uint8_t *im, GDCM_NAME_SPACE::File *f);
00056 void userSuppliedUpsideDownFunction(uint8_t *im, GDCM_NAME_SPACE::File *f);
00057 bool userSuppliedLessThanFunction(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2);
00058 bool userSuppliedLessThanFunction2(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2);
00059
00060 int orderNb;
00061 uint16_t *elemsToOrderOn;
00062
00063
00064
00065 class vtkgdcmObserver : public vtkCommand
00066 {
00067 public:
00068 virtual char const *GetClassName() const
00069 {
00070 return "vtkgdcmObserver";
00071 }
00072
00073 static vtkgdcmObserver *New()
00074 {
00075 return new vtkgdcmObserver;
00076 }
00077
00078 vtkgdcmObserver()
00079 {
00080 this->ImageViewer = NULL;
00081 }
00082
00083 virtual void Execute(vtkObject *, unsigned long event, void* )
00084 {
00085 if ( this->ImageViewer )
00086 {
00087 if ( event == vtkCommand::CharEvent )
00088 {
00089 #if (VTK_MAJOR_VERSION >= 5)
00090 int max = ImageViewer->GetSliceMax();
00091 int slice = (ImageViewer->GetSlice() + 1 ) % ++max;
00092 ImageViewer->SetSlice( slice );
00093 #else
00094 int max = ImageViewer->GetWholeZMax();
00095 int slice = (ImageViewer->GetZSlice() + 1 ) % ++max;
00096 ImageViewer->SetZSlice( slice );
00097 #endif
00098 #if !( (VTK_MAJOR_VERSION >= 5) || ( VTK_MAJOR_VERSION == 4 && VTK_MINOR_VERSION >= 5 ) )
00099
00100 ImageViewer->GetRenderer()->ResetCameraClippingRange();
00101 #endif
00102 ImageViewer->Render();
00103 }
00104 }
00105 }
00106 vtkImageViewer2 *ImageViewer;
00107 };
00108
00109 int main(int argc, char *argv[])
00110 {
00111 START_USAGE(usage)
00112 " \n vtkgdcmSerieViewer2 : \n",
00113 " Display a 'Serie' (same Serie UID) within a Directory ",
00114 " You can navigate through the stack by hitting any character key. ",
00115 " usage: vtkgdcmSerieViewer dirname=sourcedirectory ",
00116 " [noshadowseq][noshadow][noseq] ",
00117 " [reverse] [{[mirror]|[topdown]|[rotate]}] ",
00118 " [order=] [nodup][check][debug] ",
00119 " sourcedirectory : name of the directory holding the images ",
00120 " if it holds more than one serie, ",
00121 " only the first one is displayed. ",
00122 " noshadowseq: user doesn't want to load Private Sequences ",
00123 " noshadow : user doesn't want to load Private groups (odd number) ",
00124 " noseq : user doesn't want to load Sequences ",
00125 " reverse : user wants to sort the images reverse order ",
00126 " mirror : user wants to 'mirror' the images | just some simple",
00127 " upsidedown : user wants to 'upsidedown' the images| examples of user",
00128 " | suppliedfunction",
00129 " check : user wants to force more coherence checking ",
00130 " order= : group1-elem1,group2-elem2,... (in hexa, no space) ",
00131 " if we want to use them as a sort criterium ",
00132 " Right now : ValEntries only -just an example- ",
00133 " or ",
00134 " order= : order=name if we want to sort on file name (why not ?) ",
00135 " nodup : user wants to drop duplicate positions ",
00136 " debug : developper wants to run the program in 'debug mode' ",
00137 FINISH_USAGE
00138
00139
00140
00141 GDCM_NAME_SPACE::ArgMgr *am= new GDCM_NAME_SPACE::ArgMgr(argc, argv);
00142
00143 if (argc == 1 || am->ArgMgrDefined("usage") )
00144 {
00145 am->ArgMgrUsage(usage);
00146 delete am;
00147 return 0;
00148 }
00149
00150 char *dirName = am->ArgMgrWantString("dirname",usage);
00151
00152 int loadMode = GDCM_NAME_SPACE::LD_ALL;
00153 if ( am->ArgMgrDefined("noshadowseq") )
00154 loadMode |= GDCM_NAME_SPACE::LD_NOSHADOWSEQ;
00155 else
00156 {
00157 if ( am->ArgMgrDefined("noshadow") )
00158 loadMode |= GDCM_NAME_SPACE::LD_NOSHADOW;
00159 if ( am->ArgMgrDefined("noseq") )
00160 loadMode |= GDCM_NAME_SPACE::LD_NOSEQ;
00161 }
00162
00163 int reverse = am->ArgMgrDefined("reverse");
00164 int nodup = am->ArgMgrDefined("nodup");
00165 int mirror = am->ArgMgrDefined("mirror");
00166 int upsidedown = am->ArgMgrDefined("upsidedown");
00167
00168 if ( mirror && upsidedown )
00169 {
00170 std::cout << "*EITHER* mirror *OR* upsidedown !"
00171 << std::endl;
00172 delete am;
00173 return 0;
00174 }
00175
00176 int check = am->ArgMgrDefined("check");
00177
00178
00179 bool bname = ( strcmp(am->ArgMgrGetString("order", "not found"),"name")==0 );
00180 if (bname)
00181 elemsToOrderOn = am->ArgMgrGetXInt16Enum("order", &orderNb);
00182
00183 if (am->ArgMgrDefined("debug"))
00184 GDCM_NAME_SPACE::Debug::DebugOn();
00185
00186
00187 if ( am->ArgMgrPrintUnusedLabels() )
00188 {
00189 am->ArgMgrUsage(usage);
00190 delete am;
00191 return 0;
00192 }
00193
00194 delete am;
00195
00196
00197
00198 GDCM_NAME_SPACE::SerieHelper *sh = GDCM_NAME_SPACE::SerieHelper::New();
00199 sh->SetLoadMode(loadMode);
00200 if (reverse)
00201 sh->SetSortOrderToReverse();
00202 sh->SetDirectory( dirName, true);
00203
00204
00205
00206 int nbFiles;
00207
00208 GDCM_NAME_SPACE::FileList *l = sh->GetFirstSingleSerieUIDFileSet();
00209 if (l == 0 )
00210 {
00211 std::cout << "Oops! No 'Single Serie UID' FileSet found ?!?" << std::endl;
00212 return 0;
00213 }
00214
00215 if (bname)
00216 sh->SetUserLessThanFunction(userSuppliedLessThanFunction2);
00217 else if (orderNb != 0)
00218 sh->SetUserLessThanFunction(userSuppliedLessThanFunction);
00219
00220 if (nodup)
00221 sh->SetDropDuplicatePositions(true);
00222
00223 while (l)
00224 {
00225 nbFiles = l->size() ;
00226 if ( l->size() > 1 )
00227 {
00228 std::cout << "Sort list : " << nbFiles << " long" << std::endl;
00229
00230
00231 sh->OrderFileList(l);
00232
00233
00234 double zsp = sh->GetZSpacing();
00235 std::cout << "List sorted, ZSpacing = " << zsp << std::endl;
00236 break;
00237 }
00238 else
00239 {
00240 std::cout << "Oops! Empty 'Single Serie UID' FileSet found ?!?"
00241 << std::endl;
00242 }
00243 l = sh->GetNextSingleSerieUIDFileSet();
00244 }
00245
00246 if (check)
00247 {
00248 if ( !sh->IsCoherent(l) )
00249 {
00250 std::cout << "Files are not coherent. Stop everything " << std::endl;
00251 sh->Delete();
00252 return 0;
00253 }
00254 }
00255
00256 vtkGdcmReader *reader = vtkGdcmReader::New();
00257 reader->AllowLookupTableOff();
00258
00259 if (mirror)
00260 reader->SetUserFunction (userSuppliedMirrorFunction);
00261 else if (upsidedown)
00262 reader->SetUserFunction (userSuppliedUpsideDownFunction);
00263
00264
00265
00266
00267
00268 reader->SetCoherentFileList(l);
00269
00270
00271
00272
00273
00274 reader->Update();
00275
00276
00277 reader->GetOutput()->Print( cout );
00278
00279 vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
00280
00281 vtkImageViewer2 *viewer = vtkImageViewer2::New();
00282
00283 if( reader->GetLookupTable() )
00284 {
00285
00286 vtkImageMapToColors *map = vtkImageMapToColors::New ();
00287 map->SetInput (reader->GetOutput());
00288 map->SetLookupTable (reader->GetLookupTable());
00289 map->SetOutputFormatToRGB();
00290 viewer->SetInput ( map->GetOutput() );
00291 map->Delete();
00292 }
00293 else
00294 {
00295 vtkFloatingPointType *range = reader->GetOutput()->GetScalarRange();
00296 viewer->SetColorLevel (0.5 * (range[1] + range[0]));
00297 viewer->SetColorWindow (range[1] - range[0]);
00298
00299 viewer->SetInput ( reader->GetOutput() );
00300 }
00301 viewer->SetupInteractor (iren);
00302
00303
00304
00305
00306
00307
00308 vtkgdcmObserver *obs = vtkgdcmObserver::New();
00309 obs->ImageViewer = viewer;
00310 iren->AddObserver(vtkCommand::CharEvent,obs);
00311 obs->Delete();
00312
00313
00314 iren->Initialize();
00315 iren->Start();
00316
00317
00318 vtkStructuredPointsWriter *writer = vtkStructuredPointsWriter::New();
00319 writer->SetInput( reader->GetOutput());
00320 writer->SetFileName( "foo.vtk" );
00321 writer->SetFileTypeToBinary();
00322
00323
00324 reader->Delete();
00325 iren->Delete();
00326 viewer->Delete();
00327 writer->Delete();
00328
00329 return 0;
00330 }
00331
00332
00333
00334
00335
00336
00337
00338
00339 #define UF(ty) \
00340 int i, j; \
00341 ty *imj; \
00342 ty tamp; \
00343 for (j=0;j<ny;j++) \
00344 { \
00345 imj = (ty *)im +j*nx; \
00346 for (i=0;i<nx/2;i++) \
00347 { \
00348 tamp =imj[i]; \
00349 imj[i] =imj[nx-1-i]; \
00350 imj[nx-1-i]=tamp; \
00351 } \
00352 } \
00353 if (nx%2 != 0) \
00354 { \
00355 i = nx / 2; \
00356 for (j=0;j<ny;j++) \
00357 { \
00358 imj = (ty *)im +j*nx; \
00359 tamp =imj[i]; \
00360 imj[i] =imj[nx/2+1]; \
00361 imj[nx/2+1]=tamp; \
00362 } \
00363 }
00364
00365 void userSuppliedMirrorFunction(uint8_t *im, GDCM_NAME_SPACE::File *f)
00366 {
00367 if (f->GetZSize() != 1)
00368 {
00369 std::cout << "mirror : Multiframe images not yet dealt with" << std::endl;
00370 return;
00371 }
00372
00373 if (f->GetSamplesPerPixel() != 1 || f->GetBitsAllocated() == 24)
00374 {
00375 std::cout << "mirror : RGB / YBR not yet dealt with" << std::endl;
00376 return;
00377 }
00378 int nx = f->GetXSize();
00379 int ny = f->GetYSize();
00380
00381 std::string pixelType = f->GetPixelType();
00382 if ( pixelType == "8U" || pixelType == "8S" )
00383 {
00384 UF(uint8_t)
00385 return;
00386 }
00387 if ( pixelType == "16U" || pixelType == "16S")
00388 {
00389 UF(uint16_t)
00390 return;
00391 }
00392 std::cout << "mirror : Pixel Size (!=8, !=16) not yet dealt with"
00393 << std::endl;
00394 return;
00395 }
00396
00397
00398
00399
00400
00401
00402
00403
00404 #define UF2(ty) \
00405 int i, j; \
00406 ty *imj, *imJ; \
00407 ty tamp; \
00408 for (j=0;j<ny/2;j++) \
00409 { \
00410 imj = (ty *)im +j*nx; \
00411 imJ = (ty *)im +(ny-1-j)*nx; \
00412 for (i=0;i<nx;i++) \
00413 { \
00414 tamp =imj[i]; \
00415 imj[i] =imJ[i]; \
00416 imJ[i] =tamp; \
00417 } \
00418 }
00419
00420 void userSuppliedUpsideDownFunction(uint8_t *im, GDCM_NAME_SPACE::File *f)
00421 {
00422 if (f->GetZSize() != 1)
00423 {
00424 std::cout << "mirror : Multiframe images not yet dealt with" << std::endl;
00425 return;
00426 }
00427
00428 if (f->GetSamplesPerPixel() != 1 || f->GetBitsAllocated() == 24)
00429 {
00430 std::cout << "mirror : RGB / YBR not yet dealt with" << std::endl;
00431 return;
00432 }
00433 int nx = f->GetXSize();
00434 int ny = f->GetYSize();
00435
00436 std::string pixelType = f->GetPixelType();
00437 if ( pixelType == "8U" || pixelType == "8S" )
00438 {
00439 UF2(uint8_t)
00440 return;
00441 }
00442 if ( pixelType == "16U" || pixelType == "16S")
00443 {
00444 UF2(uint16_t)
00445 return;
00446 }
00447 std::cout << "topdown : Pixel Size (!=8, !=16) not yet dealt with"
00448 << std::endl;
00449 return;
00450 }
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466 bool userSuppliedLessThanFunction(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2)
00467 {
00468
00469
00470 std::string s1, s2;
00471 GDCM_NAME_SPACE::DataEntry *e1,*e2;
00472 for (int ri=0; ri<orderNb; ri++)
00473 {
00474 std::cout << std::hex << elemsToOrderOn[2*ri] << "|"
00475 << elemsToOrderOn[2*ri+1]
00476 << std::endl;
00477
00478 e1= f1->GetDataEntry( elemsToOrderOn[2*ri],
00479 elemsToOrderOn[2*ri+1]);
00480
00481 e2= f2->GetDataEntry( elemsToOrderOn[2*ri],
00482 elemsToOrderOn[2*ri+1]);
00483 if(!e2 || !e2)
00484 {
00485 std::cout << std::hex << elemsToOrderOn[2*ri] << "|"
00486 << elemsToOrderOn[2*ri+1]
00487 << " not found" << std::endl;
00488 continue;
00489 }
00490 s1 = e1->GetString();
00491 s2 = e2->GetString();
00492 std::cout << "[" << s1 << "] vs [" << s2 << "]" << std::endl;
00493 if ( s1 < s2 )
00494 return true;
00495 else if (s1 == s2 )
00496 continue;
00497 else
00498 return false;
00499 }
00500 return false;
00501 }
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511 bool userSuppliedLessThanFunction2(GDCM_NAME_SPACE::File *f1, GDCM_NAME_SPACE::File *f2)
00512 {
00513 std::cout << "[" << f1->GetFileName() << "] vs ["
00514 << f2->GetFileName() << "]" << std::endl;
00515 return f1->GetFileName() < f2->GetFileName();
00516 }