]> Creatis software - gdcm.git/blob - Example/AnonymizeReWriteMultiPatient.cxx
Add some explanations
[gdcm.git] / Example / AnonymizeReWriteMultiPatient.cxx
1 /*=========================================================================
2                                                                                  
3   Program:   gdcm
4   Module:    $RCSfile: AnonymizeReWriteMultiPatient.cxx,v $
5   Language:  C++
6   Date:      $Date: 2008/03/18 13:37:54 $
7   Version:   $Revision: 1.4 $
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 "gdcmDocEntry.h"
19 #include "gdcmDicomDir.h"
20 #include "gdcmDicomDirPatient.h"
21 #include "gdcmDicomDirStudy.h"
22 #include "gdcmDicomDirVisit.h"
23 #include "gdcmDicomDirSerie.h"
24 #include "gdcmDicomDirImage.h"
25 #include "gdcmDirList.h"
26 #include "gdcmDebug.h"
27 #include "gdcmUtil.h"
28 #include "gdcmFile.h"
29 #include "gdcmFileHelper.h"
30
31 #include "gdcmArgMgr.h"
32
33 #include <iostream>
34
35 /**
36   * \brief   Explores recursively the given directory
37   *          orders the gdcm-readable found Files
38   *          according their Patient/Study/Serie/Image characteristics
39   *          and anomymizes (rewrite) them, creates a different name for each Patient.
40   */  
41
42 int main(int argc, char *argv[]) 
43 {
44    START_USAGE(usage)
45    " \n AnonymizeReWriteMultiPatient :\n                                      ",
46    " AnonymizeReWriteMultiPatient a full gdcm-readable Dicom image            ",
47    "         optionnaly, creates the DICOMDIR                                 ",
48    "         Warning : the image is OVERWRITTEN                               ",
49    "                   to preserve image integrity, use a copy.               ",
50    " usage: AnonymizeReWriteMultiPatient dirin=inputDirectoryName  dicomdir   ",
51    "       dirin : directory holding images to anonymize                      ",
52    "       rootname : root for the 'anonymized' name                          ",
53    "       listOfElementsToRubOut : group-elem,g2-e2,... (in hexa, no space)  ",
54    "                                of extra Elements to rub out              ",
55    "       dicomdir   : user wants to generate a DICOMDIR                     ",
56    "       verbose    : user wants to run the program in 'verbose mode'       ",   
57    "       debug      : user wants to run the program in 'debug mode'         ",   
58    FINISH_USAGE
59    
60
61
62    // ----- Initialize Arguments Manager ------   
63    GDCM_NAME_SPACE::ArgMgr *am = new GDCM_NAME_SPACE::ArgMgr(argc, argv);
64   
65    if (argc == 1 || am->ArgMgrDefined("usage")) 
66    {
67       am->ArgMgrUsage(usage); // Display 'usage'
68       delete am;
69       return 0;
70    }
71    const char * name  = am->ArgMgrGetString("dirin");
72    if ( name == NULL )
73    {
74       delete am;
75       return 0;
76    }
77    
78    std::string dirName = name;
79    
80    bool verbose  = ( 0 != am->ArgMgrDefined("verbose") ); 
81    bool dicomdir = ( 0 != am->ArgMgrDefined("dicomdir") );
82    
83    const char *rootname  = am->ArgMgrGetString("rootname","Patient");
84      
85    if (am->ArgMgrDefined("debug"))
86      GDCM_NAME_SPACE::Debug::DebugOn();
87
88    int loadMode = GDCM_NAME_SPACE::LD_ALL;
89
90    int rubOutNb;
91    uint16_t *elemsToRubOut = am->ArgMgrGetXInt16Enum("rubout", &rubOutNb);
92  
93    // ----------- if unused Param we give up
94    if ( am->ArgMgrPrintUnusedLabels() )
95    { 
96       am->ArgMgrUsage(usage);
97       delete am;
98       return 0;
99    }
100
101    delete am;  // we don't need Argument Manager any longer
102
103  
104   // ---------------------------------------------------------- 
105   
106
107    // ----- Begin Processing -----
108
109    GDCM_NAME_SPACE::DicomDir *dcmdir;
110
111    // we ask for Directory parsing
112
113    dcmdir = GDCM_NAME_SPACE::DicomDir::New( );
114    dcmdir->SetLoadMode(loadMode);
115    dcmdir->SetDirectoryName(dirName);
116    dcmdir->Load();
117
118    if ( verbose )
119       std::cout << "======================= End Parsing Directory" << std::endl;
120       
121     // ----- Check the result
122     
123    if ( !dcmdir->GetFirstPatient() ) 
124    {
125       std::cout << "No patient found (?!?). Exiting."
126                 << std::endl;
127       dcmdir->Delete();
128       return 1;
129    }
130
131    GDCM_NAME_SPACE::DicomDirPatient *pa;
132    GDCM_NAME_SPACE::DicomDirStudy *st;
133    GDCM_NAME_SPACE::DicomDirSerie *se;
134    GDCM_NAME_SPACE::DicomDirImage *im;
135
136    std::string codedName;
137    std::string codedID;
138    std::string fullFileName;
139    std::string patName;
140    std::string patID;
141         
142    GDCM_NAME_SPACE::File *f;
143  
144  
145   //GDCM_NAME_SPACE::Debug::DebugOn();
146   
147    
148    int sequentialPatientNumber = 0;
149    char  char_sequentialPatientNumber[10]; // 999999999 patients in a directory should be enough?
150    pa = dcmdir->GetFirstPatient();    
151    while ( pa )
152    {  // on degouline les PATIENT du DICOMDIR
153    
154       sequentialPatientNumber++;
155       sprintf (char_sequentialPatientNumber, "%d", sequentialPatientNumber);
156       //patName = pa->GetEntryString(0x0010, 0x0010);
157       
158      
159       //codedName = "g^" + GDCM_NAME_SPACE::Util::ConvertToMD5(patName);
160       codedName = "g^" + std::string(rootname) + std::string(char_sequentialPatientNumber);
161       patID = pa->GetEntryString(0x0010, 0x0020);
162       codedID = GDCM_NAME_SPACE::Util::ConvertToMD5(patID);
163       
164       if (verbose) {
165          std::cout << "[" << patName << "] --> [" << codedName << "]" << std::endl;
166          std::cout << "[" << patID   << "] --> [" << codedID   << "]"  << std::endl;                 
167       } 
168       st = pa->GetFirstStudy();
169       while ( st ) 
170       { // on degouline les STUDY de ce patient
171          se = st->GetFirstSerie();
172          while ( se ) 
173          { // on degouline les SERIES de cette study
174             im = se->GetFirstImage();
175             while ( im ) 
176             { // on degouline les Images de cette serie       
177                fullFileName = dirName;
178                const char lastChar = dirName.c_str()[strlen(dirName.c_str())-1];
179                if ( lastChar != '/' && lastChar != '\\')
180                   fullFileName +=  GDCM_NAME_SPACE::GDCM_FILESEPARATOR;
181                fullFileName += im->GetEntryString(0x0004, 0x1500);
182                
183                // -- remove trailing space, if any
184                int pos=fullFileName.length()-1;
185                if (fullFileName[pos] == ' ')
186                {
187                   fullFileName.erase(pos);
188                }
189                // --
190                
191                if (verbose)
192                   std::cout << "FileName [" << fullFileName << "]" << std::endl;
193
194                f = GDCM_NAME_SPACE::File::New( );
195                   f->SetMaxSizeLoadEntry(0x7fff);  // we want to load entries of any length !
196                   f->SetLoadMode(loadMode);
197                   f->SetFileName( fullFileName );
198                if ( !f->Load() )
199                {
200                  std::cout << "Load failed for [" << fullFileName << "]" << std::endl;
201                  //f->Delete();
202                  //continue;  // or return 0; ?
203                }
204                else
205                {
206                   if (verbose)
207                      std::cout << "Load successed for [" << fullFileName << "]" << std::endl;
208                }
209                // 
210                //  Choose the fields to anonymize.
211                // 
212
213                // Institution name 
214                f->AddAnonymizeElement( 0x0008, 0x0080, "Xanadoo" );
215
216                // Patient's name 
217                f->AddAnonymizeElement( 0x0010, 0x0010, codedName ); 
218     
219                // Patient's ID
220                //f->AddAnonymizeElement( 0x0010, 0x0020,"1515" );
221                f->AddAnonymizeElement( 0x0010, 0x0020,codedID );
222                // Patient's Birthdate
223                f->AddAnonymizeElement( 0x0010, 0x0030,"11111111" );
224                // Patient's Adress
225                f->AddAnonymizeElement( 0x0010, 0x1040,"Sing-sing" );
226                // Patient's Mother's Birth Name
227                f->AddAnonymizeElement( 0x0010, 0x1060,"g^Vampirella" );
228        
229                // Study Instance UID
230                // we may not brutaly overwrite it
231                //f->AddAnonymizeElement( 0x0020, 0x000d, "9.99.999.9999" );
232    
233                // Telephone
234                f->AddAnonymizeElement(0x0010, 0x2154, "3615" );
235
236                // deal with user defined Elements set
237
238                for (int ri=0; ri<rubOutNb; ri++)
239                {
240                   f->AddAnonymizeElement((uint32_t)elemsToRubOut[2*ri], 
241                                          (uint32_t)elemsToRubOut[2*ri+1],"*" ); 
242                }
243
244    // ============================================================
245    //   Load the pixels in memory.
246    // ============================================================
247
248                // We need a gdcm::FileHelper, since we want to load the pixels        
249                GDCM_NAME_SPACE::FileHelper *fh = GDCM_NAME_SPACE::FileHelper::New(f);
250
251                // unit8_t DOESN'T mean it's mandatory for the image to be a 8 bits one !
252                // Feel free to cast if you know it's not.
253
254                uint8_t *imageData = fh->GetImageData();
255
256                if ( imageData == 0 )
257                {
258                    std::cerr << "Sorry, Pixels of [" << fullFileName <<"]  are not "
259                              << " gdcm-readable."       << std::endl
260                              << "Use exAnonymizeNoLoad" << std::endl;
261                    f->Delete();
262                    fh->Delete();
263                    return 0;
264                }
265                
266    // ============================================================
267               f->AnonymizeFile();    
268               f->ClearAnonymizeList();
269               
270               fh->SetContentType(GDCM_NAME_SPACE::UNMODIFIED_PIXELS_IMAGE);
271               fh->Write(fullFileName);  // WARNING : overwrites the file!
272               
273               im = se->GetNextImage(); 
274               f->Delete();
275               fh->Delete();                  
276            }
277            se = st->GetNextSerie();   
278         }
279         st = pa->GetNextStudy();
280      }     
281      pa = dcmdir->GetNextPatient();      
282    }
283
284    dcmdir->Delete();
285    
286    if (dicomdir)
287    {
288       std::cout << "DICOMDIR creation in progress ..." << std::endl;      
289       dcmdir = GDCM_NAME_SPACE::DicomDir::New( );
290       dcmdir->SetLoadMode(loadMode);
291       dcmdir->SetDirectoryName(dirName);
292       dcmdir->Load();
293       dcmdir->Write("DICOMDIR");   
294    }
295              
296    return 0;
297    
298 }