From 88d171f185620221627d10d9f59cb0856df098c0 Mon Sep 17 00:00:00 2001 From: jpr Date: Wed, 19 Jul 2006 09:03:24 +0000 Subject: [PATCH] // // This program is used to convert huge amounts of functionnal (3D + T) MR images // into 'image tiles' (one title per volume) processable by clinical softwares // --- Example/exConvert3DplusT.cxx | 389 +++++++++++++++++++++++++++++++++++ 1 file changed, 389 insertions(+) create mode 100755 Example/exConvert3DplusT.cxx diff --git a/Example/exConvert3DplusT.cxx b/Example/exConvert3DplusT.cxx new file mode 100755 index 00000000..5e3eafc7 --- /dev/null +++ b/Example/exConvert3DplusT.cxx @@ -0,0 +1,389 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: exConvert3DplusT.cxx,v $ + Language: C++ + Date: $Date: 2006/07/19 09:03:24 $ + Version: $Revision: 1.1 $ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +// +// This program is used to convert huge amounts of functionnal (3D + T) MR images +// into 'image tiles' (one title per volume) processable by clinical softwares +// +#include "gdcmFile.h" +#include "gdcmFileHelper.h" +#include "gdcmCommon.h" +#include "gdcmDebug.h" +#include "gdcmDirList.h" +#include "gdcmUtil.h" + +#include "gdcmArgMgr.h" + +#include +#include +#include // for memset + +int main(int argc, char *argv[]) +{ + START_USAGE(usage) + "\n exConvert3plusT :\n ", + " Converts the Dicom files inside a single-level Directory ", + " into a '3D + T' image set ", + " usage: exConvert3plusT ", + " dirin=inputDirectoryName ", + " dirout=outputDirectoryName ", + " [studyUID = ] [patName = ] ", + " [ { [noshadowseq] | [noshadow][noseq] } ] [debug] [verbose]", + " ", + " dirin : single-level Directory containing the images ", + " (no recursive parsing) ", + " dirout : will be created if doesn't exist ", + " ", + " [imdimx = ] [imdimy = ] [imgline = ] [imgcol = ] ", + " [pixelsize = ] [imagesinvolume = ] ", + " ", + " studyUID : *aware* user wants to add the serie ", + " to an already existing study ", + " imdimx,imdimy : 'elementary image' size (default : 64) ", + " used to reject erroneous images ", + " imgline, imgcol : sizes of the 'image tile' defaulted as 6x6 ", + " pixelsize : in bytes; defaulted as 2 (uint16_t) ", + " used to reject erroneous images ", + " imagesinvolume : we have no way to guess it! ", + " defaulted as imgline*imgcol ", + " noshadowseq: user doesn't want to load Private Sequences ", + " noshadow : user doesn't want to load Private groups (odd number) ", + " noseq : user doesn't want to load Sequences ", + " verbose : user wants to run the program in 'verbose mode' ", + " debug : developper wants to run the program in 'debug mode' ", + FINISH_USAGE + + + // ----- Initialize Arguments Manager ------ + + gdcm::ArgMgr *am = new gdcm::ArgMgr(argc, argv); + + if (am->ArgMgrDefined("usage") || argc == 1) + { + am->ArgMgrUsage(usage); // Display 'usage' + delete am; + return 0; + } + + if (am->ArgMgrDefined("debug")) + gdcm::Debug::DebugOn(); + int verbose = am->ArgMgrDefined("verbose"); + int oververbose = am->ArgMgrDefined("oververbose"); + + std::string patName = am->ArgMgrGetString("patname", "g^PatientName"); + //float zSpacing = am->ArgMgrGetFloat("zSpacing", 1.0); + + const char *dirIn = am->ArgMgrGetString("dirin"); + const char *dirOut = am->ArgMgrGetString("dirout"); + + bool userDefinedStudy = am->ArgMgrDefined("studyUID"); + const char *studyUID = am->ArgMgrGetString("studyUID"); + +// not described *on purpose* in the Usage ! + bool userDefinedSerie = am->ArgMgrDefined("serieUID"); + const char *serieUID = am->ArgMgrGetString("serieUID"); + + + int imageDimX = am->ArgMgrGetInt("imdimx",64); + int imageDimY = am->ArgMgrGetInt("imdimy",64); + int imagePixelSize = am->ArgMgrGetInt("pixelsize", 2); + int imagetteLineNumber = am->ArgMgrGetInt("imgline",6); + int imagetteRowNumber = am->ArgMgrGetInt("imgcol",6); + int nbOfImagesInVolume = am->ArgMgrGetInt("imagesinvolume", + imagetteLineNumber*imagetteRowNumber); + + int loadMode = gdcm::LD_ALL; + if ( am->ArgMgrDefined("noshadowseq") ) + loadMode |= gdcm::LD_NOSHADOWSEQ; + else + { + if ( am->ArgMgrDefined("noshadow") ) + loadMode |= gdcm::LD_NOSHADOW; + if ( am->ArgMgrDefined("noseq") ) + loadMode |= gdcm::LD_NOSEQ; + } + + /* if unused Param we give up */ + if ( am->ArgMgrPrintUnusedLabels() ) + { + am->ArgMgrUsage(usage); + delete am; + return 0; + } + + delete am; // ------ we don't need Arguments Manager any longer ------ + + // ====== Deal with a (single level, single Patient) Directory ====== + + + //std::cout << "dirIn [" << dirIn << "]" << std::endl; + if ( ! gdcm::DirList::IsDirectory(dirIn) ) + { + std::cout << "KO : [" << dirIn << "] is not a Directory." << std::endl; + return 0; + + } + else + { + if (verbose) + std::cout << "OK : [" << dirIn << "] is a Directory." << std::endl; + } + + std::string systemCommand; + std::string strDirNameout(dirOut); // to please gcc 4 + if (verbose) + std::cout << "Check for output directory :[" << dirOut << "]." + <SetLoadMode(loadMode); + f->SetFileName( it->c_str() ); + + if (verbose) + std::cout << "file [" << it->c_str() << "]" << std::endl; + if ( !f->Load() ) + { + if (verbose) + std::cout << "fail to load [" << it->c_str() << "]" << std::endl; + f->Delete(); + continue; + } + + // Load the pixels in RAM. + + fh = gdcm::FileHelper::New(f); + // Don't convert (Gray Pixels + LUT) into (RGB pixels) ?!? + + tabImageData[imageNumber] = (int16_t *)fh->GetImageDataRaw(); + if (!tabImageData[imageNumber]) + { + std::cout << "fail to read [" << it->c_str() << std::endl; + continue; + } + int16_t mini=32000; + int16_t maxi=-32000; + + if (imageNumber == nbOfImagesInVolume) + { + for(imageNumber=0; imageNumber < nbOfImagesInVolume; imageNumber++) + { + int debMove = (imageNumber%imagetteRowNumber) * imageDimX + + (imageNumber/imagetteRowNumber) *imageDimX*imageDimY*imagetteRowNumber; + + if (verbose) + std::cout << "imageNumber " << imageNumber << " debMove " << debMove << std::endl; + + for(int i=0; i 100) imageTable[debLigne + j]=100; + //std::cout << debLigne + j << " : " << imageTable[debLigne + j] << std::endl; + + if (*(tabImageData[imageNumber] + i*imageDimY + j) < mini) + mini=*(tabImageData[imageNumber] + i*imageDimY + j); + else if (*(tabImageData[imageNumber] + i*imageDimY + j) > maxi) + maxi=*(tabImageData[imageNumber] + i*imageDimY + j); + } + } + } + // if (oververbose) + // std::cout << " mini = " << mini << " maxi = " << maxi << std::endl; + // just to check (actually, it's useless) + /* + int16_t mini=32000; + int16_t maxi=-32000; + for (int k=0; k < totalNumberOfPixels; k++) + { + if (imageTable[k] < mini) mini=imageTable[k]; + else if (imageTable[k] > maxi) maxi=imageTable[k]; + } + + // if (oververbose) + // std::cout << " mini = " << mini << " maxi = " << maxi << std::endl; + /// \todo : FIXME what do I do ? Smallest/Largest Image Pixel Value is vr=US, Pixels are signed ?!? + + str.str(""); + str << mini; + fh->InsertEntryString(str.str(),0x0028,0x0106, "US"); // Smallest Image Pixel Value + + str.str(""); + str << maxi; + fh->InsertEntryString(str.str(),0x0028,0x0107, "US"); // Largest Image Pixel Value +*/ + imageNumber = 0; + + // write the imagette + + // Set the image size + str.str(""); + str << imageDimX*imagetteRowNumber; + fh->InsertEntryString(str.str(),0x0028,0x0011, "US"); // Columns + + str.str(""); + str << imageDimY*imagetteLineNumber; + fh->InsertEntryString(str.str(),0x0028,0x0010, "US"); // Rows + + fh->InsertEntryString(strStudyUID,0x0020,0x000d,"UI"); + fh->InsertEntryString(strSerieUID,0x0020,0x000e,"UI"); + fh->InsertEntryString(patName,0x0010,0x0010, "PN"); // Patient's Name + + fh->SetImageData((uint8_t *)imageTable, totalNumberOfPixels * imagePixelSize); + +// ================================================================================================== + +// This is a dirty heuristics, but no other way :-( + +// if Image Orientation (Patient) is not present +// I create one, (as Axial) +// if Image Position (Patient) is not present +// I create one, incrementing zPositionComponent up by user supplied zSpacing +// if Slice Location is not present +// I create one, as zPositionComponent +// +// Aware use is free to supply his own one ! + +/* + if (! f->CheckIfEntryExist(0x0020,0x0037) ) // 0020 0037 DS 6 Image Orientation (Patient) + { + fh->InsertEntryString("1.0\\0.0\\0.0\\0.0\\1.0\\0.0",0x0020,0x0037, "DS"); //[1\0\0\0\1\0] : Axial + + char charImagePosition[256]; + + sprintf(charImagePosition,"%f\\0.0\\0.0",zPositionComponent); + zPositionComponent += zSpacing; + + if (! f->CheckIfEntryExist(0x0020,0x0032) ) //0020 0032 DS 3 Image Position (Patient) + fh->InsertEntryString(charImagePosition,0x0020,0x0032, "DS"); + + if (! f->CheckIfEntryExist(0x0020,0x1041) ) // 0020 0x1041 DS 1 Slice Location + { + sprintf(charImagePosition,"%f",zPositionComponent); + fh->InsertEntryString(charImagePosition,0x0020,0x1041, "DS"); + } + } + +*/ + +// ================================================================================================== + + fh->SetWriteTypeToDcmExplVR(); + fh->SetContentType(gdcm::UNMODIFIED_PIXELS_IMAGE); + + + lastFilename = gdcm::Util::GetName( fullFilename ); + std::string fullWriteFilename = strDirNameout + gdcm::GDCM_FILESEPARATOR + + lastFilename; + if (verbose) + std::cout << "Write : [" << fullWriteFilename << "]" << std::endl; + if (!fh->Write(fullWriteFilename)) + { + std::cout << "Fail to write :[" << fullWriteFilename << "]" + << std::endl; + } + //break; + } // end : 'write the imagette' + else + { + imageNumber++; + } + fh->Delete(); + f->Delete(); + } +} -- 2.48.1