1 /*=========================================================================
4 Module: $RCSfile: DenseToDicom.cxx,v $
6 Date: $Date: 2007/06/21 15:06:13 $
7 Version: $Revision: 1.3 $
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.
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.
17 =========================================================================*/
24 #include "gdcmFileHelper.h"
25 #include "gdcmDebug.h"
26 #include "gdcmDirList.h"
28 #include "gdcmArgMgr.h"
32 * - explores recursively the given directory
33 * - examines the ".txt" files
34 * - Converts the files into 16 bits Dicom Files,
38 void Load(std::ifstream &from, std::string imageName);
39 //std::ifstream& eatwhite(std::ifstream& is);
42 window center (level) and width, are defined in the DICOM
43 standard very precisely as follows (see PS 3.3 C.11.2.1.2):
45 >"These Attributes are applied according to the following pseudo-code,
48 y is an output value with a range from ymin to ymax,
49 c is Window Center (0028,1050)
50 w is Window Width (0028,1051):
52 > if (x <= c - 0.5 - (w-1)/2), then y = ymin
53 > else if (x > c - 0.5 + (w-1)/2), then y = ymax,
54 > else y = ((x - (c - 0.5)) / (w-1) + 0.5) * (ymax - ymin)+ ymin
58 From: David Clunie - view profile
59 Date: Thurs, Jun 1 2006 3:03 pm
60 Email: David Clunie <dclu...@dclunie.com>
61 Groups: comp.protocols.dicom
63 The value of x is the output of the preceding step, the so-called
64 "modality LUT", which may either be:
66 - identity (no rescale values or Modality LUT, or the SOP Class is
67 PET and rescale values are ignored), in which case x is the stored
68 pixel value in (7FE0,0010)
70 - Rescale Slope and Intercept (as typically used in CT), in which
71 case x is the value obtained from applying the rescale values to
72 the stored pixel value
74 - an actual LUT, in which case x is the value stored in the LUT
75 corresponding to the LUT index value that is the stored pixel
78 The ymin and ymax are intended to represent the output range; for
79 example, if the hypothetical Presentation LUT step that follows
80 the VOI LUT (window) stage is an identity operation, then the
81 ymin and ymax represent P-Values, which might be the range of
82 digital driving levels for your display (calibrated to the GSDF),
83 in the 8-bit wide output case ranging from 0 to 255, for example.
85 The terms brightness and contrast are not used in radiology imaging
86 - the window center and width are used instead.
89 int main(int argc, char *argv[])
92 " \n DenseToDicom :\n ",
93 " - explores recursively the given directory, ",
94 " - examines the '.txt' files ",
95 " - Converts the files into 16 bits Dicom Files, ",
97 " DenseToDicom dirin=rootDirectoryName ",
98 " [listonly] [verbose] [debug] ",
100 " verbose : user wants to run the program in 'verbose mode' ",
101 " debug : *developer* wants to run the program in 'debug mode' ",
104 // ----- Initialize Arguments Manager ------
106 GDCM_NAME_SPACE::ArgMgr *am = new GDCM_NAME_SPACE::ArgMgr(argc, argv);
108 if (argc == 1 || am->ArgMgrDefined("usage"))
110 am->ArgMgrUsage(usage); // Display 'usage'
115 const char *dirNamein;
116 dirNamein = am->ArgMgrGetString("dirin",".");
118 if (am->ArgMgrDefined("debug"))
119 GDCM_NAME_SPACE::Debug::DebugOn();
121 int verbose = am->ArgMgrDefined("verbose");
122 int listonly = am->ArgMgrDefined("listonly");
124 // if unused Param we give up
125 if ( am->ArgMgrPrintUnusedLabels() )
127 am->ArgMgrUsage(usage);
131 delete am; // we don't need Argument Manager any longer
133 // ----- Begin Processing -----
135 if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirNamein) )
137 std::cout << "KO : [" << dirNamein << "] is not a Directory." << std::endl;
142 std::cout << "OK : [" << dirNamein << "] is a Directory." << std::endl;
145 std::string strDirNamein(dirNamein);
146 GDCM_NAME_SPACE::DirList dirList(strDirNamein, true); // get recursively the list of files
150 std::cout << "------------List of found files ------------" << std::endl;
152 std::cout << std::endl;
156 std::string filenameout;
158 GDCM_NAME_SPACE::DirListType fileNames;
159 fileNames = dirList.GetFilenames();
160 for (GDCM_NAME_SPACE::DirListType::iterator it = fileNames.begin();
161 it != fileNames.end();
164 std::ifstream from( (*it).c_str() );
167 std::cout << "Can't open file" << *it << std::endl;
172 filenameout = *it + ".dcm";
173 std::cout << "Success in open file" << *it << std::endl;
174 Load(from, filenameout);
181 void Load(std::ifstream &from, std::string imageName)
202 std::cout << "nx " << nx << " ny " << ny << std::endl;
205 std::getline(from, str1);
206 std::cout << "[" << str1 << "]" << std::endl;
207 std::getline(from, str1);
208 std::cout << "[" << str1 << "]" << std::endl;
209 std::getline(from, str1);
210 std::cout << "[" << str1 << "]" << std::endl;
212 //float *f = new float(nx*ny);
213 float *f = (float *) malloc(nx*ny*sizeof(float));
214 // float mini = FLT_MAX, maxi = FLT_MIN;
216 for( int j=0; j<ny; j++)
219 for (int i=0; i<nx; i++)
233 val = (float)atof(str1.c_str());
236 // In our concern, just *100 all the values is enough!
242 //std::cout << val << " ";
246 std::cout << "Missing values at [" << j <<"," << i << "]"
252 //std::cout << std::endl << " line nb : " << j
253 // << " line length : " << l << std::endl;
257 // std::cout << "mini : "<< mini << " maxi : " << maxi << std::endl;
259 // values are expressed as %.
260 // It's useless to rescale them as uint16_t : just *100
261 uint16_t *img = new uint16_t[ny*nx];
264 float div = maxi-mini;
265 std::cout << "div : " << div << " mini : " << mini << std::endl;
266 for( int k=0; k<ny*nx; k++)
268 *ptr = (uint16_t)((*tmp * 65535.0) / div);
274 uint16_t *img = new uint16_t[ny*nx];
277 for( int k=0; k<ny*nx; k++)
279 *ptr = (uint16_t)(*tmp *100);
285 Vtk/Python Theralys code for Rescale Slope, Rescale Intercept
287 mini,maxi=data.GetScalarRange()
290 if mini<=-pow(2,maxPow):mini=-pow(2,maxPow)+1
291 if maxi>pow(2,maxPow):maxi=pow(2,maxPow)
292 maxi=math.ceil(maxi)+1
293 mini=math.ceil(mini-.5)
294 slope,intercept=(pow(2,16)-1)/(maxi-mini),-mini
295 print mini,maxi,"->",slope,intercept
296 sl=math.ceil(1e6/slope)
301 if val==int(val):ok=0
303 print sl/1e6, 1/(sl/1e6)
306 interc=-math.ceil(intercept*1e6)/1e6
307 print invSlope,slope,interc
308 imageSC=vtkImageShiftScale()
309 imageSC.SetOutputScalarTypeToUnsignedShort()
310 imageSC.SetShift(-interc)
311 imageSC.SetScale(invSlope)
312 imageSC.SetInput(data)
315 // GDCM_NAME_SPACE::Debug::DebugOn();
317 std::ostringstream str;
318 GDCM_NAME_SPACE::File *file;
319 file = GDCM_NAME_SPACE::File::New();
321 // Set the image size
324 file->InsertEntryString(str.str(),0x0028,0x0011,"US"); // Columns
327 file->InsertEntryString(str.str(),0x0028,0x0010,"US"); // Rows
328 // Set the pixel type
330 file->InsertEntryString("16",0x0028,0x0100,"US"); // Bits Allocated
332 str << 16; // may be 12 or 16 if componentSize =16
333 file->InsertEntryString("16",0x0028,0x0101,"US"); // Bits Stored
335 file->InsertEntryString("15",0x0028,0x0102,"US"); // High Bit
336 // Set the pixel representation // 0/1
338 file->InsertEntryString("0",0x0028,0x0103, "US"); // Pixel Representation
339 // Set the samples per pixel // 1:Grey level, 3:RGB
340 file->InsertEntryString("1",0x0028,0x0002, "US"); // Samples per Pixel
343 // Set Rescale Intercept
346 file->InsertEntryString(str.str(),0x0028,0x1052,"DS");
351 file->InsertEntryString(str.str(),0x0028,0x1053,"DS");
356 GDCM_NAME_SPACE::FileHelper *fileH;
357 fileH = GDCM_NAME_SPACE::FileHelper::New(file);
358 // cast is just to avoid warnings (*no* conversion)
359 fileH->SetImageData((uint8_t *)img,nx*ny*sizeof(uint16_t));
360 fileH->SetWriteModeToRaw();
361 fileH->SetWriteTypeToDcmExplVR();
363 fileH->Write(imageName);
365 if( !fileH->Write(imageName))
366 std::cout << "Failed for [" << imageName << "]\n"
367 << " File is unwrittable" << std::endl;