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