From 7e08dfdddb5b4ce6f74b82f4c82391cdc2a1c539 Mon Sep 17 00:00:00 2001 From: jpr Date: Wed, 12 Sep 2007 10:43:47 +0000 Subject: [PATCH] Some cleaning in examples for extracting Overlays --- Example/exExtractOverlaysACR.cxx | 309 +++++++++++++++++++++++++++++++ Example/exExtractOverlaysDCM.cxx | 273 +++++++++++++++++++++++++++ 2 files changed, 582 insertions(+) create mode 100644 Example/exExtractOverlaysACR.cxx create mode 100755 Example/exExtractOverlaysDCM.cxx diff --git a/Example/exExtractOverlaysACR.cxx b/Example/exExtractOverlaysACR.cxx new file mode 100644 index 00000000..c992b01a --- /dev/null +++ b/Example/exExtractOverlaysACR.cxx @@ -0,0 +1,309 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: exExtractOverlaysACR.cxx,v $ + Language: C++ + Date: $Date: 2007/09/12 10:43:47 $ + 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. + +=========================================================================*/ +#include "gdcmFile.h" +#include "gdcmFileHelper.h" +#include "gdcmCommon.h" +#include "gdcmDebug.h" +#include "gdcmDocEntry.h" +#include +#include // for fseek... FIXME +#include // for atoi + +#include "gdcmArgMgr.h" + + // WARNING : + // unfinished : DO NOT to be used as is ! + + /* + // Example (sorry, we've got no more than this one ...) + +V 0028|0010[US] [Rows] [256] x(100) +V 0028|0011[US] [Columns] [256] x(100) +V 0028|0030[DS] [Pixel Spacing] [01.56\1.56] +V 0028|0100[US] [Bits Allocated] [16] x(10) +V 0028|0101[US] [Bits Stored] [12] x(c) +V 0028|0102[US] [High Bit] [11] x(b) +V 0028|0103[US] [Pixel Representation] [0] x(0) + +V 6000|0000[UL] [Group Length] [96] x(60) +V 6000|0010[US] [Rows] [256] x(100) +V 6000|0011[US] [Columns] [256] x(100) +V 6000|0040[CS] [Overlay Type] [R ] +V 6000|0050[SS] [Overlay Origin] [23601\8241] x(5c31) +V 6000|0100[US] [Overlay Bits Allocated] [16] x(10) +V 6000|0102[US] [Overlay Bit Position] [12] x(c) +... +... +V 6006|0000[UL] [Group Length] [96] x(60) +V 6006|0010[US] [Rows] [256] x(100) +V 6006|0011[US] [Columns] [256] x(100) +V 6006|0040[CS] [Overlay Type] [R ] +V 6006|0050[SS] [Overlay Origin] [23601\8241] x(5c31) +V 6006|0100[US] [Overlay Bits Allocated] [16] x(10) +V 6006|0102[US] [Overlay Bit Position] [15] x(f) + */ + +int main(int argc, char *argv[]) +{ + START_USAGE(usage) + " \n exExtractOverlaysACR :\n ", + " Extract ACR-NEMA style overlays from an image ", + " usage: exExtractOverlaysACR filein=inputDirectoryName [debug] ", + " debug : developper wants to run the program in 'debug mode' ", + FINISH_USAGE + + // ----- Initialize Arguments Manager ------ + + GDCM_NAME_SPACE::ArgMgr *am = new GDCM_NAME_SPACE::ArgMgr(argc, argv); + + if (argc == 1 || am->ArgMgrDefined("usage")) + { + am->ArgMgrUsage(usage); // Display 'usage' + delete am; + return 0; + } + + // "SIEMENS_GBS_III-16-ACR_NEMA_1.acr" + + const char *fileName = am->ArgMgrWantString("filein", usage); + + if (am->ArgMgrDefined("debug")) + GDCM_NAME_SPACE::Debug::DebugOn(); + + if (am->ArgMgrDefined("warning")) + GDCM_NAME_SPACE::Debug::WarningOn(); + + // if unused Param we give up + if ( am->ArgMgrPrintUnusedLabels() ) + { + am->ArgMgrUsage(usage); + delete am; + return 0; + } + + delete am; // we don't need Argument Manager any longer + + + // ========================== Now, we can do the job! ================ + + GDCM_NAME_SPACE::File *f; + + +// ============================================================ +// Read the input image. +// ============================================================ + + //std::cout << argv[1] << std::endl; + + f = GDCM_NAME_SPACE::File::New( ); + + f->SetLoadMode(GDCM_NAME_SPACE::LD_NOSEQ | GDCM_NAME_SPACE::LD_NOSHADOW); + f->SetFileName( fileName ); + bool res = f->Load(); + + if( GDCM_NAME_SPACE::Debug::GetDebugFlag() ) + { + std::cout << "---------------------------------------------" << std::endl; + f->Print(); + std::cout << "---------------------------------------------" << std::endl; + } + if (!res) { + std::cout << "Sorry, " << fileName <<" not a gdcm-readable " + << "DICOM / ACR File" + <Delete(); + return 0; + } + std::cout << " ... is readable " << std::endl; + +// ============================================================ +// Check whether image contains Overlays ACR-NEMA style. +// ============================================================ + + int bitsAllocated = f->GetBitsAllocated(); + if ( bitsAllocated <= 8 ) + { + std::cout << " 8 bits pixel image cannot contain Overlays " << std::endl; + f->Delete(); + return 0; + } + std::string s1 = f->GetEntryString(0x6000, 0x0102); + if (s1 == GDCM_NAME_SPACE::GDCM_UNFOUND) + { + std::cout << " Image doesn't contain any Overlay " << std::endl; + f->Delete(); + return 0; + } + std::cout << " File is read! " << std::endl; + + +// ============================================================ +// Load the pixels in memory. +// ============================================================ + + int nx = f->GetXSize(); + int ny = f->GetYSize(); + + GDCM_NAME_SPACE::FileHelper *fh1 = GDCM_NAME_SPACE::FileHelper::New(f); + fh1->SetKeepOverlays(true); + uint16_t *pixels = (uint16_t *)fh1->GetImageDataRaw(); + int lgt = fh1->GetImageDataRawSize(); + + if( GDCM_NAME_SPACE::Debug::GetDebugFlag() ) + std::cout << "Pixels read as expected : length = " << lgt << std::endl; + +// ============================================================ +// Prepare the stuff +// ============================================================ + + uint8_t *tabPixels = new uint8_t[nx*ny]; // uint8 is enought to hold 1 bit ! + + uint16_t currentOvlGroup = 0x6000; + std::string strOvlBitPosition; + int ovlBitPosition; + uint16_t mask; + int i = 0; + uint16_t overlayLocation; + std::ostringstream str; + + std::string strOverlayLocation; + + GDCM_NAME_SPACE::File *fileToBuild = 0; + GDCM_NAME_SPACE::FileHelper *fh = 0; + +// ============================================================ +// Get each overlay Bit into an image +// ============================================================ + for(i=0, currentOvlGroup=0x6000; i<32; i+=2 ,currentOvlGroup+=2) + { + if ( (strOvlBitPosition = f->GetEntryString(currentOvlGroup, 0x0102)) + == GDCM_NAME_SPACE::GDCM_UNFOUND ) + continue; + + if( GDCM_NAME_SPACE::Debug::GetDebugFlag() ) + std::cout << "Current Overlay Group " << std::hex << currentOvlGroup + << " OvlBitPosition " << strOvlBitPosition << std::endl; + + strOverlayLocation = f->GetEntryString(currentOvlGroup, 0x0200); + if ( strOverlayLocation != GDCM_NAME_SPACE::GDCM_UNFOUND ) + { + overlayLocation = atoi(strOverlayLocation.c_str()); + if ( overlayLocation != f->GetGrPixel() ) + { + std::cout << "Big Trouble : Overlays are NOT in the Pixels Group " + << std::hex << "(" << overlayLocation << " vs " + << f->GetGrPixel() << std::endl; + // Actually, here, we should (try to) read the overlay location + // and go on the job. + continue; + } + } + ovlBitPosition = atoi(strOvlBitPosition.c_str()); + mask = 1 << ovlBitPosition; + + if( GDCM_NAME_SPACE::Debug::GetDebugFlag() ) + std::cout << "Mask :[" <= 0x1000)// if it contains at least one overlay bit + printf("%d : %04x\n",j, pixels[j]); + + if ( (pixels[j] & mask) == 0 ) + tabPixels[j] = 0; + else + tabPixels[j] = 128; + } + if( GDCM_NAME_SPACE::Debug::GetDebugFlag() ) + std::cout << "About to built empty file" << std::endl; + + fileToBuild = GDCM_NAME_SPACE::File::New(); + + if( GDCM_NAME_SPACE::Debug::GetDebugFlag() ) + std::cout << "Finish to built empty file" << std::endl; + + str.str(""); + str << nx; + fileToBuild->InsertEntryString(str.str(),0x0028,0x0011); // Columns + str.str(""); + str << ny; + fileToBuild->InsertEntryString(str.str(),0x0028,0x0010); // Rows + + fileToBuild->InsertEntryString("8",0x0028,0x0100); // Bits Allocated + fileToBuild->InsertEntryString("8",0x0028,0x0101); // Bits Stored + fileToBuild->InsertEntryString("7",0x0028,0x0102); // High Bit + fileToBuild->InsertEntryString("0",0x0028,0x0103); // Pixel Representation + fileToBuild->InsertEntryString("1",0x0028,0x0002); // Samples per Pixel + + fileToBuild->InsertEntryString("MONOCHROME2 ",0x0028,0x0004); + // Other mandatory fields will be set automatically, + // just before Write(), by FileHelper::CheckMandatoryElements() + + if( GDCM_NAME_SPACE::Debug::GetDebugFlag() ) + std::cout << "-------------About to built FileHelper" << std::endl; + + fh = GDCM_NAME_SPACE::FileHelper::New(fileToBuild); + + if( GDCM_NAME_SPACE::Debug::GetDebugFlag() ) + std::cout << "-------------Finish to built FileHelper" << std::endl; + + fh->SetImageData(tabPixels,nx*ny); + fh->SetWriteTypeToDcmExplVR(); + +std::ostringstream tmp; +tmp < Why doesn't it work ?!? + //str << fileName << std::hex << currentOvlGroup << ".dcm" << std::ends; + +str << fileName << ".ovly." << tmp.str() << ".dcm" << std::ends; + + // Write the current 'overlay' file + + if( !fh->Write(str.str()) ) + { + std::cout << "Failed\n" + << "File [" << str.str() << "] is unwrittable" << std::endl; + /* + fh->Delete(); + if (fileToBuild) + fileToBuild->Delete(); + delete pixels; + delete tabPixels; + return 0; + */ + } + else + { + std::cout << "File written successfully [" << str.str() << "]" << std::endl; + } + } + + if (f) + fh->Delete(); + if (fileToBuild) + fileToBuild->Delete(); + f->Delete(); + delete pixels; + delete tabPixels; + + return 0; +} + diff --git a/Example/exExtractOverlaysDCM.cxx b/Example/exExtractOverlaysDCM.cxx new file mode 100755 index 00000000..6e10dbcf --- /dev/null +++ b/Example/exExtractOverlaysDCM.cxx @@ -0,0 +1,273 @@ +/*========================================================================= + + Program: gdcm + Module: $RCSfile: exExtractOverlaysDCM.cxx,v $ + Language: C++ + Date: $Date: 2007/09/12 10:43:47 $ + 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. + +=========================================================================*/ + + +#include "gdcmFile.h" +#include "gdcmFileHelper.h" +#include "gdcmCommon.h" +#include "gdcmDebug.h" +#include "gdcmDataEntry.h" +#include "gdcmDirList.h" + +#include "gdcmArgMgr.h" +#include + +// Each BIT of Overlay Data (0x6000,0x3000) corresponds +// to a BYTE of overlay image. +void explodeByte(unsigned char byte, unsigned char* result) +{ + unsigned char mask = 1; + for (int i=0;i<8;i++) + { + if ((byte & mask)==0) + result[i]=0; + else + result[i]=1; + mask<<=1; + } + return; +} + + +int main(int argc, char *argv[]) +{ + START_USAGE(usage) + " \n ExtractOverlays :\n ", + " Extract overlay images from all DICOM image within a directory ", + " Warning : probably segfaults if no overlay ", + " usage: ExtractOverlays dirin=inputDirectoryName [debug] ", + " debug : developper wants to run the program in 'debug mode' ", + FINISH_USAGE + + // ----- Initialize Arguments Manager ------ + + GDCM_NAME_SPACE::ArgMgr *am = new GDCM_NAME_SPACE::ArgMgr(argc, argv); + + if (argc == 1 || am->ArgMgrDefined("usage")) + { + am->ArgMgrUsage(usage); // Display 'usage' + delete am; + return 0; + } + + const char *dirIn = am->ArgMgrWantString("dirin", usage); + + if (am->ArgMgrDefined("debug")) + GDCM_NAME_SPACE::Debug::DebugOn(); + + if (am->ArgMgrDefined("warning")) + GDCM_NAME_SPACE::Debug::WarningOn(); + + // if unused Param we give up + if ( am->ArgMgrPrintUnusedLabels() ) + { + am->ArgMgrUsage(usage); + delete am; + return 0; + } + + delete am; // we don't need Argument Manager any longer + + + // ========================== Now, we can do the job! ================ + + + // ======================== more checking on the params ============== + + if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirIn) ) + { + std::cout << "KO : [" << dirIn << "] is not a Directory." << std::endl; + return 0; + + } + + char outputFileName[1024]; // Hope it's enough for a file name! + + GDCM_NAME_SPACE::File *f; + + GDCM_NAME_SPACE::DirList dirList(dirIn,true); // gets (recursively) the file list + GDCM_NAME_SPACE::DirListType fileList = dirList.GetFilenames(); + for( GDCM_NAME_SPACE::DirListType::iterator it = fileList.begin(); + it != fileList.end(); + ++it ) + { + // Just to see *all* the file names: + // std::cout << "file [" << it->c_str() << "]" << std::endl; + + // Read the input file. + + if( GDCM_NAME_SPACE::Debug::GetWarningFlag() ) + std::cerr << "Deal with [" << it->c_str() + << "] File" <SetLoadMode( GDCM_NAME_SPACE::LD_ALL ); + f->SetFileName( it->c_str() ); + + f->AddForceLoadElement(0x6000,0x3000); // Overlay Data + f->AddForceLoadElement(0x6002,0x3000); + f->AddForceLoadElement(0x6004,0x3000); + f->AddForceLoadElement(0x6006,0x3000); + f->AddForceLoadElement(0x6008,0x3000); + f->AddForceLoadElement(0x600a,0x3000); + f->AddForceLoadElement(0x600c,0x3000); + f->AddForceLoadElement(0x600e,0x3000); + f->AddForceLoadElement(0x6010,0x3000); + f->AddForceLoadElement(0x6012,0x3000); + f->AddForceLoadElement(0x6014,0x3000); + f->AddForceLoadElement(0x6016,0x3000); + f->AddForceLoadElement(0x6018,0x3000); + f->AddForceLoadElement(0x601a,0x3000); + f->AddForceLoadElement(0x601c,0x3000); + f->AddForceLoadElement(0x601e,0x3000); // Hope it's enought : Dicom says 60xx ... + + int res = f->Load(); + + if ( !res ) + { + std::cerr << "Sorry, " << it->c_str() <<" not a gdcm-readable " + << "DICOM / ACR File" <Delete(); + continue; + } + + if( GDCM_NAME_SPACE::Debug::GetWarningFlag() ) + std::cout << " ... is readable " << std::endl; + + // ============================================================ + // Load Overlay info in memory + // ============================================================ + +/// \todo : deal with *each* overlay Data Element (not only the first one!) + + uint16_t ovlyGroup = 0x6000; + + for (int k=0; k<32; k+=2) + { + + GDCM_NAME_SPACE::DataEntry *e10 = f->GetDataEntry(ovlyGroup+k, 0x0010); // nb Row Ovly + if (e10 == 0) + { + if( GDCM_NAME_SPACE::Debug::GetWarningFlag() ) + std::cout << " Image doesn't contain Overlay on " <GetXSize(); + unsigned int dimY= f->GetYSize(); + unsigned int dimXY=dimX*dimY; + + unsigned char *outputData = new unsigned char[dimXY]; + + + GDCM_NAME_SPACE::DataEntry *e = f->GetDataEntry(ovlyGroup+k, 0x3000); + if (e == 0) + { + if( GDCM_NAME_SPACE::Debug::GetWarningFlag() ) + std::cout << " Image doesn't contain DICOM Overlay Data " <GetImageDataRaw(); + + if (pixelData == 0) + { + std::cerr << "Sorry, Pixel Data of [" << it->c_str() <<"] are not " + << " gdcm-readable." << std::endl; + continue; + } + + } + else + { + uint8_t *overlay = (uint8_t *)(e->GetBinArea()); + if ( overlay == 0 ) + { + std::cerr << "Sorry, Overlays of [" << it->c_str() <<"] are not " + << " gdcm-readable." << std::endl; + continue; + } + if( GDCM_NAME_SPACE::Debug::GetWarningFlag() ) + std::cout << " Overlay on group [" << std::hex << ovlyGroup+k << "] is read! " << std::endl; + + // ============================================================ + // DICOM Overlay Image data generation + // ============================================================ + + + unsigned char *result=outputData; + for (unsigned int i=0;i<(dimXY/8);i++) + { + explodeByte(overlay[i], result); + result+=8; + } + } + // ============================================================ + // Write a new file + // ============================================================ + + GDCM_NAME_SPACE::File *f2; + f2 = GDCM_NAME_SPACE::File::New( ); + GDCM_NAME_SPACE::FileHelper *fh2 = GDCM_NAME_SPACE::FileHelper::New(f2); + + char temp[256]; + + sprintf(temp,"%d ",dimX); + f2->InsertEntryString(temp,0x0028,0x0011, "US"); // Columns + sprintf(temp,"%d ",dimY); + f2->InsertEntryString(temp,0x0028,0x0010, "US"); // Rows + f2->InsertEntryString("8",0x0028,0x0100, "US"); // Bits Allocated + f2->InsertEntryString("8",0x0028,0x0101, "US"); // Bits Stored + f2->InsertEntryString("7",0x0028,0x0102, "US"); // High Bit + f2->InsertEntryString("0",0x0028,0x0103, "US"); // Pixel Representation + f2->InsertEntryString("1",0x0028,0x0002, "US"); // Samples per Pixel + f2->InsertEntryString("MONOCHROME2 ",0x0028,0x0004, "LO"); + + // feel free to add any field (Dicom Data Entry) you like, here. + // ... + + sprintf(outputFileName, "../%s.ovly.%04x.dcm",it->c_str(), ovlyGroup+k); + + fh2->SetImageData(outputData,dimXY); + fh2->WriteDcmExplVR(outputFileName); + + std::cout <<"File written successfully [" << outputFileName << "]" <Delete(); + fh2->Delete(); + + } // end on loop on 60xx + + f->Delete(); + + +} // end of loop on files ( DirListType::iterator ) + + return 0; +} + -- 2.45.1