Update copyright date; remove old CVS keyword
[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         ImageFileArrayConst vLHSImag = getImaginaryArray();
578         ImageFileArray vResult = result.getArray();
579         ImageFileArray vResultImag = result.getImaginaryArray();
580
581         for (unsigned int ix = 0; ix < m_nx; ix++) {
582           for (unsigned int iy = 0; iy < m_ny; iy++) {
583             if (result.isComplex()) {
584               double dImag = 0;
585               if (isComplex())
586                 dImag = vLHSImag[ix][iy];
587               std::complex<double> cLHS (vLHS[ix][iy], dImag);
588               std::complex<double> cResult = std::sqrt(cLHS);
589               vResult[ix][iy] = cResult.real();
590               vResultImag[ix][iy] = cResult.imag();
591             } else
592               vResult[ix][iy] = ::sqrt (vLHS[ix][iy]);
593           }
594         }
595
596
597         return true;
598 }
599
600 bool
601 ImageFile::log (ImageFile& result) const
602 {
603   if (m_nx != result.nx() || m_ny != result.ny()) {
604     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::log]");
605     return false;
606   }
607
608   if (isComplex() && ! result.isComplex())
609     result.convertRealToComplex();
610
611   ImageFileArrayConst vLHS = getArray();
612   ImageFileArrayConst vLHSImag = getImaginaryArray();
613   ImageFileArray vResult = result.getArray();
614   ImageFileArray vResultImag = result.getImaginaryArray();
615
616   for (unsigned int ix = 0; ix < m_nx; ix++) {
617     for (unsigned int iy = 0; iy < m_ny; iy++) {
618       if (result.isComplex()) {
619         double dImag = 0;
620         if (isComplex())
621           dImag = vLHSImag[ix][iy];
622         std::complex<double> cLHS (vLHS[ix][iy], dImag);
623         std::complex<double> cResult = std::log (cLHS);
624         vResult[ix][iy] = cResult.real();
625         vResultImag[ix][iy] = cResult.imag();
626       } else {
627         if (vLHS[ix][iy] > 0)
628           vResult[ix][iy] = ::log (vLHS[ix][iy]);
629         else
630           vResult[ix][iy] = 0;
631       }
632     }
633   }
634
635
636   return true;
637 }
638
639 bool
640 ImageFile::exp (ImageFile& result) const
641 {
642   if (m_nx != result.nx() || m_ny != result.ny()) {
643     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
644     return false;
645   }
646
647   if (isComplex() && ! result.isComplex())
648     result.convertRealToComplex();
649
650   ImageFileArrayConst vLHS = getArray();
651   ImageFileArrayConst vLHSImag = getImaginaryArray();
652   ImageFileArray vResult = result.getArray();
653   ImageFileArray vResultImag = result.getImaginaryArray();
654
655   for (unsigned int ix = 0; ix < m_nx; ix++) {
656     for (unsigned int iy = 0; iy < m_ny; iy++) {
657       if (result.isComplex()) {
658         double dImag = 0;
659         if (isComplex())
660           dImag = vLHSImag[ix][iy];
661         std::complex<double> cLHS (vLHS[ix][iy], dImag);
662         std::complex<double> cResult = std::exp (cLHS);
663         vResult[ix][iy] = cResult.real();
664         vResultImag[ix][iy] = cResult.imag();
665       } else
666         vResult[ix][iy] = ::exp (vLHS[ix][iy]);
667     }
668   }
669
670
671   return true;
672 }
673
674 bool
675 ImageFile::scaleImage (ImageFile& result) const
676 {
677   unsigned int nx = m_nx;
678   unsigned int ny = m_ny;
679   unsigned int newNX = result.nx();
680   unsigned int newNY = result.ny();
681
682   double dXScale = static_cast<double>(newNX) / static_cast<double>(nx);
683   double dYScale = static_cast<double>(newNY) / static_cast<double>(ny);
684
685   if (isComplex() && ! result.isComplex())
686     result.convertRealToComplex();
687
688   ImageFileArrayConst vReal = getArray();
689   ImageFileArrayConst vImag = getImaginaryArray();
690   ImageFileArray vResult = result.getArray();
691   ImageFileArray vResultImag = result.getImaginaryArray();
692
693   BilinearInterpolator<ImageFileValue> realInterp (vReal, nx, ny);
694   BilinearInterpolator<ImageFileValue> imagInterp (vImag, nx, ny);
695
696   for (unsigned int ix = 0; ix < newNX; ix++) {
697     for (unsigned int iy = 0; iy < newNY; iy++) {
698       double dXPos = ix / dXScale;
699       double dYPos = iy / dYScale;
700       vResult[ix][iy] = realInterp.interpolate (dXPos, dYPos);
701       if (result.isComplex()) {
702         if (isComplex()) {
703           vResultImag[ix][iy] = imagInterp.interpolate (dXPos, dYPos);
704         } else {
705           vResultImag[ix][iy] = 0;
706         }
707       }
708     }
709   }
710
711   return true;
712 }
713
714 #ifdef HAVE_FFTW
715 bool
716 ImageFile::fft (ImageFile& result) const
717 {
718   if (m_nx != result.nx() || m_ny != result.ny()) {
719     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
720     return false;
721   }
722
723   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
724     if (! result.convertRealToComplex ())
725       return false;
726   }
727
728   fftw_complex* in = static_cast<fftw_complex*> (fftw_malloc (sizeof(fftw_complex) * m_nx * m_ny));
729
730   ImageFileArrayConst vReal = getArray();
731   ImageFileArrayConst vImag = getImaginaryArray();
732
733   unsigned int ix, iy;
734   unsigned int iArray = 0;
735   for (ix = 0; ix < m_nx; ix++) {
736     for (iy = 0; iy < m_ny; iy++) {
737       in[iArray][0] = vReal[ix][iy];
738       if (isComplex())
739         in[iArray][1] = vImag[ix][iy];
740       else
741         in[iArray][1] = 0;
742       iArray++;
743     }
744   }
745
746   fftw_plan plan = fftw_plan_dft_2d (m_nx, m_ny, in, in, FFTW_FORWARD, FFTW_ESTIMATE);
747   fftw_execute (plan);
748
749   ImageFileArray vRealResult = result.getArray();
750   ImageFileArray vImagResult = result.getImaginaryArray();
751   iArray = 0;
752   unsigned int iScale = m_nx * m_ny;
753   for (ix = 0; ix < m_nx; ix++) {
754     for (iy = 0; iy < m_ny; iy++) {
755       vRealResult[ix][iy] = in[iArray][0] / iScale;
756       vImagResult[ix][iy] = in[iArray][1] / iScale;
757       iArray++;
758     }
759   }
760   fftw_free(in);
761   fftw_destroy_plan (plan);
762
763   Fourier::shuffleFourierToNaturalOrder (result);
764
765   return true;
766 }
767
768
769 bool
770 ImageFile::ifft (ImageFile& result) const
771 {
772   if (m_nx != result.nx() || m_ny != result.ny()) {
773     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
774     return false;
775   }
776
777   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
778     if (! result.convertRealToComplex ())
779       return false;
780   }
781
782   ImageFileArrayConst vReal = getArray();
783   ImageFileArrayConst vImag = getImaginaryArray();
784   ImageFileArray vRealResult = result.getArray();
785   ImageFileArray vImagResult = result.getImaginaryArray();
786   unsigned int ix, iy;
787   for (ix = 0; ix < m_nx; ix++) {
788     for (iy = 0; iy < m_ny; iy++) {
789       vRealResult[ix][iy] = vReal[ix][iy];
790       if (isComplex())
791         vImagResult[ix][iy] = vImag[ix][iy];
792       else
793         vImagResult[ix][iy] = 0;
794     }
795   }
796
797   Fourier::shuffleNaturalToFourierOrder (result);
798
799   fftw_complex* in = static_cast<fftw_complex*>(fftw_malloc(sizeof(fftw_complex) * m_nx * m_ny));
800
801   unsigned int iArray = 0;
802   for (ix = 0; ix < m_nx; ix++) {
803     for (iy = 0; iy < m_ny; iy++) {
804       in[iArray][0] = vRealResult[ix][iy];
805       in[iArray][1] = vImagResult[ix][iy];
806       iArray++;
807     }
808   }
809
810   fftw_plan plan = fftw_plan_dft_2d (m_nx, m_ny, in, in, FFTW_BACKWARD, FFTW_ESTIMATE);
811
812   fftw_execute (plan);
813
814   iArray = 0;
815   for (ix = 0; ix < m_nx; ix++) {
816     for (iy = 0; iy < m_ny; iy++) {
817       vRealResult[ix][iy] = in[iArray][0];
818       vImagResult[ix][iy] = in[iArray][1];
819       iArray++;
820     }
821   }
822   fftw_destroy_plan (plan);
823   fftw_free(in);
824
825   return true;
826 }
827
828 bool
829 ImageFile::fftRows (ImageFile& result) const
830 {
831   if (m_nx != result.nx() || m_ny != result.ny()) {
832     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::fftRows]");
833     return false;
834   }
835
836   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
837     if (! result.convertRealToComplex ())
838       return false;
839   }
840
841   ImageFileArrayConst vReal = getArray();
842   ImageFileArrayConst vImag = getImaginaryArray();
843
844   fftw_complex* in = static_cast<fftw_complex*>(fftw_malloc(sizeof(fftw_complex) * m_nx));
845   fftw_plan plan = fftw_plan_dft_1d (m_nx, in, in, FFTW_FORWARD, FFTW_ESTIMATE);
846
847   std::complex<double>* pcRow = new std::complex<double> [m_nx];
848   for (unsigned int iy = 0; iy < m_ny; iy++) {
849     unsigned int ix;
850     for (ix = 0; ix < m_nx; ix++) {
851       in[ix][0] = vReal[ix][iy];
852       if (isComplex())
853         in[ix][1] = vImag[ix][iy];
854       else
855         in[ix][1] = 0;
856     }
857
858     fftw_execute (plan);
859
860     for (ix = 0; ix < m_nx; ix++)
861       pcRow[ix] = std::complex<double>(in[ix][0], in[ix][1]);
862
863     Fourier::shuffleFourierToNaturalOrder (pcRow, m_nx);
864     for (ix = 0; ix < m_nx; ix++) {
865       vReal[ix][iy] = pcRow[ix].real() / m_nx;
866       vImag[ix][iy] = pcRow[ix].imag() / m_nx;
867     }
868   }
869   delete [] pcRow;
870
871   fftw_destroy_plan (plan);
872   fftw_free(in);
873
874   return true;
875 }
876
877 bool
878 ImageFile::ifftRows (ImageFile& result) const
879 {
880   if (m_nx != result.nx() || m_ny != result.ny()) {
881     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::fftRows]");
882     return false;
883   }
884
885   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
886     if (! result.convertRealToComplex ())
887       return false;
888   }
889
890   ImageFileArrayConst vReal = getArray();
891   ImageFileArrayConst vImag = getImaginaryArray();
892
893   fftw_complex* in = static_cast<fftw_complex*>(fftw_malloc(sizeof(fftw_complex) * m_nx));
894   fftw_plan plan = fftw_plan_dft_1d (m_nx, in, in, FFTW_BACKWARD, FFTW_ESTIMATE);
895   std::complex<double>* pcRow = new std::complex<double> [m_nx];
896
897   unsigned int ix, iy;
898   // unsigned int iArray = 0;
899   for (iy = 0; iy < m_ny; iy++) {
900     for (ix = 0; ix < m_nx; ix++) {
901       double dImag = 0;
902       if (isComplex())
903         dImag = vImag[ix][iy];
904       pcRow[ix] = std::complex<double> (vReal[ix][iy], dImag);
905     }
906
907     Fourier::shuffleNaturalToFourierOrder (pcRow, m_nx);
908
909     for (ix = 0; ix < m_nx; ix++) {
910       in[ix][0] = pcRow[ix].real();
911       in[ix][1] = pcRow[ix].imag();
912     }
913
914     fftw_execute (plan);
915
916     for (ix = 0; ix < m_nx; ix++) {
917       vReal[ix][iy] = in[ix][0];
918       vImag[ix][iy] = in[ix][1];
919     }
920   }
921   delete [] pcRow;
922
923   fftw_destroy_plan (plan);
924   fftw_free(in);
925
926   return true;
927 }
928
929 bool
930 ImageFile::fftCols (ImageFile& result) const
931 {
932   if (m_nx != result.nx() || m_ny != result.ny()) {
933     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::fftRows]");
934     return false;
935   }
936
937   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
938     if (! result.convertRealToComplex ())
939       return false;
940   }
941
942   ImageFileArrayConst vReal = getArray();
943   ImageFileArrayConst vImag = getImaginaryArray();
944
945   fftw_complex* in = static_cast<fftw_complex*>(fftw_malloc(sizeof(fftw_complex) * m_ny));
946   fftw_plan plan = fftw_plan_dft_1d (m_ny, in, in, FFTW_FORWARD, FFTW_ESTIMATE);
947
948   std::complex<double>* pcCol = new std::complex<double> [m_ny];
949   for (unsigned int ix = 0; ix < m_nx; ix++) {
950     unsigned int iy;
951     for (iy = 0; iy < m_ny; iy++) {
952       in[iy][0] = vReal[ix][iy];
953       if (isComplex())
954         in[iy][1] = vImag[ix][iy];
955       else
956         in[iy][1] = 0;
957     }
958
959     fftw_execute (plan);
960
961     for (iy = 0; iy < m_ny; iy++)
962       pcCol[iy] = std::complex<double>(in[iy][0], in[iy][1]);
963
964     Fourier::shuffleFourierToNaturalOrder (pcCol, m_ny);
965     for (iy = 0; iy < m_ny; iy++) {
966       vReal[ix][iy] = pcCol[iy].real() / m_ny;
967       vImag[ix][iy] = pcCol[iy].imag() / m_ny;
968     }
969   }
970   delete [] pcCol;
971
972   fftw_destroy_plan (plan);
973   fftw_free(in);
974
975   return true;
976 }
977
978 bool
979 ImageFile::ifftCols (ImageFile& result) const
980 {
981   if (m_nx != result.nx() || m_ny != result.ny()) {
982     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::fftRows]");
983     return false;
984   }
985
986   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
987     if (! result.convertRealToComplex ())
988       return false;
989   }
990
991   ImageFileArrayConst vReal = getArray();
992   ImageFileArrayConst vImag = getImaginaryArray();
993
994   fftw_complex* in = static_cast<fftw_complex*>(fftw_malloc(sizeof(fftw_complex) * m_ny));
995   fftw_plan plan = fftw_plan_dft_1d (m_ny, in, in, FFTW_BACKWARD, FFTW_ESTIMATE);
996   std::complex<double>* pcCol = new std::complex<double> [m_ny];
997
998   unsigned int ix, iy;
999   // unsigned int iArray = 0;
1000   for (ix = 0; ix < m_nx; ix++) {
1001     for (iy = 0; iy < m_ny; iy++) {
1002       double dImag = 0;
1003       if (isComplex())
1004         dImag = vImag[ix][iy];
1005       pcCol[iy] = std::complex<double> (vReal[ix][iy], dImag);
1006     }
1007
1008     Fourier::shuffleNaturalToFourierOrder (pcCol, m_ny);
1009
1010     for (iy = 0; iy < m_ny; iy++) {
1011       in[iy][0] = pcCol[iy].real();
1012       in[iy][1] = pcCol[iy].imag();
1013     }
1014
1015     fftw_execute (plan);
1016
1017     for (iy = 0; iy < m_ny; iy++) {
1018       vReal[ix][iy] = in[iy][0];
1019       vImag[ix][iy] = in[iy][1];
1020     }
1021   }
1022   delete [] pcCol;
1023
1024   fftw_destroy_plan (plan);
1025   fftw_free(in);
1026
1027   return true;
1028 }
1029
1030 #endif // HAVE_FFTW
1031
1032
1033
1034 bool
1035 ImageFile::fourier (ImageFile& result) const
1036 {
1037   if (m_nx != result.nx() || m_ny != result.ny()) {
1038     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1039     return false;
1040   }
1041
1042   if (! result.isComplex())
1043     if (! result.convertRealToComplex ())
1044       return false;
1045
1046     ImageFileArrayConst vLHS = getArray();
1047     ImageFileArrayConst vLHSImag = getImaginaryArray();
1048     ImageFileArray vRealResult = result.getArray();
1049     ImageFileArray vImagResult = result.getImaginaryArray();
1050
1051     unsigned int ix, iy;
1052
1053     // alloc output matrix
1054     CTSimComplex** complexOut = new CTSimComplex* [m_nx];
1055     for (ix = 0; ix < m_nx; ix++)
1056       complexOut[ix] = new CTSimComplex [m_ny];
1057
1058     // fourier each x column
1059     CTSimComplex* pY = new CTSimComplex [m_ny];
1060     for (ix = 0; ix < m_nx; ix++) {
1061       for (iy = 0; iy < m_ny; iy++) {
1062         double dImag = 0;
1063         if (isComplex())
1064           dImag = vLHSImag[ix][iy];
1065         pY[iy] = std::complex<double>(vLHS[ix][iy], dImag);
1066       }
1067       ProcessSignal::finiteFourierTransform (pY, complexOut[ix], m_ny,  ProcessSignal::FORWARD);
1068     }
1069     delete [] pY;
1070
1071     // fourier each y row
1072     CTSimComplex* pX = new CTSimComplex [m_nx];
1073     CTSimComplex* complexOutRow = new CTSimComplex [m_nx];
1074     for (iy = 0; iy < m_ny; iy++) {
1075       for (ix = 0; ix < m_nx; ix++)
1076         pX[ix] = complexOut[ix][iy];
1077       ProcessSignal::finiteFourierTransform (pX, complexOutRow, m_nx, ProcessSignal::FORWARD);
1078       for (ix = 0; ix < m_nx; ix++)
1079         complexOut[ix][iy] = complexOutRow[ix];
1080     }
1081     delete [] pX;
1082     delete [] complexOutRow;
1083
1084     for (ix = 0; ix < m_nx; ix++)
1085       for (iy = 0; iy < m_ny; iy++) {
1086         vRealResult[ix][iy] = complexOut[ix][iy].real();
1087         vImagResult[ix][iy] = complexOut[ix][iy].imag();
1088       }
1089
1090       Fourier::shuffleFourierToNaturalOrder (result);
1091
1092       // delete complexOut matrix
1093       for (ix = 0; ix < m_nx; ix++)
1094         delete [] complexOut[ix];
1095       delete [] complexOut;
1096
1097       return true;
1098 }
1099
1100 bool
1101 ImageFile::inverseFourier (ImageFile& result) const
1102 {
1103   if (m_nx != result.nx() || m_ny != result.ny()) {
1104     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1105     return false;
1106   }
1107
1108   if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
1109     if (! result.convertRealToComplex ())
1110       return false;
1111   }
1112
1113   ImageFileArrayConst vLHSReal = getArray();
1114   ImageFileArrayConst vLHSImag = getImaginaryArray();
1115   ImageFileArray vRealResult = result.getArray();
1116   ImageFileArray vImagResult = result.getImaginaryArray();
1117
1118   unsigned int ix, iy;
1119   // alloc 2d complex output matrix
1120   CTSimComplex** complexOut = new CTSimComplex* [m_nx];
1121   for (ix = 0; ix < m_nx; ix++)
1122     complexOut[ix] = new CTSimComplex [m_ny];
1123
1124   // put input image into result
1125   for (ix = 0; ix < m_nx; ix++)
1126     for (iy = 0; iy < m_ny; iy++) {
1127       vRealResult[ix][iy] = vLHSReal[ix][iy];
1128       if (isComplex())
1129         vImagResult[ix][iy] = vLHSImag[ix][iy];
1130       else
1131         vImagResult[ix][iy] = 0;
1132     }
1133
1134     Fourier::shuffleNaturalToFourierOrder (result);
1135
1136     // ifourier each x column
1137     CTSimComplex* pCol = new CTSimComplex [m_ny];
1138     for (ix = 0; ix < m_nx; ix++) {
1139       for (iy = 0; iy < m_ny; iy++) {
1140         pCol[iy] = std::complex<double> (vRealResult[ix][iy], vImagResult[ix][iy]);
1141       }
1142       ProcessSignal::finiteFourierTransform (pCol, complexOut[ix], m_ny,  ProcessSignal::BACKWARD);
1143     }
1144     delete [] pCol;
1145
1146     // ifourier each y row
1147     CTSimComplex* complexInRow = new CTSimComplex [m_nx];
1148     CTSimComplex* complexOutRow = new CTSimComplex [m_nx];
1149     for (iy = 0; iy < m_ny; iy++) {
1150       for (ix = 0; ix < m_nx; ix++)
1151         complexInRow[ix] = complexOut[ix][iy];
1152       ProcessSignal::finiteFourierTransform (complexInRow, complexOutRow, m_nx, ProcessSignal::BACKWARD);
1153       for (ix = 0; ix < m_nx; ix++)
1154         complexOut[ix][iy] = complexOutRow[ix];
1155     }
1156     delete [] complexInRow;
1157     delete [] complexOutRow;
1158
1159     for (ix = 0; ix < m_nx; ix++)
1160       for (iy = 0; iy < m_ny; iy++) {
1161         vRealResult[ix][iy] = complexOut[ix][iy].real();
1162         vImagResult[ix][iy] = complexOut[ix][iy].imag();
1163       }
1164
1165       // delete complexOut matrix
1166       for (ix = 0; ix < m_nx; ix++)
1167         delete [] complexOut[ix];
1168       delete [] complexOut;
1169
1170       return true;
1171 }
1172
1173
1174 bool
1175 ImageFile::magnitude (ImageFile& result) const
1176 {
1177   if (m_nx != result.nx() || m_ny != result.ny()) {
1178     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1179     return false;
1180   }
1181
1182   ImageFileArray vReal = getArray();
1183   ImageFileArray vImag = getImaginaryArray();
1184   ImageFileArray vRealResult = result.getArray();
1185
1186   for (unsigned int ix = 0; ix < m_nx; ix++)
1187     for (unsigned int iy = 0; iy < m_ny; iy++) {
1188       if (isComplex())
1189         vRealResult[ix][iy] = ::sqrt (vReal[ix][iy] * vReal[ix][iy] + vImag[ix][iy] * vImag[ix][iy]);
1190       else
1191         vRealResult[ix][iy] = ::fabs(vReal[ix][iy]);
1192     }
1193
1194     if (result.isComplex())
1195       result.reallocComplexToReal();
1196
1197     return true;
1198 }
1199
1200 bool
1201 ImageFile::phase (ImageFile& result) const
1202 {
1203   if (m_nx != result.nx() || m_ny != result.ny()) {
1204     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1205     return false;
1206   }
1207
1208   ImageFileArray vReal = getArray();
1209   ImageFileArray vImag = getImaginaryArray();
1210   ImageFileArray vRealResult = result.getArray();
1211
1212   for (unsigned int ix = 0; ix < m_nx; ix++) {
1213     for (unsigned int iy = 0; iy < m_ny; iy++) {
1214       if (isComplex())
1215         vRealResult[ix][iy] = ::atan2 (vImag[ix][iy], vReal[ix][iy]);
1216       else
1217         vRealResult[ix][iy] = 0;
1218     }
1219   }
1220   if (result.isComplex())
1221     result.reallocComplexToReal();
1222
1223   return true;
1224 }
1225
1226 bool
1227 ImageFile::real (ImageFile& result) const
1228 {
1229   if (m_nx != result.nx() || m_ny != result.ny()) {
1230     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1231     return false;
1232   }
1233
1234   ImageFileArray vReal = getArray();
1235   ImageFileArray vRealResult = result.getArray();
1236
1237   for (unsigned int ix = 0; ix < m_nx; ix++) {
1238     for (unsigned int iy = 0; iy < m_ny; iy++) {
1239         vRealResult[ix][iy] = vReal[ix][iy];
1240     }
1241   }
1242
1243   if (result.isComplex())
1244     result.reallocComplexToReal();
1245
1246   return true;
1247 }
1248
1249 bool
1250 ImageFile::imaginary (ImageFile& result) const
1251 {
1252   if (m_nx != result.nx() || m_ny != result.ny()) {
1253     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1254     return false;
1255   }
1256
1257   ImageFileArray vImag = getArray();
1258   ImageFileArray vRealResult = result.getArray();
1259
1260   for (unsigned int ix = 0; ix < m_nx; ix++) {
1261     for (unsigned int iy = 0; iy < m_ny; iy++) {
1262       if (isComplex())
1263         vRealResult[ix][iy] = vImag[ix][iy];
1264       else
1265         vRealResult[ix][iy] = 0;
1266     }
1267   }
1268
1269   if (result.isComplex())
1270       result.reallocComplexToReal();
1271
1272   return true;
1273 }
1274
1275 bool
1276 ImageFile::square (ImageFile& result) const
1277 {
1278   if (m_nx != result.nx() || m_ny != result.ny()) {
1279     sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::invertPixelValues]");
1280     return false;
1281   }
1282
1283   if (isComplex() && ! result.isComplex())
1284     result.convertRealToComplex();
1285
1286   ImageFileArrayConst vLHS = getArray();
1287   ImageFileArrayConst vLHSImag = getImaginaryArray();
1288   ImageFileArray vResult = result.getArray();
1289   ImageFileArray vResultImag = result.getImaginaryArray();
1290
1291   for (unsigned int ix = 0; ix < m_nx; ix++) {
1292     for (unsigned int iy = 0; iy < m_ny; iy++) {
1293       if (result.isComplex()) {
1294         double dImag = 0;
1295         if (isComplex())
1296           dImag = vLHSImag[ix][iy];
1297         std::complex<double> cLHS (vLHS[ix][iy], dImag);
1298         std::complex<double> cResult = cLHS * cLHS;
1299         vResult[ix][iy] = cResult.real();
1300         vResultImag[ix][iy] = cResult.imag();
1301       } else
1302         vResult[ix][iy] = vLHS[ix][iy] * vLHS[ix][iy];
1303     }
1304   }
1305
1306   return true;
1307 }
1308
1309 int
1310 ImageFile::convertExportFormatNameToID (const char* const formatName)
1311 {
1312   int formatID = EXPORT_FORMAT_INVALID;
1313
1314   for (int i = 0; i < s_iExportFormatCount; i++)
1315     if (strcasecmp (formatName, s_aszExportFormatName[i]) == 0) {
1316       formatID = i;
1317       break;
1318     }
1319
1320     return (formatID);
1321 }
1322
1323 const char*
1324 ImageFile::convertExportFormatIDToName (int formatID)
1325 {
1326   static const char *formatName = "";
1327
1328   if (formatID >= 0 && formatID < s_iExportFormatCount)
1329     return (s_aszExportFormatName[formatID]);
1330
1331   return (formatName);
1332 }
1333
1334 const char*
1335 ImageFile::convertExportFormatIDToTitle (const int formatID)
1336 {
1337   static const char *formatTitle = "";
1338
1339   if (formatID >= 0 && formatID < s_iExportFormatCount)
1340     return (s_aszExportFormatTitle[formatID]);
1341
1342   return (formatTitle);
1343 }
1344
1345 int
1346 ImageFile::convertImportFormatNameToID (const char* const formatName)
1347 {
1348   int formatID = IMPORT_FORMAT_INVALID;
1349
1350   for (int i = 0; i < s_iImportFormatCount; i++)
1351     if (strcasecmp (formatName, s_aszImportFormatName[i]) == 0) {
1352       formatID = i;
1353       break;
1354     }
1355
1356     return (formatID);
1357 }
1358
1359 const char*
1360 ImageFile::convertImportFormatIDToName (int formatID)
1361 {
1362   static const char *formatName = "";
1363
1364   if (formatID >= 0 && formatID < s_iImportFormatCount)
1365     return (s_aszImportFormatName[formatID]);
1366
1367   return (formatName);
1368 }
1369
1370 const char*
1371 ImageFile::convertImportFormatIDToTitle (const int formatID)
1372 {
1373   static const char *formatTitle = "";
1374
1375   if (formatID >= 0 && formatID < s_iImportFormatCount)
1376     return (s_aszImportFormatTitle[formatID]);
1377
1378   return (formatTitle);
1379 }
1380
1381 bool
1382 ImageFile::importImage (const char* const pszFormat, const char* const pszFilename)
1383 {
1384   int iFormatID = convertImportFormatNameToID (pszFormat);
1385
1386   if (iFormatID == IMPORT_FORMAT_PPM)
1387     return readImagePPM (pszFilename);
1388 #ifdef HAVE_PNG
1389   else if (iFormatID == IMPORT_FORMAT_PNG)
1390     return readImagePNG (pszFilename);
1391 #endif
1392
1393   sys_error (ERR_SEVERE, "Invalid format %s [ImageFile::importImage]", pszFormat);
1394   return false;
1395 }
1396
1397 void
1398 ImageFile::skipSpacePPM (FILE* fp)
1399 {
1400   int c = fgetc (fp);
1401   while (isspace (c) || c == '#') {
1402     if (c == '#') {   // comment until end of line
1403       c = fgetc(fp);
1404       while (c != 13 && c != 10)
1405         c = fgetc(fp);
1406     }
1407     else
1408       c = fgetc(fp);
1409   }
1410
1411   ungetc (c, fp);
1412 }
1413
1414 bool
1415 ImageFile::readImagePPM (const char* const pszFile)
1416 {
1417   FILE* fp = fopen (pszFile, "r");
1418   if ((fp = fopen (pszFile, "r")) == NULL)
1419     return false;
1420   char cSignature = toupper(fgetc(fp));
1421   if (cSignature != 'P') {
1422     fclose(fp);
1423     return false;
1424   }
1425   cSignature = fgetc(fp);
1426   if (cSignature == '5' || cSignature == '6') { // binary modes
1427     fclose(fp);
1428     fp = fopen(pszFile, "rb"); // reopen in binary mode
1429     fgetc(fp);
1430     fgetc(fp);
1431   } else if (cSignature != '2' && cSignature != '3') {
1432     fclose(fp);
1433     return false;
1434   }
1435
1436   int nRows, nCols, iMaxValue;
1437   skipSpacePPM (fp);
1438   if (fscanf (fp, "%d", &nCols) != 1) {
1439     fclose(fp);
1440     return false;
1441   }
1442   skipSpacePPM (fp);
1443   if (fscanf (fp, "%d", &nRows) != 1) {
1444     fclose(fp);
1445     return false;
1446   }
1447   skipSpacePPM (fp);
1448   if (fscanf (fp, "%d", &iMaxValue) != 1) {
1449     fclose(fp);
1450     return false;
1451   }
1452   setArraySize (nRows, nCols);
1453
1454   if (cSignature == '5' || cSignature == '6') { // binary modes
1455     int c = fgetc(fp);
1456     if (c == 13) {
1457       c = fgetc(fp);
1458       if (c != 10)  // read msdos 13-10 newline
1459         ungetc(c, fp);
1460     }
1461   } else
1462     skipSpacePPM (fp); // ascii may have comments
1463
1464   bool bMonochromeImage = false;
1465   double dMaxValue = iMaxValue;
1466   double dMaxValue3 = iMaxValue * 3;
1467
1468   ImageFileArray v = getArray();
1469   for (int iy = nRows - 1; iy >= 0; iy--) {
1470     for (int ix = 0; ix < nCols; ix++) {
1471       int iGS, iR, iG, iB;
1472       double dR, dG, dB;
1473       switch (cSignature) {
1474       case '2':
1475         if (fscanf(fp, "%d ", &iGS) != 1) {
1476           fclose(fp);
1477           return false;
1478         }
1479         v[ix][iy] = iGS / dMaxValue;
1480         break;
1481       case '5':
1482         iGS = fgetc(fp);
1483         if (iGS == EOF) {
1484           fclose(fp);
1485           return false;
1486         }
1487         v[ix][iy] = iGS / dMaxValue;
1488         break;
1489       case '3':
1490         if (fscanf (fp, "%d %d %d ", &iR, &iG, &iB) != 3) {
1491           fclose(fp);
1492           return false;
1493         }
1494         if (ix == 0 && iy == 0 && (iR == iG && iG == iB))
1495           bMonochromeImage = true;
1496         if (bMonochromeImage)
1497           v[ix][iy] = (iR + iG + iB) / dMaxValue3;
1498         else {
1499           dR = iR / dMaxValue;
1500           dG = iG / dMaxValue;
1501           dB = iB / dMaxValue;
1502           v[ix][iy] = colorToGrayscale (dR, dG, dB);
1503         }
1504         break;
1505       case '6':
1506         iR = fgetc(fp);
1507         iG = fgetc(fp);
1508         iB = fgetc(fp);
1509
1510         if (iB == EOF) {
1511           fclose(fp);
1512           return false;
1513         }
1514         if (ix == 0 && iy == 0 && (iR == iG && iG == iB))
1515           bMonochromeImage = true;
1516
1517         if (bMonochromeImage)
1518           v[ix][iy] = (iR + iG + iB) / dMaxValue3;
1519         else {
1520           dR = iR / dMaxValue;
1521           dG = iG / dMaxValue;
1522           dB = iB / dMaxValue;
1523           v[ix][iy] = colorToGrayscale (dR, dG, dB);
1524         }
1525         break;
1526       }
1527     }
1528   }
1529
1530   fclose(fp);
1531   return true;
1532 }
1533
1534 #ifdef HAVE_PNG
1535 bool
1536 ImageFile::readImagePNG (const char* const pszFile)
1537 {
1538   FILE* fp = fopen(pszFile, "rb");
1539   if (!fp)
1540     return false;
1541   unsigned char header[8];
1542   fread (header, 1, 8, fp);
1543   if (png_sig_cmp (header, 0, 8)) {
1544     fclose (fp);
1545     return false;
1546   }
1547
1548   png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1549   if (!png_ptr) {
1550     fclose(fp);
1551     return false;
1552   }
1553
1554   png_infop info_ptr = png_create_info_struct(png_ptr);
1555   if (!info_ptr) {
1556     png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
1557     fclose(fp);
1558     return false;
1559   }
1560
1561   png_infop end_info = png_create_info_struct(png_ptr);
1562   if (!end_info) {
1563     png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
1564     fclose(fp);
1565     return false;
1566   }
1567
1568   if (setjmp(png_ptr->jmpbuf)) {
1569     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
1570     fclose(fp);
1571     return false;
1572   }
1573
1574   png_init_io(png_ptr, fp);
1575   png_set_sig_bytes(png_ptr, 8);
1576   png_read_info(png_ptr, info_ptr);
1577
1578   int width = png_get_image_width (png_ptr, info_ptr);
1579   int height = png_get_image_height (png_ptr, info_ptr);
1580   int bit_depth = png_get_bit_depth (png_ptr, info_ptr);
1581   int color_type = png_get_color_type (png_ptr, info_ptr);
1582
1583   if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8)
1584     png_set_expand(png_ptr);
1585
1586   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
1587     png_set_expand(png_ptr);
1588
1589   if (bit_depth < 8)
1590     png_set_packing(png_ptr);
1591
1592   if (color_type & PNG_COLOR_MASK_ALPHA)
1593     png_set_strip_alpha(png_ptr);
1594
1595   if (bit_depth == 16)
1596     png_set_swap(png_ptr); // convert to little-endian format
1597
1598   png_read_update_info(png_ptr, info_ptr); // update with transformations
1599   int rowbytes = png_get_rowbytes (png_ptr, info_ptr);
1600   bit_depth = png_get_bit_depth (png_ptr, info_ptr);
1601   color_type = png_get_color_type (png_ptr, info_ptr);
1602
1603   png_bytep* row_pointers = new png_bytep [height];
1604   int i;
1605   for (i = 0; i < height; i++)
1606     row_pointers[i] = new unsigned char [rowbytes];
1607
1608   png_read_image(png_ptr, row_pointers);
1609
1610   setArraySize (width, height);
1611   ImageFileArray v = getArray();
1612   for (int iy = 0; iy < height; iy++) {
1613     for (int ix = 0; ix < width; ix++) {
1614       double dV = 0;
1615       if (color_type == PNG_COLOR_TYPE_GRAY) {
1616         if (bit_depth == 8)
1617           dV = row_pointers[iy][ix] / 255.;
1618         else if (bit_depth == 16) {
1619           int iBase = ix * 2;
1620           dV = (row_pointers[iy][iBase] + (row_pointers[iy][iBase+1] << 8)) / 65536.;
1621         } else
1622           dV = 0;
1623       } else if (color_type == PNG_COLOR_TYPE_RGB) {
1624         if (bit_depth == 8) {
1625           int iBase = ix * 3;
1626           double dR = row_pointers[iy][iBase] / 255.;
1627           double dG = row_pointers[iy][iBase+1] / 255.;
1628           double dB = row_pointers[iy][iBase+2] / 255.;
1629           dV = colorToGrayscale (dR, dG, dB);
1630         } else
1631           dV = 0;
1632       }
1633       v[ix][height-iy-1] = dV;
1634     }
1635   }
1636
1637   png_read_end(png_ptr, end_info);
1638   png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
1639
1640   for (i = 0; i < height; i++)
1641     delete row_pointers[i];
1642   delete row_pointers;
1643
1644   fclose (fp);
1645   return true;
1646 }
1647 #endif
1648
1649 bool
1650 ImageFile::exportImage (const char* const pszFormat, const char* const pszFilename, int nxcell, int nycell, double densmin, double densmax)
1651 {
1652   int iFormatID = convertExportFormatNameToID (pszFormat);
1653
1654   if (iFormatID == EXPORT_FORMAT_PGM)
1655     return writeImagePGM (pszFilename, nxcell, nycell, densmin, densmax);
1656   else if (iFormatID == EXPORT_FORMAT_PGMASCII)
1657     return writeImagePGMASCII (pszFilename, nxcell, nycell, densmin, densmax);
1658   else if (iFormatID == EXPORT_FORMAT_TEXT)
1659     return writeImageText (pszFilename);
1660 #ifdef HAVE_PNG
1661   else if (iFormatID == EXPORT_FORMAT_PNG)
1662     return writeImagePNG (pszFilename, 8, nxcell, nycell, densmin, densmax);
1663   else if (iFormatID == EXPORT_FORMAT_PNG16)
1664     return writeImagePNG (pszFilename, 16, nxcell, nycell, densmin, densmax);
1665 #endif
1666 #ifdef HAVE_CTN_DICOM
1667   else if (iFormatID == EXPORT_FORMAT_DICOM) {
1668     DicomExporter dicomExport (this);
1669     bool bSuccess = dicomExport.writeFile (pszFilename);
1670     if (! bSuccess)
1671       sys_error (ERR_SEVERE, dicomExport.failMessage().c_str());
1672     return bSuccess;
1673   }
1674 #endif
1675   else if (iFormatID == EXPORT_FORMAT_RAW)
1676          return writeImageRaw(pszFilename, nxcell, nycell);
1677
1678
1679   sys_error (ERR_SEVERE, "Invalid format %s [ImageFile::exportImage]", pszFormat);
1680   return false;
1681 }
1682
1683
1684 bool
1685 ImageFile::writeImagePGM (const char* const outfile, int nxcell, int nycell, double densmin, double densmax)
1686 {
1687   FILE *fp;
1688   int nx = m_nx;
1689   int ny = m_ny;
1690   ImageFileArray v = getArray();
1691
1692   unsigned char* rowp = new unsigned char [nx * nxcell];
1693
1694   if ((fp = fopen (outfile, "wb")) == NULL)
1695     return false;
1696
1697   fprintf(fp, "P5\n");
1698   fprintf(fp, "%d %d\n", nx, ny);
1699   fprintf(fp, "255\n");
1700
1701   for (int irow = ny - 1; irow >= 0; irow--) {
1702     for (int icol = 0; icol < nx; icol++) {
1703       int pos = icol * nxcell;
1704       double dens = (v[icol][irow] - densmin) / (densmax - densmin);
1705       dens = clamp (dens, 0., 1.);
1706       for (int p = pos; p < pos + nxcell; p++) {
1707         rowp[p] = static_cast<unsigned int> (dens * 255.);
1708       }
1709     }
1710     for (int ir = 0; ir < nycell; ir++) {
1711       for (int ic = 0; ic < nx * nxcell; ic++)
1712         fputc( rowp[ic], fp );
1713     }
1714   }
1715
1716   delete rowp;
1717   fclose(fp);
1718
1719   return true;
1720 }
1721
1722 bool
1723 ImageFile::writeImagePGMASCII (const char* const outfile, int nxcell, int nycell, double densmin, double densmax)
1724 {
1725   FILE *fp;
1726   int nx = m_nx;
1727   int ny = m_ny;
1728   ImageFileArray v = getArray();
1729
1730   unsigned char* rowp = new unsigned char [nx * nxcell];
1731
1732   if ((fp = fopen (outfile, "wb")) == NULL)
1733     return false;
1734
1735   fprintf(fp, "P2\n");
1736   fprintf(fp, "%d %d\n", nx, ny);
1737   fprintf(fp, "255\n");
1738
1739   for (int irow = ny - 1; irow >= 0; irow--) {
1740     for (int icol = 0; icol < nx; icol++) {
1741       int pos = icol * nxcell;
1742       double dens = (v[icol][irow] - densmin) / (densmax - densmin);
1743       dens = clamp (dens, 0., 1.);
1744       for (int p = pos; p < pos + nxcell; p++) {
1745         rowp[p] = static_cast<unsigned int> (dens * 255.);
1746       }
1747     }
1748     for (int ir = 0; ir < nycell; ir++) {
1749       for (int ic = 0; ic < nx * nxcell; ic++)
1750         fprintf(fp, "%d ", rowp[ic]);
1751       fprintf(fp, "\n");
1752     }
1753   }
1754
1755   delete rowp;
1756   fclose(fp);
1757
1758   return true;
1759 }
1760
1761 bool
1762 ImageFile::writeImageText (const char* const outfile)
1763 {
1764   FILE *fp;
1765   int nx = m_nx;
1766   int ny = m_ny;
1767   ImageFileArray v = getArray();
1768   ImageFileArray vImag = getImaginaryArray();
1769
1770   if ((fp = fopen (outfile, "w")) == NULL)
1771     return false;
1772
1773   for (int irow = ny - 1; irow >= 0; irow--) {
1774     for (int icol = 0; icol < nx; icol++) {
1775       if (isComplex()) {
1776         if (vImag[icol][irow] >= 0)
1777           fprintf (fp, "%.9g+%.9gi ", v[icol][irow], vImag[icol][irow]);
1778         else
1779           fprintf (fp, "%.9g-%.9gi ", v[icol][irow], -vImag[icol][irow]);
1780       } else
1781         fprintf (fp, "%12.8g ", v[icol][irow]);
1782     }
1783     fprintf(fp, "\n");
1784   }
1785
1786   fclose(fp);
1787
1788   return true;
1789 }
1790
1791
1792 #ifdef HAVE_PNG
1793 bool
1794 ImageFile::writeImagePNG (const char* const outfile, int bitdepth, int nxcell, int nycell, double densmin, double densmax)
1795 {
1796   double max_out_level = (1 << bitdepth) - 1;
1797   int nx = m_nx;
1798   int ny = m_ny;
1799   ImageFileArray v = getArray();
1800
1801   unsigned char* rowp = new unsigned char [nx * nxcell * (bitdepth / 8)];
1802
1803   FILE *fp = fopen (outfile, "wb");
1804   if (! fp)
1805     return false;
1806
1807   png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1808   if (! png_ptr)
1809     return false;
1810
1811   png_infop info_ptr = png_create_info_struct (png_ptr);
1812   if (! info_ptr) {
1813     png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
1814     fclose (fp);
1815     return false;
1816   }
1817
1818   if (setjmp (png_ptr->jmpbuf)) {
1819     png_destroy_write_struct (&png_ptr, &info_ptr);
1820     fclose (fp);
1821     return false;
1822   }
1823
1824   png_init_io(png_ptr, fp);
1825
1826   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);
1827
1828   png_write_info(png_ptr, info_ptr);
1829   for (int irow = ny - 1; irow >= 0; irow--) {
1830     png_bytep row_pointer = rowp;
1831
1832     for (int icol = 0; icol < nx; icol++) {
1833       int pos = icol * nxcell;
1834       double dens = (v[icol][irow] - densmin) / (densmax - densmin);
1835       dens = clamp (dens, 0., 1.);
1836       unsigned int outval = static_cast<unsigned int> (dens * max_out_level);
1837
1838       for (int p = pos; p < pos + nxcell; p++) {
1839         if (bitdepth == 8)
1840           rowp[p] = outval;
1841         else {
1842           int rowpos = p * 2;
1843           rowp[rowpos+1] = (outval >> 8) & 0xFF;
1844           rowp[rowpos] = (outval & 0xFF);
1845         }
1846       }
1847     }
1848     for (int ir = 0; ir < nycell; ir++)
1849       png_write_rows (png_ptr, &row_pointer, 1);
1850   }
1851
1852   png_write_end (png_ptr, info_ptr);
1853   png_destroy_write_struct (&png_ptr, &info_ptr);
1854   delete rowp;
1855
1856   fclose(fp);
1857
1858   return true;
1859 }
1860 #endif
1861
1862 #ifdef HAVE_GD
1863 #include "gd.h"
1864 static const int N_GRAYSCALE=256;
1865
1866 bool
1867 ImageFile::writeImageGIF (const char* const outfile, int nxcell, int nycell, double densmin, double densmax)
1868 {
1869   int gs_indices[N_GRAYSCALE];
1870   int nx = m_nx;
1871   int ny = m_ny;
1872   ImageFileArray v = getArray();
1873
1874   unsigned char* rowp = new unsigned char [nx * nxcell];
1875
1876   gdImagePtr gif = gdImageCreate(nx * nxcell, ny * nycell);
1877   for (int i = 0; i < N_GRAYSCALE; i++)
1878     gs_indices[i] = gdImageColorAllocate(gif, i, i, i);
1879
1880   int lastrow = ny * nycell - 1;
1881   for (int irow = 0; irow < ny; irow++) {
1882     int rpos = irow * nycell;
1883     for (int ir = rpos; ir < rpos + nycell; ir++) {
1884       for (int icol = 0; icol < nx; icol++) {
1885         int cpos = icol * nxcell;
1886         double dens = (v[icol][irow] - densmin) / (densmax - densmin);
1887         dens = clamp(dens, 0., 1.);
1888         for (int ic = cpos; ic < cpos + nxcell; ic++) {
1889           rowp[ic] = (unsigned int) (dens * (double) (N_GRAYSCALE - 1));
1890           gdImageSetPixel(gif, ic, lastrow - ir, gs_indices[rowp[ic]]);
1891         }
1892       }
1893     }
1894   }
1895
1896   FILE *out;
1897   if ((out = fopen (outfile,"w")) == NULL) {
1898     sys_error(ERR_SEVERE, "Error opening output file %s for writing", outfile);
1899     return false;
1900   }
1901   gdImageGif(gif,out);
1902   fclose(out);
1903   gdImageDestroy(gif);
1904
1905   delete rowp;
1906
1907   return true;
1908 }
1909 #endif
1910
1911 bool
1912 ImageFile::writeImageRaw (const char* const outfile, int nxcell, int nycell)
1913 {
1914   FILE *fp;
1915   int nx = m_nx;
1916   int ny = m_ny;
1917   ImageFileArray v = getArray();
1918
1919   if ((fp = fopen (outfile, "wb")) == NULL)
1920     return false;
1921
1922   for (int irow = ny - 1; irow >= 0; irow--) {
1923     for (int icol = 0; icol < nx; icol++) {
1924       float dens = v[icol][irow];
1925      fwrite(&dens, sizeof(float), 1, fp);
1926     }
1927   }
1928
1929   fclose(fp);
1930   return true;
1931 }
1932
1933