]> Creatis software - gdcm.git/blob - Example/AnonymizeMultiPatient.cxx
Add an application to allow anonymizing a 'multi patient' dictionnary
[gdcm.git] / Example / AnonymizeMultiPatient.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: AnonymizeMultiPatient.cxx,v $
5   Language:  C++
6   Date:      $Date: 2006/05/30 08:26:36 $
7   Version:   $Revision: 1.1 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18 #include "gdcmFile.h"
19 #include "gdcmFileHelper.h"
20 #include "gdcmCommon.h"
21 #include "gdcmUtil.h"
22 #include "gdcmDebug.h"
23 #include "gdcmDirList.h"
24
25 #include "gdcmDicomDir.h"
26 #include "gdcmDicomDirPatient.h"
27 #include "gdcmDicomDirStudy.h"
28 #include "gdcmDicomDirSerie.h"
29 #include "gdcmDicomDirImage.h"
30
31 #include "gdcmArgMgr.h"
32
33 #include <iostream>
34
35
36 int main(int argc, char *argv[])
37 {
38    START_USAGE(usage)
39    " \n AnonymizeMultiPatient :\n                                             ",
40    " AnonymizeMultiPatient a full gdcm-readable Dicom image                   ",
41    "         Warning : the image is OVERWRITTEN                               ",
42    "                   to preserve image integrity, use a copy.               ",
43    " usage: AnonymizeMultiPatient dirin=inputDirectoryName dirout=outputDirectoryName",
44    "       listOfElementsToRubOut : group-elem,g2-e2,... (in hexa, no space)  ",
45    "                                of extra Elements to rub out              ",
46    "       noshadowseq: user doesn't want to load Private Sequences           ",
47    "       noshadow   : user doesn't want to load Private groups (odd number) ",
48    "       noseq      : user doesn't want to load Sequences                   ",
49    "       verbose  : user wants to run the program in 'verbose mode'         ",   
50    "       debug      : user wants to run the program in 'debug mode'         ",   
51    FINISH_USAGE
52
53    // ----- Initialize Arguments Manager ------   
54    gdcm::ArgMgr *am = new gdcm::ArgMgr(argc, argv);
55   
56    if (argc == 1 || am->ArgMgrDefined("usage")) 
57    {
58       am->ArgMgrUsage(usage); // Display 'usage'
59       delete am;
60       return 0;
61    }
62    const char *dirName  = am->ArgMgrGetString("dirin");
63    if ( dirName == NULL )
64    {
65       delete am;
66       return 0;
67    }
68    
69    /*
70    char *outputDirName = am->ArgMgrWantString("dirout",usage);
71    if ( outputDirName == NULL )
72    {
73       delete am;
74       return 0;
75    }
76  */
77    
78    bool verbose  = am->ArgMgrDefined("verbose");
79    
80    if (am->ArgMgrDefined("debug"))
81       gdcm::Debug::DebugOn();
82
83    int loadMode = gdcm::LD_ALL;
84    if ( am->ArgMgrDefined("noshadowseq") )
85       loadMode |= gdcm::LD_NOSHADOWSEQ;
86    else 
87    {
88       if ( am->ArgMgrDefined("noshadow") )
89          loadMode |= gdcm::LD_NOSHADOW;
90       if ( am->ArgMgrDefined("noseq") )
91          loadMode |= gdcm::LD_NOSEQ;
92    }
93
94    int rubOutNb;
95    uint16_t *elemsToRubOut = am->ArgMgrGetXInt16Enum("rubout", &rubOutNb);
96  
97    // if unused Param we give up
98    if ( am->ArgMgrPrintUnusedLabels() )
99    { 
100       am->ArgMgrUsage(usage);
101       delete am;
102       return 0;
103    }
104
105    delete am;  // we don't need Argument Manager any longer
106    
107   // ---------------------------------------------------------- 
108   
109      // ----- Begin Processing -----
110
111    gdcm::DicomDir *dcmdir;
112
113    // we ask for Directory parsing
114
115    dcmdir = gdcm::DicomDir::New( );
116
117    dcmdir->SetLoadMode(loadMode);
118    dcmdir->SetDirectoryName(dirName);
119    dcmdir->Load();
120
121
122
123    gdcm::DicomDirPatient *pa;
124    gdcm::DicomDirStudy *st;
125    gdcm::DicomDirSerie *se;
126    gdcm::DicomDirVisit *vs;
127    gdcm::DicomDirImage *im;      
128   
129    // Test if the DicomDir contains any Patient
130    pa = dcmdir->GetFirstPatient();
131    if ( pa == 0)
132    {
133       std::cout<<"          DicomDir '"<< dirName
134                <<" has no patient"<<std::endl
135                <<"          ...Failed"<<std::endl;
136
137       dcmdir->Delete();
138       return 1;
139    } 
140    
141       if ( verbose )
142       std::cout << "-------------------------- Directory [" << dirName << "] parsed" << std::endl;
143
144 // Since files may be help in a Directory tree-like structure
145 // we should have to duplicate this structure.
146 // No time to code that stuff
147 //  --> We 'AnonymizeNoLoad' (overwrite the files)
148
149 // Do not remove the commented out lines.
150 // They will be usefull in a further program. 
151 /*
152    std::string systemCommand;
153    
154    std::cout << "Check for output directory :[" << outputDirName << "]."
155              <<std::endl;
156    if ( ! gdcm::DirList::IsDirectory(outputDirName) )    // dirout not found
157    {
158       std::string strDirNameout(outputDirName);          // to please gcc 4
159       systemCommand = "mkdir " +strDirNameout;        // create it!
160       if (verbose)
161          std::cout << systemCommand << std::endl;
162       system (systemCommand.c_str());
163       if ( ! gdcm::DirList::IsDirectory(outputDirName) ) // be sure it worked
164       {
165           std::cout << "KO : not a dir : [" << outputDirName << "] (creation failure ?)" << std::endl;
166           exit(0);
167       }
168       else
169       {
170         std::cout << "Directory [" << outputDirName << "] created." << std::endl;
171       }
172    }
173    else
174    {
175        std::cout << "Output Directory [" << outputDirName << "] already exists; Used as is." << std::endl;
176    }
177 */
178
179   gdcm::File *f;
180   gdcm::FileHelper *fh;
181  // std::string outputFileName;
182
183   std::string codedName; 
184   while (pa)
185   {
186      if (verbose)
187      {
188         std::cout << "Pat.Name:[" << pa->GetEntryString(0x0010, 0x0010) <<"]"; // Patient's Name
189         std::cout << " Pat.ID:[";
190         std::cout << pa->GetEntryString(0x0010, 0x0020) << "]" << std::endl; // Patient ID
191      }     
192      std::string patName = pa->GetEntryString(0x0010, 0x0010);
193      //codedName = "g^" + gdcm::Util::ConvertToMD5(patName); // just to be sure MD5 is not guilty
194      std::string fullFileName;
195      if (verbose)
196         std::cout << patName << " --> " << codedName << std::endl;
197          
198      st = pa->GetFirstStudy();
199       while ( st ) 
200       { // on degouline les STUDY de ce patient
201          if (verbose)
202          {
203             std::cout << "--- Stud.descr:["    << st->GetEntryString(0x0008, 0x1030) << "]"; // Study Description    
204             std::cout << " Stud.ID:["          << st->GetEntryString(0x0020, 0x0010) << "]"; // Study ID
205             std::cout << std::endl;
206          }
207          se = st->GetFirstSerie();
208          while ( se ) 
209          { // on degouline les SERIES de cette study
210             if (verbose)
211             {
212                std::cout << "--- --- Ser.Descr:["<< se->GetEntryString(0x0008, 0x103e) << "]";  // Series Description
213                std::cout << " Ser.nb:["          <<  se->GetEntryString(0x0020, 0x0011) << "]";  // Series number
214                std::cout << " Mod.:["      <<  se->GetEntryString(0x0008, 0x0060) << "]";  // Modality
215                std::cout << " Serie Inst.UID.:[" <<  se->GetEntryString(0x0020, 0x000e) << "]";  // Series Instance UID
216                std::cout << std::endl; 
217             }
218   
219             im = se->GetFirstImage();
220             std::string ReferencedFileID;
221             while ( im ) 
222             { // on degouline les IMAGEs de cette serie
223                ReferencedFileID = im->GetEntryString(0x0004, 0x1500);
224                if (verbose)
225                {
226                   std::cout << "--- --- --- "<< " IMAGE Ref. File ID :[" << ReferencedFileID 
227                             << "]" << std::endl; // File name (Referenced File ID)
228                }       
229                f = gdcm::File::New( );
230                f->SetLoadMode(loadMode);
231                fullFileName = dirName;
232        
233                std::cout << "fullFileName (1) " << fullFileName << std::endl;
234                std::cout << "ReferencedFileID " << ReferencedFileID << std::endl;
235                fullFileName = fullFileName + "/" + ReferencedFileID;       
236                std::cout << "fullFileName (2) " << fullFileName << std::endl;
237
238                f->SetFileName( fullFileName );
239        
240                if ( !f->Load() )
241                    std::cout << "Load failed for [" << fullFileName << "]" << std::endl; 
242                else
243                   std::cout << "Load successed for [" << fullFileName << "]" << std::endl; 
244        
245                // 
246                //  Choose the fields to anonymize.
247                // 
248
249                // Institution name 
250                f->AddAnonymizeElement( 0x0008, 0x0080, "Xanadoo" );
251
252                // Patient's name 
253                f->AddAnonymizeElement( 0x0010, 0x0010, codedName ); 
254     
255                // Patient's ID
256                f->AddAnonymizeElement( 0x0010, 0x0020,"1515" );
257                // Patient's Birthdate
258                f->AddAnonymizeElement( 0x0010, 0x0030,"11111111" );
259                // Patient's Adress
260                f->AddAnonymizeElement( 0x0010, 0x1040,"Sing-sing" );
261                // Patient's Mother's Birth Name
262                f->AddAnonymizeElement( 0x0010, 0x1060,"g^Vampirella" );
263        
264                // Study Instance UID
265                // we may not brutaly overwrite it
266                //f->AddAnonymizeElement( 0x0020, 0x000d, "9.99.999.9999" );
267   
268                // Telephone
269                f->AddAnonymizeElement(0x0010, 0x2154, "3615" );
270
271                // deal with user defined Elements set
272
273 std::cout << "rubOutNb " << rubOutNb << std::endl;
274                for (int ri=0; ri<rubOutNb; ri++)
275                {
276                   f->AddAnonymizeElement((uint32_t)elemsToRubOut[2*ri], 
277                        (uint32_t)elemsToRubOut[2*ri+1],"*" ); 
278                }
279       
280                // The gdcm::File is modified in memory
281                // f->AnonymizeFile();    
282
283                // 
284                //      Overwrite the file
285                // 
286                // The gdcm::File remains untouched in memory    
287                f->AnonymizeNoLoad();     
288
289                // ============================================================
290                //               Write a new file
291                // ============================================================
292
293                // 
294                //      No need to load the pixels in memory.
295                //      File will be overwritten
296
297                // Do not remove the commented out lines.
298                // They will be usefull in a further program.
299                // 
300 /*     
301                // Get the Pixels
302                fh = gdcm::FileHelper::New(f);
303
304                // unit8_t DOESN'T mean it's mandatory for the image to be a 8 bits one !
305                // Feel free to cast if you know it's not. 
306
307                uint8_t *imageData = fh->GetImageData();
308
309                if ( imageData == 0 )
310                {
311                   std::cerr << "Sorry, Pixels of" << im->GetEntryString(0x0004, 0x1500) <<"  are not "
312                       << " gdcm-readable."       << std::endl
313                       << "Use AnonymizeNoLoad" << std::endl;
314                   f->Delete();
315                   fh->Delete();
316                   break;
317                 } 
318
319                      // Since we just Anonymized the file, we *know* no modification 
320                      // was performed on the pixels.
321                      // The written image will not appear as a 'Secondary Captured image'
322                      // nor as a DERIVED one
323
324                      fh->SetContentType(gdcm::UNMODIFIED_PIXELS_IMAGE);
325                      outputFileName = outputDirName + "/" + im->GetEntryString(0x0004, 0x1500);
326                      fh->WriteDcmExplVR(outputFileName);
327                      std::cout <<"End Anonymize" << std::cout;
328
329                      fh->Delete();       
330 */
331
332                      f->Delete();
333                      f->ClearAnonymizeList();
334      
335                      im = se->GetNextImage();   
336                   }
337                   se = st->GetNextSerie();   
338                }  
339                st = pa->GetNextStudy();
340             }         
341      
342      pa = dcmdir->GetNextPatient();    
343   }
344   
345 }
346