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