4a49465065257ba2f02dd5c4df6c20e2b1cd4ebc
[ctsim.git] / libctsim / imagefile.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **      Name:           imagefile.cpp
5 **  Purpose:      Imagefile classes
6 **      Programmer:   Kevin Rosenberg
7 **      Date Started: June 2000
8 **
9 **  This is part of the CTSim program
10 **  Copyright (c) 1983-2001 Kevin Rosenberg
11 **
12 **  $Id: imagefile.cpp,v 1.46 2002/06/27 03:19:23 kevin Exp $
13 **
14 **  This program is free software; you can redistribute it and/or modify
15 **  it under the terms of the GNU General Public License (version 2) as
16 **  published by the Free Software Foundation.
17 **
18 **  This program is distributed in the hope that it will be useful,
19 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 **  GNU General Public License for more details.
22 **
23 **  You should have received a copy of the GNU General Public License
24 **  along with this program; if not, write to the Free Software
25 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 ******************************************************************************/
27
28 #include "ct.h"
29 #ifdef HAVE_CTN_DICOM
30 #include "ctndicom.h"
31 #endif
32
33 const double ImageFile::s_dRedGrayscaleFactor = 0.299;
34 const double ImageFile::s_dGreenGrayscaleFactor = 0.587;
35 const double ImageFile::s_dBlueGrayscaleFactor = 0.114;
36
37
38 const int ImageFile::EXPORT_FORMAT_INVALID = -1;
39 const int ImageFile::EXPORT_FORMAT_TEXT = 0;
40 const int ImageFile::EXPORT_FORMAT_PGM = 1;
41 const int ImageFile::EXPORT_FORMAT_PGMASCII = 2;
42 #ifdef HAVE_PNG
43 const int ImageFile::EXPORT_FORMAT_PNG = 3;
44 const int ImageFile::EXPORT_FORMAT_PNG16 = 4;
45 #endif
46 #ifdef HAVE_CTN_DICOM
47 const int ImageFile::EXPORT_FORMAT_DICOM = 5;
48 #endif
49 const int ImageFile::EXPORT_FORMAT_RAW = 6;
50
51 const char* ImageFile::s_aszExportFormatName[] = 
52 {
53   {"text"},
54   {"pgm"},
55   {"pgmascii"},
56 #ifdef HAVE_PNG
57   {"png"},
58   {"png16"},
59 #endif
60 #ifdef HAVE_CTN_DICOM
61   {"dicom"},
62 #endif
63 };
64
65 const char* ImageFile::s_aszExportFormatTitle[] = 
66 {
67   {"Text"},
68   {"PGM"},
69   {"PGM ASCII"},
70   {"PNG"},
71   {"PNG 16-bit"},
72 #ifdef HAVE_CTN_DICOM
73   {"Dicom"},
74 #endif
75 };
76 const int ImageFile::s_iExportFormatCount = sizeof(s_aszExportFormatName) / sizeof(const char*);
77
78
79 const int ImageFile::IMPORT_FORMAT_INVALID = -1;
80 const int ImageFile::IMPORT_FORMAT_PPM = 0;
81 #ifdef HAVE_PNG
82 const int ImageFile::IMPORT_FORMAT_PNG = 1;
83 #endif
84 #ifdef HAVE_CTN_DICOM
85 const int ImageFile::IMPORT_FORMAT_DICOM = 2;
86 #endif
87
88
89 const char* ImageFile::s_aszImportFormatName[] = 
90 {
91   {"ppm"},
92 #ifdef HAVE_PNG
93   {"png"},
94 #endif
95 #ifdef HAVE_CTN_DICOM
96   {"dicom"},
97 #endif
98 };
99
100 const char* ImageFile::s_aszImportFormatTitle[] = 
101 {
102   {"PPM"},
103   {"PNG"},
104 #ifdef HAVE_CTN_DICOM
105   {"Dicom"},
106 #endif
107 };
108 const int ImageFile::s_iImportFormatCount = sizeof(s_aszImportFormatName) / sizeof(const char*);
109
110
111
112 F32Image::F32Image (int nx, int ny, int dataType)
113 : Array2dFile (nx, ny, sizeof(kfloat32), Array2dFile::PIXEL_FLOAT32, dataType)
114 {
115 }
116
117 F32Image::F32Image (void)
118 : Array2dFile()
119 {
120   setPixelFormat (Array2dFile::PIXEL_FLOAT32);
121   setPixelSize (sizeof(kfloat32));
122   setDataType (Array2dFile::DATA_TYPE_REAL);
123 }
124
125 F64Image::F64Image (int nx, int ny, int dataType)
126 : Array2dFile (nx, ny, sizeof(kfloat64), Array2dFile::PIXEL_FLOAT64, dataType)
127 {
128 }
129
130 F64Image::F64Image (void)
131 : Array2dFile ()
132 {
133   setPixelFormat (PIXEL_FLOAT64);
134   setPixelSize (sizeof(kfloat64));
135   setDataType (Array2dFile::DATA_TYPE_REAL);
136 }
137
138 void 
139 ImageFile::getCenterCoordinates (unsigned int& iXCenter, unsigned int& iYCenter)
140 {
141   if (isEven (m_nx))
142     iXCenter = m_nx / 2;
143   else
144     iXCenter = (m_nx - 1) / 2;
145   
146   if (isEven (m_ny))
147     iYCenter = m_ny / 2;
148   else
149     iYCenter = (m_ny - 1) / 2;
150 }
151
152
153 void 
154 ImageFile::filterResponse (const char* const domainName, double bw, const char* const filterName, 
155                            double filt_param, double dInputScale, double dOutputScale)
156 {
157   ImageFileArray v = getArray();
158   SignalFilter filter (filterName, domainName, bw, filt_param);
159   
160   unsigned int iXCenter, iYCenter;
161   getCenterCoordinates (iXCenter, iYCenter);
162   
163   for (unsigned int ix = 0; ix < m_nx; ix++)
164     for (unsigned int iy = 0; iy < m_ny; iy++) {
165       long lD2 = ((ix - iXCenter) * (ix - iXCenter)) + ((iy - iYCenter) * (iy - iYCenter));
166       double r = ::sqrt (static_cast<double>(lD2)) * dInputScale;
167       v[ix][iy] = filter.response (r) * dOutputScale;
168     }
169 }
170
171
172 // ImageFile::comparativeStatistics    Calculate comparative stats
173 //
174 // OUTPUT
175 //   d   Normalized root mean squared distance measure
176 //   r   Normalized mean absolute distance measure
177 //   e   Worst case distance measure
178 //
179 // REFERENCES
180 //  G.T. Herman, Image Reconstruction From Projections, 1980
181
182 bool
183 ImageFile::comparativeStatistics (const ImageFile& imComp, double& d, double& r, double& e) const
184 {
185   if (imComp.nx() != m_nx && imComp.ny() != m_ny) {
186     sys_error (ERR_WARNING, "Image sizes differ [ImageFile::comparativeStatistics]");
187     return false;
188   }
189   ImageFileArrayConst v = getArray();
190   if (v == NULL || m_nx == 0 || m_ny == 0)
191     return false;
192   
193   ImageFileArrayConst vComp = imComp.getArray();
194   
195   double myMean = 0.;
196   for (unsigned int ix = 0; ix < m_nx; ix++) {
197     for (unsigned int iy = 0; iy < m_ny; iy++) {
198       myMean += v[ix][iy];
199     }
200   }
201   myMean /= (m_nx * m_ny);
202   
203   double sqErrorSum = 0.;
204   double absErrorSum = 0.;
205   double sqDiffFromMeanSum = 0.;
206   double absValueSum = 0.;
207   for (unsigned int ix2 = 0; ix2 < m_nx; ix2++) {
208     for (unsigned int iy = 0; iy < m_ny; iy++) {
209       double diff = v[ix2][iy] - vComp[ix2][iy];
210       sqErrorSum += diff * diff;
211       absErrorSum += fabs(diff);
212       double diffFromMean = v[ix2][iy] - myMean;
213       sqDiffFromMeanSum += diffFromMean * diffFromMean;
214       absValueSum += fabs(v[ix2][iy]);
215     }
216   }
217   
218   d = ::sqrt (sqErrorSum / sqDiffFromMeanSum);
219   r = absErrorSum / absValueSum;
220   
221   int hx = m_nx / 2;
222   int hy = m_ny / 2;
223   double eMax = -1;
224   for (int ix3 = 0; ix3 < hx; ix3++) {
225     for (int iy = 0; iy < hy; iy++) {
226       double avgPixel = 0.25 * (v[2*ix3][2*iy] + v[2*ix3+1][2*iy] + v[2*ix3][2*iy+1] + v[2*ix3+1][2*iy+1]);
227       double avgPixelComp = 0.25 * (vComp[2*ix3][2*iy] + vComp[2*ix3+1][2*iy] + vComp[2*ix3][2*iy+1] + vComp[2*ix3+1][2*iy+1]);
228       double error = fabs (avgPixel - avgPixelComp);
229       if (error > eMax)
230         eMax = error;
231     }
232   }
233   
234   e = eMax;
235   
236   return true;
237 }
238
239
240 bool
241 ImageFile::printComparativeStatistics (const ImageFile& imComp, std::ostream& os) const
242 {
243   double d, r, e;
244   
245   if (comparativeStatistics (imComp, d, r, e)) {
246     os << "  Normalized root mean squared distance (d): " << d << std::endl;
247     os << "      Normalized mean absolute distance (r): " << r << std::endl;
248     os << "Worst case distance (2x2 pixel average) (e): " << e << std::endl;
249     return true;
250   }
251   return false;
252 }
253
254
255 void
256 ImageFile::printStatistics (std::ostream& os) const
257 {
258   double min, max, mean, mode, median, stddev;
259   
260   statistics (min, max, mean, mode, median, stddev);
261   if (isComplex())
262     os << "Real Component Statistics" << std::endl;
263   
264   os << "   min: " << min << std::endl;
265   os << "   max: " << max << std::endl;
266   os << "  mean: " << mean << std::endl;
267   os << "  mode: " << mode << std::endl;
268   os << "median: " << median << std::endl;
269   os << "stddev: " << stddev << std::endl;
270   
271   if (isComplex()) {
272     statistics (getImaginaryArray(), min, max, mean, mode, median, stddev);
273     os << std::endl << "Imaginary Component Statistics" << std::endl;
274     os << "   min: " << min << std::endl;
275     os << "   max: " << max << std::endl;
276     os << "  mean: " << mean << std::endl;
277     os << "  mode: " << mode << std::endl;
278     os << "median: " << median << std::endl;
279     os << "stddev: " << stddev << std::endl;
280   }
281 }
282
283
284 void
285 ImageFile::statistics (double& min, double& max, double& mean, double& mode, double& median, double& stddev) const
286 {
287   ImageFileArrayConst v = getArray();
288   statistics (v, min, max, mean, mode, median, stddev);
289 }
290
291
292 void
293 ImageFile::statistics (ImageFileArrayConst v, double& min, double& max, double& mean, double& mode, double& median, double& stddev) const
294 {
295   int nx = m_nx;
296   int ny = m_ny;
297   
298   if (v == NULL || nx == 0 || ny == 0)
299     return;
300   
301   std::vector<double> vecImage;
302   int iVec = 0;
303   vecImage.resize (nx * ny);
304   for (int ix = 0; ix < nx; ix++) {
305     for (int iy = 0; iy < ny; iy++)
306       vecImage[iVec++] = v[ix][iy];
307   }
308   
309   vectorNumericStatistics (vecImage, nx * ny, min, max, mean, mode, median, stddev);
310 }
311
312 void
313 ImageFile::getMinMax (double& min, double& max) const
314 {
315   int nx = m_nx;
316   int ny = m_ny;
317   ImageFileArrayConst v = getArray();
318   
319   if (v == NULL || nx == 0 || ny == 0)
320     return;
321   
322   min = v[0][0];
323   max = v[0][0];
324   for (int ix = 0; ix < nx; ix++) {
325     for (int iy = 0; iy < ny; iy++) {
326       if (v[ix][iy] > max)
327         max = v[ix][iy];
328       if (v[ix][iy] < min)
329         min = v[ix][iy];
330     }
331   }
332 }
333
334 bool
335 ImageFile::convertRealToComplex ()
336 {
337   if (dataType() != Array2dFile::DATA_TYPE_REAL)
338     return false;
339   
340   if (! reallocRealToComplex())
341     return false;
342   
343   ImageFileArray vImag = getImaginaryArray();
344   for (unsigned int ix = 0; ix < m_nx; ix++) {
345     ImageFileColumn vCol = vImag[ix];
346     for (unsigned int iy = 0; iy < m_ny; iy++)
347       *vCol++ = 0;
348   }
349   
350   return true;
351 }
352
353 bool
354 ImageFile::convertComplexToReal ()
355 {
356   if (dataType() != Array2dFile::DATA_TYPE_COMPLEX)
357     return false;
358   
359   ImageFileArray vReal = getArray();
360   ImageFileArray vImag = getImaginaryArray();
361   for (unsigned int ix = 0; ix < m_nx; ix++) {
362     ImageFileColumn vRealCol = vReal[ix];
363     ImageFileColumn vImagCol = vImag[ix];
364     for (unsigned int iy = 0; iy < m_ny; iy++) {
365       CTSimComplex c (*vRealCol, *vImagCol);
366       *vRealCol++ = std::abs (c);
367       vImagCol++;
368     }
369   }
370   
371   return reallocComplexToReal();
372 }
373
374 bool
375 ImageFile::subtractImages (const ImageFile& rRHS, ImageFile& result) const
376 {
377   if (m_nx != rRHS.nx() || m_ny != rRHS.ny() || m_nx != result.nx() || m_ny != result.ny()) {
378     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::subtractImage]");
379     return false;
380   }
381   
382   if (isComplex() || rRHS.isComplex() && ! result.isComplex())
383     result.convertRealToComplex();
384   
385   ImageFileArrayConst vLHS = getArray();
386   ImageFileArrayConst vLHSImag = getImaginaryArray();
387   ImageFileArrayConst vRHS = rRHS.getArray();
388   ImageFileArrayConst vRHSImag = rRHS.getImaginaryArray();
389   ImageFileArray vResult = result.getArray();
390   ImageFileArray vResultImag = result.getImaginaryArray();
391   
392   for (unsigned int ix = 0; ix < m_nx; ix++) {
393     for (unsigned int iy = 0; iy < m_ny; iy++) {
394       vResult[ix][iy] = vLHS[ix][iy] - vRHS[ix][iy];
395       if (result.isComplex()) {
396         vResultImag[ix][iy] = 0;
397         if (isComplex())
398           vResultImag[ix][iy] += vLHSImag[ix][iy];
399         if (rRHS.isComplex())
400           vResultImag[ix][iy] -= vRHSImag[ix][iy];
401       }
402     }
403   }
404   
405   return true;
406 }
407
408 bool
409 ImageFile::addImages (const ImageFile& rRHS, ImageFile& result) const
410 {
411   if (m_nx != rRHS.nx() || m_ny != rRHS.ny() || m_nx != result.nx() || m_ny != result.ny()) {
412     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::subtractImage]");
413     return false;
414   }
415   
416   if (isComplex() || rRHS.isComplex() && ! result.isComplex())
417     result.convertRealToComplex();
418   
419   ImageFileArrayConst vLHS = getArray();
420   ImageFileArrayConst vLHSImag = getImaginaryArray();
421   ImageFileArrayConst vRHS = rRHS.getArray();
422   ImageFileArrayConst vRHSImag = rRHS.getImaginaryArray();
423   ImageFileArray vResult = result.getArray();
424   ImageFileArray vResultImag = result.getImaginaryArray();
425   
426   for (unsigned int ix = 0; ix < m_nx; ix++) {
427     for (unsigned int iy = 0; iy < m_ny; iy++) {
428       vResult[ix][iy] = vLHS[ix][iy] + vRHS[ix][iy];
429       if (result.isComplex()) {
430         vResultImag[ix][iy] = 0;
431         if (isComplex())
432           vResultImag[ix][iy] += vLHSImag[ix][iy];
433         if (rRHS.isComplex())
434           vResultImag[ix][iy] += vRHSImag[ix][iy];
435       }
436     }
437   }
438   
439   return true;
440 }
441
442 bool
443 ImageFile::multiplyImages (const ImageFile& rRHS, ImageFile& result) const
444 {
445   if (m_nx != rRHS.nx() || m_ny != rRHS.ny() || m_nx != result.nx() || m_ny != result.ny()) {
446     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::subtractImage]");
447     return false;
448   }
449   
450   if (isComplex() || rRHS.isComplex() && ! result.isComplex())
451     result.convertRealToComplex();
452   
453   ImageFileArrayConst vLHS = getArray();
454   ImageFileArrayConst vLHSImag = getImaginaryArray();
455   ImageFileArrayConst vRHS = rRHS.getArray();
456   ImageFileArrayConst vRHSImag = rRHS.getImaginaryArray();
457   ImageFileArray vResult = result.getArray();
458   ImageFileArray vResultImag = result.getImaginaryArray();
459   
460   for (unsigned int ix = 0; ix < m_nx; ix++) {
461     for (unsigned int iy = 0; iy < m_ny; iy++) {
462       if (result.isComplex()) {
463         double dImag = 0;
464         if (isComplex())
465           dImag = vLHSImag[ix][iy];
466         std::complex<double> cLHS (vLHS[ix][iy], dImag);
467         dImag = 0;
468         if (rRHS.isComplex())
469           dImag = vRHSImag[ix][iy];
470         std::complex<double> cRHS (vRHS[ix][iy], dImag);
471         std::complex<double> cResult = cLHS * cRHS;
472         vResult[ix][iy] = cResult.real();
473         vResultImag[ix][iy] = cResult.imag();
474       } else
475         vResult[ix][iy] = vLHS[ix][iy] * vRHS[ix][iy];
476     }
477   }
478   
479   
480   return true;
481 }
482
483 bool
484 ImageFile::divideImages (const ImageFile& rRHS, ImageFile& result) const
485 {
486   if (m_nx != rRHS.nx() || m_ny != rRHS.ny() || m_nx != result.nx() || m_ny != result.ny()) {
487     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::subtractImage]");
488     return false;
489   }
490   
491   if (isComplex() || rRHS.isComplex() && ! result.isComplex())
492     result.convertRealToComplex();
493   
494   ImageFileArrayConst vLHS = getArray();
495   ImageFileArrayConst vLHSImag = getImaginaryArray();
496   ImageFileArrayConst vRHS = rRHS.getArray();
497   ImageFileArrayConst vRHSImag = rRHS.getImaginaryArray();
498   ImageFileArray vResult = result.getArray();
499   ImageFileArray vResultImag = result.getImaginaryArray();
500   
501   for (unsigned int ix = 0; ix < m_nx; ix++) {
502     for (unsigned int iy = 0; iy < m_ny; iy++) {
503       if (result.isComplex()) {
504         double dImag = 0;
505         if (isComplex())
506           dImag = vLHSImag[ix][iy];
507         std::complex<double> cLHS (vLHS[ix][iy], dImag);
508         dImag = 0;
509         if (rRHS.isComplex())
510           dImag = vRHSImag[ix][iy];
511         std::complex<double> cRHS (vRHS[ix][iy], dImag);
512         std::complex<double> cResult = cLHS / cRHS;
513         vResult[ix][iy] = cResult.real();
514         vResultImag[ix][iy] = cResult.imag();
515       } else {
516         if (vRHS != 0)
517           vResult[ix][iy] = vLHS[ix][iy] / vRHS[ix][iy];
518         else
519           vResult[ix][iy] = 0;
520       }
521     }
522   }
523   
524   return true;
525 }
526
527
528 bool
529 ImageFile::invertPixelValues (ImageFile& result) const
530 {
531   if (m_nx != result.nx() || m_ny != result.ny()) {
532     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
533     return false;
534   }
535   
536   if (isComplex() && ! result.isComplex())
537     result.convertRealToComplex();
538   
539   ImageFileArrayConst vLHS = getArray();
540   ImageFileArray vResult = result.getArray();
541   
542   for (unsigned int ix = 0; ix < m_nx; ix++) {
543     ImageFileColumnConst in = vLHS[ix];
544     ImageFileColumn out = vResult[ix];
545     for (unsigned int iy = 0; iy < m_ny; iy++)
546       *out++ = - *in++;
547   }
548   
549   return true;
550 }
551
552 bool
553 ImageFile::sqrt (ImageFile& result) const
554 {
555   if (m_nx != result.nx() || m_ny != result.ny()) {
556     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
557     return false;
558   }
559   
560   if (isComplex() && ! result.isComplex())
561     result.convertRealToComplex();
562   
563   bool bComplexOutput = result.isComplex();
564   ImageFileArrayConst vLHS = getArray();
565   if (! bComplexOutput)   // check if should convert to complex output
566     for (unsigned int ix = 0; ix < m_nx; ix++)
567       for (unsigned int iy = 0; iy < m_ny; iy++)
568         if (! bComplexOutput && vLHS[ix][iy] < 0) {
569           result.convertRealToComplex();
570           bComplexOutput = true;
571           break;
572         }
573         
574         ImageFileArrayConst vLHSImag = getImaginaryArray();
575         ImageFileArray vResult = result.getArray();
576         ImageFileArray vResultImag = result.getImaginaryArray();
577         
578         for (unsigned int ix = 0; ix < m_nx; ix++) {
579           for (unsigned int iy = 0; iy < m_ny; iy++) {
580             if (result.isComplex()) {
581               double dImag = 0;
582               if (isComplex())
583                 dImag = vLHSImag[ix][iy];
584               std::complex<double> cLHS (vLHS[ix][iy], dImag);
585               std::complex<double> cResult = std::sqrt(cLHS);
586               vResult[ix][iy] = cResult.real();
587               vResultImag[ix][iy] = cResult.imag();
588             } else
589               vResult[ix][iy] = ::sqrt (vLHS[ix][iy]);
590           }
591         }
592         
593         
594         return true;
595 }
596
597 bool
598 ImageFile::log (ImageFile& result) const
599 {
600   if (m_nx != result.nx() || m_ny != result.ny()) {
601     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::log]");
602     return false;
603   }
604   
605   if (isComplex() && ! result.isComplex())
606     result.convertRealToComplex();
607   
608   ImageFileArrayConst vLHS = getArray();
609   ImageFileArrayConst vLHSImag = getImaginaryArray();
610   ImageFileArray vResult = result.getArray();
611   ImageFileArray vResultImag = result.getImaginaryArray();
612   
613   for (unsigned int ix = 0; ix < m_nx; ix++) {
614     for (unsigned int iy = 0; iy < m_ny; iy++) {
615       if (result.isComplex()) {
616         double dImag = 0;
617         if (isComplex())
618           dImag = vLHSImag[ix][iy];
619         std::complex<double> cLHS (vLHS[ix][iy], dImag);
620         std::complex<double> cResult = std::log (cLHS);
621         vResult[ix][iy] = cResult.real();
622         vResultImag[ix][iy] = cResult.imag();
623       } else {
624         if (vLHS[ix][iy] > 0)
625           vResult[ix][iy] = ::log (vLHS[ix][iy]);
626         else
627           vResult[ix][iy] = 0;
628       }
629     }
630   }
631   
632   
633   return true;
634 }
635
636 bool
637 ImageFile::exp (ImageFile& result) const
638 {
639   if (m_nx != result.nx() || m_ny != result.ny()) {
640     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
641     return false;
642   }
643   
644   if (isComplex() && ! result.isComplex())
645     result.convertRealToComplex();
646   
647   ImageFileArrayConst vLHS = getArray();
648   ImageFileArrayConst vLHSImag = getImaginaryArray();
649   ImageFileArray vResult = result.getArray();
650   ImageFileArray vResultImag = result.getImaginaryArray();
651   
652   for (unsigned int ix = 0; ix < m_nx; ix++) {
653     for (unsigned int iy = 0; iy < m_ny; iy++) {
654       if (result.isComplex()) {
655         double dImag = 0;
656         if (isComplex())
657           dImag = vLHSImag[ix][iy];
658         std::complex<double> cLHS (vLHS[ix][iy], dImag);
659         std::complex<double> cResult = std::exp (cLHS);
660         vResult[ix][iy] = cResult.real();
661         vResultImag[ix][iy] = cResult.imag();
662       } else
663         vResult[ix][iy] = ::exp (vLHS[ix][iy]);
664     }
665   }
666   
667   
668   return true;
669 }
670
671 bool
672 ImageFile::scaleImage (ImageFile& result) const
673 {
674   unsigned int nx = m_nx;
675   unsigned int ny = m_ny;
676   unsigned int newNX = result.nx();
677   unsigned int newNY = result.ny();
678   
679   double dXScale = static_cast<double>(newNX) / static_cast<double>(nx);
680   double dYScale = static_cast<double>(newNY) / static_cast<double>(ny);
681   
682   if (isComplex() && ! result.isComplex())
683     result.convertRealToComplex();
684   
685   ImageFileArrayConst vReal = getArray();
686   ImageFileArrayConst vImag = getImaginaryArray();
687   ImageFileArray vResult = result.getArray();
688   ImageFileArray vResultImag = result.getImaginaryArray();
689   
690   BilinearInterpolator<ImageFileValue> realInterp (vReal, nx, ny);
691   BilinearInterpolator<ImageFileValue> imagInterp (vImag, nx, ny);
692
693   for (unsigned int ix = 0; ix < newNX; ix++) {
694     for (unsigned int iy = 0; iy < newNY; iy++) {
695       double dXPos = ix / dXScale;
696       double dYPos = iy / dYScale;
697       vResult[ix][iy] = realInterp.interpolate (dXPos, dYPos);
698       if (result.isComplex())
699         if (isComplex())
700           vResultImag[ix][iy] = imagInterp.interpolate (dXPos, dYPos);
701         else
702           vResultImag[ix][iy] = 0;
703     }
704   }
705
706   return true;
707 }
708
709 #ifdef HAVE_FFTW
710 bool
711 ImageFile::fft (ImageFile& result) const
712 {
713   if (m_nx != result.nx() || m_ny != result.ny()) {
714     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
715     return false;
716   }
717   
718   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
719     if (! result.convertRealToComplex ())
720       return false;
721   }
722   
723   fftw_complex* in = new fftw_complex [m_nx * m_ny];
724   
725   ImageFileArrayConst vReal = getArray();
726   ImageFileArrayConst vImag = getImaginaryArray();
727   
728   unsigned int ix, iy;
729   unsigned int iArray = 0;
730   for (ix = 0; ix < m_nx; ix++) {
731     for (iy = 0; iy < m_ny; iy++) {
732       in[iArray].re = vReal[ix][iy];
733       if (isComplex())
734         in[iArray].im = vImag[ix][iy];
735       else
736         in[iArray].im = 0;
737       iArray++;
738     }
739   }
740   
741   fftwnd_plan plan = fftw2d_create_plan (m_nx, m_ny, FFTW_FORWARD, FFTW_IN_PLACE | FFTW_ESTIMATE | FFTW_USE_WISDOM);  
742   fftwnd_one (plan, in, NULL);
743   
744   ImageFileArray vRealResult = result.getArray();
745   ImageFileArray vImagResult = result.getImaginaryArray();
746   iArray = 0;
747   unsigned int iScale = m_nx * m_ny;
748   for (ix = 0; ix < m_nx; ix++) {
749     for (iy = 0; iy < m_ny; iy++) {
750       vRealResult[ix][iy] = in[iArray].re / iScale;
751       vImagResult[ix][iy] = in[iArray].im / iScale;
752       iArray++;
753     }
754   }
755   delete in;
756   fftwnd_destroy_plan (plan);
757   
758   Fourier::shuffleFourierToNaturalOrder (result);
759   
760   return true;
761 }
762
763
764 bool
765 ImageFile::ifft (ImageFile& result) const
766 {
767   if (m_nx != result.nx() || m_ny != result.ny()) {
768     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
769     return false;
770   }
771   
772   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
773     if (! result.convertRealToComplex ())
774       return false;
775   }
776   
777   ImageFileArrayConst vReal = getArray();
778   ImageFileArrayConst vImag = getImaginaryArray();
779   ImageFileArray vRealResult = result.getArray();
780   ImageFileArray vImagResult = result.getImaginaryArray();
781   unsigned int ix, iy;
782   for (ix = 0; ix < m_nx; ix++) {
783     for (iy = 0; iy < m_ny; iy++) {
784       vRealResult[ix][iy] = vReal[ix][iy];
785       if (isComplex()) 
786         vImagResult[ix][iy] = vImag[ix][iy];
787       else
788         vImagResult[ix][iy] = 0;
789     }
790   }
791   
792   Fourier::shuffleNaturalToFourierOrder (result);
793   
794   fftw_complex* in = new fftw_complex [m_nx * m_ny];
795   
796   unsigned int iArray = 0;
797   for (ix = 0; ix < m_nx; ix++) {
798     for (iy = 0; iy < m_ny; iy++) {
799       in[iArray].re = vRealResult[ix][iy];
800       in[iArray].im = vImagResult[ix][iy];
801       iArray++;
802     }
803   }
804   
805   fftwnd_plan plan = fftw2d_create_plan (m_nx, m_ny, FFTW_BACKWARD, FFTW_IN_PLACE | FFTW_ESTIMATE | FFTW_USE_WISDOM);
806   
807   fftwnd_one (plan, in, NULL);
808   
809   iArray = 0;
810   for (ix = 0; ix < m_nx; ix++) {
811     for (iy = 0; iy < m_ny; iy++) {
812       vRealResult[ix][iy] = in[iArray].re;
813       vImagResult[ix][iy] = in[iArray].im;
814       iArray++;
815     }
816   }
817   fftwnd_destroy_plan (plan);
818   
819   delete in;
820   
821   return true;
822 }
823
824 bool
825 ImageFile::fftRows (ImageFile& result) const
826 {
827   if (m_nx != result.nx() || m_ny != result.ny()) {
828     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::fftRows]");
829     return false;
830   }
831   
832   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
833     if (! result.convertRealToComplex ())
834       return false;
835   }
836    
837   ImageFileArrayConst vReal = getArray();
838   ImageFileArrayConst vImag = getImaginaryArray();
839   
840   fftw_plan plan = fftw_create_plan (m_nx, FFTW_FORWARD, FFTW_IN_PLACE | FFTW_ESTIMATE | FFTW_USE_WISDOM);
841
842   fftw_complex* in = new fftw_complex [m_nx];
843   std::complex<double>* pcRow = new std::complex<double> [m_nx];  
844   for (unsigned int iy = 0; iy < m_ny; iy++) {
845     unsigned int ix;
846     for (ix = 0; ix < m_nx; ix++) {
847       in[ix].re = vReal[ix][iy];
848       if (isComplex())
849         in[ix].im = vImag[ix][iy];
850       else
851         in[ix].im = 0;
852     }
853     
854     fftw_one (plan, in, NULL);
855     
856     for (ix = 0; ix < m_nx; ix++)
857       pcRow[ix] = std::complex<double>(in[ix].re, in[ix].im);
858     
859     Fourier::shuffleFourierToNaturalOrder (pcRow, m_nx);
860     for (ix = 0; ix < m_nx; ix++) {
861       vReal[ix][iy] = pcRow[ix].real() / m_nx;
862       vImag[ix][iy] = pcRow[ix].imag() / m_nx;
863     }
864   }
865   delete [] pcRow;
866   
867   fftw_destroy_plan (plan);
868   delete in;
869   
870   return true;
871 }     
872
873 bool
874 ImageFile::ifftRows (ImageFile& result) const
875 {
876   if (m_nx != result.nx() || m_ny != result.ny()) {
877     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::fftRows]");
878     return false;
879   }
880   
881   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
882     if (! result.convertRealToComplex ())
883       return false;
884   }
885   
886   fftw_complex* in = new fftw_complex [m_nx];
887   
888   ImageFileArrayConst vReal = getArray();
889   ImageFileArrayConst vImag = getImaginaryArray();
890   
891   fftw_plan plan = fftw_create_plan (m_nx, FFTW_BACKWARD, FFTW_IN_PLACE | FFTW_ESTIMATE | FFTW_USE_WISDOM);
892   std::complex<double>* pcRow = new std::complex<double> [m_nx];
893   
894   unsigned int ix, iy;
895   // unsigned int iArray = 0;
896   for (iy = 0; iy < m_ny; iy++) {
897     for (ix = 0; ix < m_nx; ix++) {
898       double dImag = 0;
899       if (isComplex())
900         dImag = vImag[ix][iy];
901       pcRow[ix] = std::complex<double> (vReal[ix][iy], dImag);
902     }
903     
904     Fourier::shuffleNaturalToFourierOrder (pcRow, m_nx);
905     
906     for (ix = 0; ix < m_nx; ix++) {
907       in[ix].re = pcRow[ix].real();
908       in[ix].im = pcRow[ix].imag();
909     }
910     
911     fftw_one (plan, in, NULL);
912     
913     for (ix = 0; ix < m_nx; ix++) {
914       vReal[ix][iy] = in[ix].re;
915       vImag[ix][iy] = in[ix].im;
916     }
917   }
918   delete [] pcRow;
919   
920   fftw_destroy_plan (plan);
921   delete in;
922   
923   return true;
924 }
925
926 bool
927 ImageFile::fftCols (ImageFile& result) const
928 {
929   if (m_nx != result.nx() || m_ny != result.ny()) {
930     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::fftRows]");
931     return false;
932   }
933   
934   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
935     if (! result.convertRealToComplex ())
936       return false;
937   }
938     
939   ImageFileArrayConst vReal = getArray();
940   ImageFileArrayConst vImag = getImaginaryArray();
941   
942   fftw_plan plan = fftw_create_plan (m_ny, FFTW_FORWARD, FFTW_IN_PLACE | FFTW_ESTIMATE | FFTW_USE_WISDOM);
943
944   std::complex<double>* pcCol = new std::complex<double> [m_ny];  
945   fftw_complex* in = new fftw_complex [m_ny];
946   for (unsigned int ix = 0; ix < m_nx; ix++) {
947     unsigned int iy;
948     for (iy = 0; iy < m_ny; iy++) {
949       in[iy].re = vReal[ix][iy];
950       if (isComplex())
951         in[iy].im = vImag[ix][iy];
952       else
953         in[iy].im = 0;
954     }
955     
956     fftw_one (plan, in, NULL);
957     
958     for (iy = 0; iy < m_ny; iy++)
959       pcCol[iy] = std::complex<double>(in[iy].re, in[iy].im);
960     
961     Fourier::shuffleFourierToNaturalOrder (pcCol, m_ny);
962     for (iy = 0; iy < m_ny; iy++) {
963       vReal[ix][iy] = pcCol[iy].real() / m_ny;
964       vImag[ix][iy] = pcCol[iy].imag() / m_ny;
965     }
966   }
967   delete [] pcCol;
968   
969   fftw_destroy_plan (plan);
970   delete in;
971   
972   return true;
973 }
974
975 bool
976 ImageFile::ifftCols (ImageFile& result) const
977 {
978   if (m_nx != result.nx() || m_ny != result.ny()) {
979     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::fftRows]");
980     return false;
981   }
982   
983   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
984     if (! result.convertRealToComplex ())
985       return false;
986   }
987   
988   fftw_complex* in = new fftw_complex [m_ny];
989   
990   ImageFileArrayConst vReal = getArray();
991   ImageFileArrayConst vImag = getImaginaryArray();
992   
993   fftw_plan plan = fftw_create_plan (m_ny, FFTW_BACKWARD, FFTW_IN_PLACE | FFTW_ESTIMATE | FFTW_USE_WISDOM);
994   std::complex<double>* pcCol = new std::complex<double> [m_ny];
995   
996   unsigned int ix, iy;
997   // unsigned int iArray = 0;
998   for (ix = 0; ix < m_nx; ix++) {
999     for (iy = 0; iy < m_ny; iy++) {
1000       double dImag = 0;
1001       if (isComplex())
1002         dImag = vImag[ix][iy];
1003       pcCol[iy] = std::complex<double> (vReal[ix][iy], dImag);
1004     }
1005     
1006     Fourier::shuffleNaturalToFourierOrder (pcCol, m_ny);
1007     
1008     for (iy = 0; iy < m_ny; iy++) {
1009       in[iy].re = pcCol[iy].real();
1010       in[iy].im = pcCol[iy].imag();
1011     }
1012     
1013     fftw_one (plan, in, NULL);
1014     
1015     for (iy = 0; iy < m_ny; iy++) {
1016       vReal[ix][iy] = in[iy].re;
1017       vImag[ix][iy] = in[iy].im;
1018     }
1019   }
1020   delete [] pcCol;
1021   
1022   fftw_destroy_plan (plan);
1023   delete in;
1024   
1025   return true;
1026 }
1027
1028 #endif // HAVE_FFTW
1029
1030
1031
1032 bool
1033 ImageFile::fourier (ImageFile& result) const
1034 {
1035   if (m_nx != result.nx() || m_ny != result.ny()) {
1036     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1037     return false;
1038   }
1039   
1040   if (! result.isComplex())
1041     if (! result.convertRealToComplex ())
1042       return false;
1043     
1044     ImageFileArrayConst vLHS = getArray();
1045     ImageFileArrayConst vLHSImag = getImaginaryArray();
1046     ImageFileArray vRealResult = result.getArray();
1047     ImageFileArray vImagResult = result.getImaginaryArray();
1048     
1049     unsigned int ix, iy;
1050     
1051     // alloc output matrix
1052     CTSimComplex** complexOut = new CTSimComplex* [m_nx];
1053     for (ix = 0; ix < m_nx; ix++)
1054       complexOut[ix] = new CTSimComplex [m_ny];
1055     
1056     // fourier each x column
1057     CTSimComplex* pY = new CTSimComplex [m_ny];
1058     for (ix = 0; ix < m_nx; ix++) {
1059       for (iy = 0; iy < m_ny; iy++) {
1060         double dImag = 0;
1061         if (isComplex())
1062           dImag = vLHSImag[ix][iy];
1063         pY[iy] = std::complex<double>(vLHS[ix][iy], dImag);
1064       } 
1065       ProcessSignal::finiteFourierTransform (pY, complexOut[ix], m_ny,  ProcessSignal::FORWARD);
1066     }
1067     delete [] pY;
1068     
1069     // fourier each y row
1070     CTSimComplex* pX = new CTSimComplex [m_nx];
1071     CTSimComplex* complexOutRow = new CTSimComplex [m_nx];
1072     for (iy = 0; iy < m_ny; iy++) {
1073       for (ix = 0; ix < m_nx; ix++)
1074         pX[ix] = complexOut[ix][iy];
1075       ProcessSignal::finiteFourierTransform (pX, complexOutRow, m_nx, ProcessSignal::FORWARD);
1076       for (ix = 0; ix < m_nx; ix++)
1077         complexOut[ix][iy] = complexOutRow[ix];
1078     }
1079     delete [] pX;
1080     delete [] complexOutRow;
1081     
1082     for (ix = 0; ix < m_nx; ix++)
1083       for (iy = 0; iy < m_ny; iy++) {
1084         vRealResult[ix][iy] = complexOut[ix][iy].real();
1085         vImagResult[ix][iy] = complexOut[ix][iy].imag();
1086       }
1087       
1088       Fourier::shuffleFourierToNaturalOrder (result);
1089       
1090       // delete complexOut matrix
1091       for (ix = 0; ix < m_nx; ix++)
1092         delete [] complexOut[ix];
1093       delete [] complexOut;
1094       
1095       return true;
1096 }
1097
1098 bool
1099 ImageFile::inverseFourier (ImageFile& result) const
1100 {
1101   if (m_nx != result.nx() || m_ny != result.ny()) {
1102     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1103     return false;
1104   }
1105   
1106   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
1107     if (! result.convertRealToComplex ())
1108       return false;
1109   }
1110   
1111   ImageFileArrayConst vLHSReal = getArray();
1112   ImageFileArrayConst vLHSImag = getImaginaryArray();
1113   ImageFileArray vRealResult = result.getArray();
1114   ImageFileArray vImagResult = result.getImaginaryArray();
1115   
1116   unsigned int ix, iy;
1117   // alloc 2d complex output matrix
1118   CTSimComplex** complexOut = new CTSimComplex* [m_nx];
1119   for (ix = 0; ix < m_nx; ix++)
1120     complexOut[ix] = new CTSimComplex [m_ny];
1121   
1122   // put input image into result
1123   for (ix = 0; ix < m_nx; ix++)
1124     for (iy = 0; iy < m_ny; iy++) {
1125       vRealResult[ix][iy] = vLHSReal[ix][iy];
1126       if (isComplex())
1127         vImagResult[ix][iy] = vLHSImag[ix][iy];
1128       else
1129         vImagResult[ix][iy] = 0;
1130     }
1131     
1132     Fourier::shuffleNaturalToFourierOrder (result);
1133     
1134     // ifourier each x column
1135     CTSimComplex* pCol = new CTSimComplex [m_ny];
1136     for (ix = 0; ix < m_nx; ix++) {
1137       for (iy = 0; iy < m_ny; iy++) {
1138         pCol[iy] = std::complex<double> (vRealResult[ix][iy], vImagResult[ix][iy]);
1139       }
1140       ProcessSignal::finiteFourierTransform (pCol, complexOut[ix], m_ny,  ProcessSignal::BACKWARD);
1141     }
1142     delete [] pCol;
1143     
1144     // ifourier each y row
1145     CTSimComplex* complexInRow = new CTSimComplex [m_nx];
1146     CTSimComplex* complexOutRow = new CTSimComplex [m_nx];
1147     for (iy = 0; iy < m_ny; iy++) {
1148       for (ix = 0; ix < m_nx; ix++)
1149         complexInRow[ix] = complexOut[ix][iy];
1150       ProcessSignal::finiteFourierTransform (complexInRow, complexOutRow, m_nx, ProcessSignal::BACKWARD);
1151       for (ix = 0; ix < m_nx; ix++)
1152         complexOut[ix][iy] = complexOutRow[ix];
1153     }
1154     delete [] complexInRow;
1155     delete [] complexOutRow;
1156     
1157     for (ix = 0; ix < m_nx; ix++)
1158       for (iy = 0; iy < m_ny; iy++) {
1159         vRealResult[ix][iy] = complexOut[ix][iy].real();
1160         vImagResult[ix][iy] = complexOut[ix][iy].imag();
1161       }
1162       
1163       // delete complexOut matrix
1164       for (ix = 0; ix < m_nx; ix++)
1165         delete [] complexOut[ix];
1166       delete [] complexOut;
1167       
1168       return true;
1169 }
1170
1171
1172 bool
1173 ImageFile::magnitude (ImageFile& result) const
1174 {
1175   if (m_nx != result.nx() || m_ny != result.ny()) {
1176     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1177     return false;
1178   }
1179   
1180   ImageFileArray vReal = getArray();
1181   ImageFileArray vImag = getImaginaryArray();
1182   ImageFileArray vRealResult = result.getArray();
1183   
1184   for (unsigned int ix = 0; ix < m_nx; ix++)
1185     for (unsigned int iy = 0; iy < m_ny; iy++) {
1186       if (isComplex()) 
1187         vRealResult[ix][iy] = ::sqrt (vReal[ix][iy] * vReal[ix][iy] + vImag[ix][iy] * vImag[ix][iy]);
1188       else
1189         vRealResult[ix][iy] = ::fabs(vReal[ix][iy]);
1190     }
1191     
1192     if (result.isComplex())
1193       result.reallocComplexToReal();
1194     
1195     return true;
1196 }
1197
1198 bool
1199 ImageFile::phase (ImageFile& result) const
1200 {
1201   if (m_nx != result.nx() || m_ny != result.ny()) {
1202     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1203     return false;
1204   }
1205   
1206   ImageFileArray vReal = getArray();
1207   ImageFileArray vImag = getImaginaryArray();
1208   ImageFileArray vRealResult = result.getArray();
1209   
1210   for (unsigned int ix = 0; ix < m_nx; ix++) {
1211     for (unsigned int iy = 0; iy < m_ny; iy++) {
1212       if (isComplex())
1213         vRealResult[ix][iy] = ::atan2 (vImag[ix][iy], vReal[ix][iy]);
1214       else
1215         vRealResult[ix][iy] = 0;
1216     }
1217   }
1218   if (result.isComplex())
1219     result.reallocComplexToReal();
1220     
1221   return true;
1222 }
1223
1224 bool
1225 ImageFile::real (ImageFile& result) const
1226 {
1227   if (m_nx != result.nx() || m_ny != result.ny()) {
1228     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1229     return false;
1230   }
1231   
1232   ImageFileArray vReal = getArray();
1233   ImageFileArray vRealResult = result.getArray();
1234   
1235   for (unsigned int ix = 0; ix < m_nx; ix++) {
1236     for (unsigned int iy = 0; iy < m_ny; iy++) {
1237         vRealResult[ix][iy] = vReal[ix][iy];
1238     }
1239   }
1240
1241   if (result.isComplex())
1242     result.reallocComplexToReal();
1243     
1244   return true;
1245 }
1246
1247 bool
1248 ImageFile::imaginary (ImageFile& result) const
1249 {
1250   if (m_nx != result.nx() || m_ny != result.ny()) {
1251     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1252     return false;
1253   }
1254   
1255   ImageFileArray vImag = getArray();
1256   ImageFileArray vRealResult = result.getArray();
1257   
1258   for (unsigned int ix = 0; ix < m_nx; ix++) {
1259     for (unsigned int iy = 0; iy < m_ny; iy++) {
1260       if (isComplex())
1261         vRealResult[ix][iy] = vImag[ix][iy];
1262       else
1263         vRealResult[ix][iy] = 0;
1264     }
1265   }
1266
1267   if (result.isComplex())
1268       result.reallocComplexToReal();
1269     
1270   return true;
1271 }
1272
1273 bool
1274 ImageFile::square (ImageFile& result) const
1275 {
1276   if (m_nx != result.nx() || m_ny != result.ny()) {
1277     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1278     return false;
1279   }
1280   
1281   if (isComplex() && ! result.isComplex())
1282     result.convertRealToComplex();
1283   
1284   ImageFileArrayConst vLHS = getArray();
1285   ImageFileArrayConst vLHSImag = getImaginaryArray();
1286   ImageFileArray vResult = result.getArray();
1287   ImageFileArray vResultImag = result.getImaginaryArray();
1288   
1289   for (unsigned int ix = 0; ix < m_nx; ix++) {
1290     for (unsigned int iy = 0; iy < m_ny; iy++) {
1291       if (result.isComplex()) {
1292         double dImag = 0;
1293         if (isComplex())
1294           dImag = vLHSImag[ix][iy];
1295         std::complex<double> cLHS (vLHS[ix][iy], dImag);
1296         std::complex<double> cResult = cLHS * cLHS;
1297         vResult[ix][iy] = cResult.real();
1298         vResultImag[ix][iy] = cResult.imag();
1299       } else
1300         vResult[ix][iy] = vLHS[ix][iy] * vLHS[ix][iy];
1301     }
1302   }
1303     
1304   return true;
1305 }
1306
1307 int
1308 ImageFile::convertExportFormatNameToID (const char* const formatName)
1309 {
1310   int formatID = EXPORT_FORMAT_INVALID;
1311   
1312   for (int i = 0; i < s_iExportFormatCount; i++)
1313     if (strcasecmp (formatName, s_aszExportFormatName[i]) == 0) {
1314       formatID = i;
1315       break;
1316     }
1317     
1318     return (formatID);
1319 }
1320
1321 const char*
1322 ImageFile::convertExportFormatIDToName (int formatID)
1323 {
1324   static const char *formatName = "";
1325   
1326   if (formatID >= 0 && formatID < s_iExportFormatCount)
1327     return (s_aszExportFormatName[formatID]);
1328   
1329   return (formatName);
1330 }
1331
1332 const char*
1333 ImageFile::convertExportFormatIDToTitle (const int formatID)
1334 {
1335   static const char *formatTitle = "";
1336   
1337   if (formatID >= 0 && formatID < s_iExportFormatCount)
1338     return (s_aszExportFormatTitle[formatID]);
1339   
1340   return (formatTitle);
1341 }
1342
1343 int
1344 ImageFile::convertImportFormatNameToID (const char* const formatName)
1345 {
1346   int formatID = IMPORT_FORMAT_INVALID;
1347   
1348   for (int i = 0; i < s_iImportFormatCount; i++)
1349     if (strcasecmp (formatName, s_aszImportFormatName[i]) == 0) {
1350       formatID = i;
1351       break;
1352     }
1353     
1354     return (formatID);
1355 }
1356
1357 const char*
1358 ImageFile::convertImportFormatIDToName (int formatID)
1359 {
1360   static const char *formatName = "";
1361   
1362   if (formatID >= 0 && formatID < s_iImportFormatCount)
1363     return (s_aszImportFormatName[formatID]);
1364   
1365   return (formatName);
1366 }
1367
1368 const char*
1369 ImageFile::convertImportFormatIDToTitle (const int formatID)
1370 {
1371   static const char *formatTitle = "";
1372   
1373   if (formatID >= 0 && formatID < s_iImportFormatCount)
1374     return (s_aszImportFormatTitle[formatID]);
1375   
1376   return (formatTitle);
1377 }
1378
1379 bool
1380 ImageFile::importImage (const char* const pszFormat, const char* const pszFilename)
1381 {
1382   int iFormatID = convertImportFormatNameToID (pszFormat);
1383   
1384   if (iFormatID == IMPORT_FORMAT_PPM)
1385     return readImagePPM (pszFilename);
1386 #ifdef HAVE_PNG
1387   else if (iFormatID == IMPORT_FORMAT_PNG)
1388     return readImagePNG (pszFilename);
1389 #endif
1390   
1391   sys_error (ERR_SEVERE, "Invalid format %s [ImageFile::importImage]", pszFormat);
1392   return false;
1393 }
1394
1395 void
1396 ImageFile::skipSpacePPM (FILE* fp)
1397 {
1398   int c = fgetc (fp);
1399   while (isspace (c) || c == '#') {
1400     if (c == '#') {   // comment until end of line
1401       c = fgetc(fp);
1402       while (c != 13 && c != 10)
1403         c = fgetc(fp);
1404     }
1405     else
1406       c = fgetc(fp);
1407   }
1408   
1409   ungetc (c, fp);
1410 }
1411
1412 bool
1413 ImageFile::readImagePPM (const char* const pszFile)
1414 {
1415   FILE* fp = fopen (pszFile, "r");
1416   if ((fp = fopen (pszFile, "r")) == NULL)
1417     return false;
1418   char cSignature = toupper(fgetc(fp));
1419   if (cSignature != 'P') {
1420     fclose(fp);
1421     return false;
1422   }
1423   cSignature = fgetc(fp);
1424   if (cSignature == '5' || cSignature == '6') { // binary modes
1425     fclose(fp);
1426     fp = fopen(pszFile, "rb"); // reopen in binary mode
1427     fgetc(fp);
1428     fgetc(fp);
1429   } else if (cSignature != '2' && cSignature != '3') {
1430     fclose(fp);
1431     return false;
1432   }
1433   
1434   int nRows, nCols, iMaxValue;
1435   skipSpacePPM (fp); 
1436   if (fscanf (fp, "%d", &nCols) != 1) {
1437     fclose(fp);
1438     return false;
1439   }
1440   skipSpacePPM (fp);
1441   if (fscanf (fp, "%d", &nRows) != 1) {
1442     fclose(fp);
1443     return false;
1444   }
1445   skipSpacePPM (fp);
1446   if (fscanf (fp, "%d", &iMaxValue) != 1) {
1447     fclose(fp);
1448     return false;
1449   }
1450   setArraySize (nRows, nCols);
1451   
1452   if (cSignature == '5' || cSignature == '6') { // binary modes
1453     int c = fgetc(fp);
1454     if (c == 13) {
1455       c = fgetc(fp);
1456       if (c != 10)  // read msdos 13-10 newline
1457         ungetc(c, fp);
1458     }
1459   } else
1460     skipSpacePPM (fp); // ascii may have comments
1461   
1462   bool bMonochromeImage = false;
1463   double dMaxValue = iMaxValue;
1464   double dMaxValue3 = iMaxValue * 3;
1465
1466   ImageFileArray v = getArray();
1467   for (int iy = nRows - 1; iy >= 0; iy--) {
1468     for (int ix = 0; ix < nCols; ix++) {
1469       int iGS, iR, iG, iB;
1470       double dR, dG, dB;
1471       switch (cSignature) {
1472       case '2':
1473         if (fscanf(fp, "%d ", &iGS) != 1) {
1474           fclose(fp);
1475           return false;
1476         }
1477         v[ix][iy] = iGS / dMaxValue;
1478         break;
1479       case '5':
1480         iGS = fgetc(fp);
1481         if (iGS == EOF) {
1482           fclose(fp);
1483           return false;
1484         }
1485         v[ix][iy] = iGS / dMaxValue;
1486         break;
1487       case '3':
1488         if (fscanf (fp, "%d %d %d ", &iR, &iG, &iB) != 3) {
1489           fclose(fp);
1490           return false;
1491         }
1492         if (ix == 0 && iy == 0 && (iR == iG && iG == iB))
1493           bMonochromeImage = true;
1494         if (bMonochromeImage)
1495           v[ix][iy] = (iR + iG + iB) / dMaxValue3;
1496         else {
1497           dR = iR / dMaxValue;
1498           dG = iG / dMaxValue;
1499           dB = iB / dMaxValue;
1500           v[ix][iy] = colorToGrayscale (dR, dG, dB);
1501         }
1502         break;
1503       case '6':
1504         iR = fgetc(fp);
1505         iG = fgetc(fp);
1506         iB = fgetc(fp);
1507
1508         if (iB == EOF) {
1509           fclose(fp);
1510           return false;
1511         }
1512         if (ix == 0 && iy == 0 && (iR == iG && iG == iB))
1513           bMonochromeImage = true;
1514
1515         if (bMonochromeImage)
1516           v[ix][iy] = (iR + iG + iB) / dMaxValue3;
1517         else {
1518           dR = iR / dMaxValue;
1519           dG = iG / dMaxValue;
1520           dB = iB / dMaxValue;
1521           v[ix][iy] = colorToGrayscale (dR, dG, dB);
1522         }
1523         break;
1524       }
1525     }
1526   }
1527   
1528   fclose(fp);
1529   return true;
1530 }
1531
1532 #ifdef HAVE_PNG
1533 bool
1534 ImageFile::readImagePNG (const char* const pszFile)
1535 {
1536   FILE* fp = fopen(pszFile, "rb");
1537   if (!fp) 
1538     return false;
1539   unsigned char header[8];
1540   fread (header, 1, 8, fp);
1541   if (png_sig_cmp (header, 0, 8)) {
1542     fclose (fp);
1543     return false;
1544   }
1545   
1546   png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1547   if (!png_ptr) {
1548     fclose(fp);
1549     return false;
1550   }
1551   
1552   png_infop info_ptr = png_create_info_struct(png_ptr);
1553   if (!info_ptr) {
1554     png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
1555     fclose(fp);
1556     return false;
1557   }
1558   
1559   png_infop end_info = png_create_info_struct(png_ptr);
1560   if (!end_info) {
1561     png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
1562     fclose(fp);
1563     return false;
1564   }
1565   
1566   if (setjmp(png_ptr->jmpbuf)) {
1567     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
1568     fclose(fp);
1569     return false;
1570   }
1571   
1572   png_init_io(png_ptr, fp);
1573   png_set_sig_bytes(png_ptr, 8);
1574   png_read_info(png_ptr, info_ptr);
1575   
1576   int width = png_get_image_width (png_ptr, info_ptr);
1577   int height = png_get_image_height (png_ptr, info_ptr);
1578   int bit_depth = png_get_bit_depth (png_ptr, info_ptr);
1579   int color_type = png_get_color_type (png_ptr, info_ptr);
1580   
1581   if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) 
1582     png_set_expand(png_ptr);
1583   
1584   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) 
1585     png_set_expand(png_ptr);
1586   
1587   if (bit_depth < 8)
1588     png_set_packing(png_ptr);
1589   
1590   if (color_type & PNG_COLOR_MASK_ALPHA)
1591     png_set_strip_alpha(png_ptr);
1592   
1593   if (bit_depth == 16)
1594     png_set_swap(png_ptr); // convert to little-endian format
1595   
1596   png_read_update_info(png_ptr, info_ptr); // update with transformations
1597   int rowbytes = png_get_rowbytes (png_ptr, info_ptr);
1598   bit_depth = png_get_bit_depth (png_ptr, info_ptr);
1599   color_type = png_get_color_type (png_ptr, info_ptr);
1600   
1601   png_bytep* row_pointers = new png_bytep [height];
1602   int i;
1603   for (i = 0; i < height; i++)
1604     row_pointers[i] = new unsigned char [rowbytes];
1605   
1606   png_read_image(png_ptr, row_pointers);
1607   
1608   setArraySize (width, height);
1609   ImageFileArray v = getArray();
1610   for (int iy = 0; iy < height; iy++) {
1611     for (int ix = 0; ix < width; ix++) {
1612       double dV = 0;
1613       if (color_type == PNG_COLOR_TYPE_GRAY) {
1614         if (bit_depth == 8)
1615           dV = row_pointers[iy][ix] / 255.;
1616         else if (bit_depth == 16) {
1617           int iBase = ix * 2;
1618           dV = (row_pointers[iy][iBase] + (row_pointers[iy][iBase+1] << 8)) / 65536.;
1619         } else
1620           dV = 0;
1621       } else if (color_type == PNG_COLOR_TYPE_RGB) {
1622         if (bit_depth == 8) {
1623           int iBase = ix * 3;
1624           double dR = row_pointers[iy][iBase] / 255.;
1625           double dG = row_pointers[iy][iBase+1] / 255.;
1626           double dB = row_pointers[iy][iBase+2] / 255.;
1627           dV = colorToGrayscale (dR, dG, dB);
1628         } else
1629           dV = 0;
1630       }
1631       v[ix][height-iy-1] = dV;
1632     }
1633   }
1634   
1635   png_read_end(png_ptr, end_info);
1636   png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
1637   
1638   for (i = 0; i < height; i++)
1639     delete row_pointers[i];
1640   delete row_pointers;
1641   
1642   fclose (fp);
1643   return true;
1644 }
1645 #endif
1646
1647 bool
1648 ImageFile::exportImage (const char* const pszFormat, const char* const pszFilename, int nxcell, int nycell, double densmin, double densmax)
1649 {
1650   int iFormatID = convertExportFormatNameToID (pszFormat);
1651   
1652   if (iFormatID == EXPORT_FORMAT_PGM)
1653     return writeImagePGM (pszFilename, nxcell, nycell, densmin, densmax);
1654   else if (iFormatID == EXPORT_FORMAT_PGMASCII)
1655     return writeImagePGMASCII (pszFilename, nxcell, nycell, densmin, densmax);
1656   else if (iFormatID == EXPORT_FORMAT_TEXT)
1657     return writeImageText (pszFilename);
1658 #ifdef HAVE_PNG
1659   else if (iFormatID == EXPORT_FORMAT_PNG)
1660     return writeImagePNG (pszFilename, 8, nxcell, nycell, densmin, densmax);
1661   else if (iFormatID == EXPORT_FORMAT_PNG16)
1662     return writeImagePNG (pszFilename, 16, nxcell, nycell, densmin, densmax);
1663 #endif
1664 #ifdef HAVE_CTN_DICOM
1665   else if (iFormatID == EXPORT_FORMAT_DICOM) {
1666     DicomExporter dicomExport (this);
1667     bool bSuccess = dicomExport.writeFile (pszFilename);
1668     if (! bSuccess) 
1669       sys_error (ERR_SEVERE, dicomExport.failMessage().c_str());
1670     return bSuccess;
1671   }
1672 #endif
1673   else if (iFormatID == EXPORT_FORMAT_RAW)  
1674          return writeImageRaw(pszFilename, nxcell, nycell);
1675         
1676   
1677   sys_error (ERR_SEVERE, "Invalid format %s [ImageFile::exportImage]", pszFormat);
1678   return false;
1679 }
1680
1681
1682 bool
1683 ImageFile::writeImagePGM (const char* const outfile, int nxcell, int nycell, double densmin, double densmax)
1684 {
1685   FILE *fp;
1686   int nx = m_nx;
1687   int ny = m_ny;
1688   ImageFileArray v = getArray();
1689   
1690   unsigned char* rowp = new unsigned char [nx * nxcell];
1691   
1692   if ((fp = fopen (outfile, "wb")) == NULL)
1693     return false;
1694   
1695   fprintf(fp, "P5\n");
1696   fprintf(fp, "%d %d\n", nx, ny);
1697   fprintf(fp, "255\n");
1698   
1699   for (int irow = ny - 1; irow >= 0; irow--) {
1700     for (int icol = 0; icol < nx; icol++) {
1701       int pos = icol * nxcell;
1702       double dens = (v[icol][irow] - densmin) / (densmax - densmin);
1703       dens = clamp (dens, 0., 1.);
1704       for (int p = pos; p < pos + nxcell; p++) {
1705         rowp[p] = static_cast<unsigned int> (dens * 255.);
1706       }
1707     }
1708     for (int ir = 0; ir < nycell; ir++) {
1709       for (int ic = 0; ic < nx * nxcell; ic++) 
1710         fputc( rowp[ic], fp );
1711     }
1712   }
1713   
1714   delete rowp;
1715   fclose(fp);
1716   
1717   return true;
1718 }
1719
1720 bool
1721 ImageFile::writeImagePGMASCII (const char* const outfile, int nxcell, int nycell, double densmin, double densmax)
1722 {
1723   FILE *fp;
1724   int nx = m_nx;
1725   int ny = m_ny;
1726   ImageFileArray v = getArray();
1727   
1728   unsigned char* rowp = new unsigned char [nx * nxcell];
1729   
1730   if ((fp = fopen (outfile, "wb")) == NULL)
1731     return false;
1732   
1733   fprintf(fp, "P2\n");
1734   fprintf(fp, "%d %d\n", nx, ny);
1735   fprintf(fp, "255\n");
1736   
1737   for (int irow = ny - 1; irow >= 0; irow--) {
1738     for (int icol = 0; icol < nx; icol++) {
1739       int pos = icol * nxcell;
1740       double dens = (v[icol][irow] - densmin) / (densmax - densmin);
1741       dens = clamp (dens, 0., 1.);
1742       for (int p = pos; p < pos + nxcell; p++) {
1743         rowp[p] = static_cast<unsigned int> (dens * 255.);
1744       }
1745     }
1746     for (int ir = 0; ir < nycell; ir++) {
1747       for (int ic = 0; ic < nx * nxcell; ic++) 
1748         fprintf(fp, "%d ", rowp[ic]);
1749       fprintf(fp, "\n");
1750     }
1751   }
1752   
1753   delete rowp;
1754   fclose(fp);
1755   
1756   return true;
1757 }
1758
1759 bool
1760 ImageFile::writeImageText (const char* const outfile)
1761 {
1762   FILE *fp;
1763   int nx = m_nx;
1764   int ny = m_ny;
1765   ImageFileArray v = getArray();
1766   ImageFileArray vImag = getImaginaryArray();
1767   
1768   if ((fp = fopen (outfile, "w")) == NULL)
1769     return false;
1770   
1771   for (int irow = ny - 1; irow >= 0; irow--) {
1772     for (int icol = 0; icol < nx; icol++) {
1773       if (isComplex()) {
1774         if (vImag[icol][irow] >= 0)
1775           fprintf (fp, "%.9g+%.9gi ", v[icol][irow], vImag[icol][irow]);
1776         else
1777           fprintf (fp, "%.9g-%.9gi ", v[icol][irow], -vImag[icol][irow]);
1778       } else
1779         fprintf (fp, "%12.8g ", v[icol][irow]);
1780     }
1781     fprintf(fp, "\n");
1782   }
1783   
1784   fclose(fp);
1785   
1786   return true;
1787 }
1788
1789
1790 #ifdef HAVE_PNG
1791 bool
1792 ImageFile::writeImagePNG (const char* const outfile, int bitdepth, int nxcell, int nycell, double densmin, double densmax)
1793 {
1794   double max_out_level = (1 << bitdepth) - 1;
1795   int nx = m_nx;
1796   int ny = m_ny;
1797   ImageFileArray v = getArray();
1798   
1799   unsigned char* rowp = new unsigned char [nx * nxcell * (bitdepth / 8)];
1800   
1801   FILE *fp = fopen (outfile, "wb");
1802   if (! fp)
1803     return false;
1804   
1805   png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1806   if (! png_ptr)
1807     return false;
1808   
1809   png_infop info_ptr = png_create_info_struct (png_ptr);
1810   if (! info_ptr) {
1811     png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
1812     fclose (fp);
1813     return false;
1814   }
1815   
1816   if (setjmp (png_ptr->jmpbuf)) {
1817     png_destroy_write_struct (&png_ptr, &info_ptr);
1818     fclose (fp);
1819     return false;
1820   }
1821   
1822   png_init_io(png_ptr, fp);
1823   
1824   png_set_IHDR (png_ptr, info_ptr, nx * nxcell, ny * nycell, bitdepth, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1825   
1826   png_write_info(png_ptr, info_ptr);
1827   for (int irow = ny - 1; irow >= 0; irow--) {
1828     png_bytep row_pointer = rowp;
1829     
1830     for (int icol = 0; icol < nx; icol++) {
1831       int pos = icol * nxcell;
1832       double dens = (v[icol][irow] - densmin) / (densmax - densmin);
1833       dens = clamp (dens, 0., 1.);
1834       unsigned int outval = static_cast<unsigned int> (dens * max_out_level);
1835       
1836       for (int p = pos; p < pos + nxcell; p++) {
1837         if (bitdepth == 8)
1838           rowp[p] = outval;
1839         else {
1840           int rowpos = p * 2;
1841           rowp[rowpos+1] = (outval >> 8) & 0xFF;
1842           rowp[rowpos] = (outval & 0xFF);
1843         }
1844       }
1845     }
1846     for (int ir = 0; ir < nycell; ir++)
1847       png_write_rows (png_ptr, &row_pointer, 1);
1848   }
1849   
1850   png_write_end (png_ptr, info_ptr);
1851   png_destroy_write_struct (&png_ptr, &info_ptr);
1852   delete rowp;
1853   
1854   fclose(fp);
1855   
1856   return true;
1857 }
1858 #endif
1859
1860 #ifdef HAVE_GD
1861 #include "gd.h"
1862 static const int N_GRAYSCALE=256;
1863
1864 bool
1865 ImageFile::writeImageGIF (const char* const outfile, int nxcell, int nycell, double densmin, double densmax)
1866 {
1867   int gs_indices[N_GRAYSCALE];
1868   int nx = m_nx;
1869   int ny = m_ny;
1870   ImageFileArray v = getArray();
1871   
1872   unsigned char* rowp = new unsigned char [nx * nxcell];
1873   
1874   gdImagePtr gif = gdImageCreate(nx * nxcell, ny * nycell);
1875   for (int i = 0; i < N_GRAYSCALE; i++)
1876     gs_indices[i] = gdImageColorAllocate(gif, i, i, i);
1877   
1878   int lastrow = ny * nycell - 1;
1879   for (int irow = 0; irow < ny; irow++) {
1880     int rpos = irow * nycell;
1881     for (int ir = rpos; ir < rpos + nycell; ir++) {
1882       for (int icol = 0; icol < nx; icol++) {
1883         int cpos = icol * nxcell;
1884         double dens = (v[icol][irow] - densmin) / (densmax - densmin);
1885         dens = clamp(dens, 0., 1.);
1886         for (int ic = cpos; ic < cpos + nxcell; ic++) {
1887           rowp[ic] = (unsigned int) (dens * (double) (N_GRAYSCALE - 1));
1888           gdImageSetPixel(gif, ic, lastrow - ir, gs_indices[rowp[ic]]);
1889         }
1890       }
1891     }
1892   }
1893   
1894   FILE *out;
1895   if ((out = fopen (outfile,"w")) == NULL) {
1896     sys_error(ERR_SEVERE, "Error opening output file %s for writing", outfile);
1897     return false;
1898   }
1899   gdImageGif(gif,out);
1900   fclose(out);
1901   gdImageDestroy(gif);
1902   
1903   delete rowp;
1904   
1905   return true;
1906 }
1907 #endif
1908
1909 bool
1910 ImageFile::writeImageRaw (const char* const outfile, int nxcell, int nycell)
1911 {
1912   FILE *fp;
1913   int nx = m_nx;
1914   int ny = m_ny;
1915   ImageFileArray v = getArray();
1916   
1917   if ((fp = fopen (outfile, "wb")) == NULL)
1918     return false;
1919   
1920   for (int irow = ny - 1; irow >= 0; irow--) {
1921     for (int icol = 0; icol < nx; icol++) {
1922       float dens = v[icol][irow];
1923      fwrite(&dens, sizeof(float), 1, fp);
1924     }
1925   }
1926   
1927   fclose(fp);
1928   return true;
1929 }
1930
1931