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