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