+Projections::printScanInfo (std::ostringstream& os) const
+{
+ os << "Number of detectors: " << m_nDet << "\n";
+ os << "Number of views: " << m_nView<< "\n";
+ os << "Description: " << m_remark.c_str()<< "\n";
+ os << "Geometry: " << Scanner::convertGeometryIDToName (m_geometry)<< "\n";
+ os << "Focal Length: " << m_dFocalLength<< "\n";
+ os << "Source Detector Length: " << m_dSourceDetectorLength << "\n";
+ os << "View Diameter: " << m_dViewDiameter<< "\n";
+ os << "Fan Beam Angle: " << convertRadiansToDegrees(m_dFanBeamAngle) << "\n";
+ os << "detStart: " << m_detStart<< "\n";
+ os << "detInc: " << m_detInc<< "\n";
+ os << "rotStart: " << m_rotStart<< "\n";
+ os << "rotInc: " << m_rotInc<< "\n";
+}
+
+
+bool
+Projections::convertPolar (ImageFile& rIF, int iInterpolationID)
+{
+ unsigned int nx = rIF.nx();
+ unsigned int ny = rIF.ny();
+ ImageFileArray v = rIF.getArray();
+ ImageFileArray vImag = rIF.getImaginaryArray();
+
+ if (! v || nx == 0 || ny == 0)
+ return false;
+
+ Projections* pProj = this;
+ if (m_geometry == Scanner::GEOMETRY_EQUIANGULAR || m_geometry == Scanner::GEOMETRY_EQUILINEAR)
+ pProj = interpolateToParallel();
+
+ Array2d<double> adView (nx, ny);
+ Array2d<double> adDet (nx, ny);
+ double** ppdView = adView.getArray();
+ double** ppdDet = adDet.getArray();
+
+ std::complex<double>** ppcDetValue = new std::complex<double>* [pProj->m_nView];
+ int iView;
+ for (iView = 0; iView < pProj->m_nView; iView++) {
+ ppcDetValue[iView] = new std::complex<double> [pProj->m_nDet];
+ DetectorValue* detval = pProj->getDetectorArray (iView).detValues();
+ for (int iDet = 0; iDet < pProj->m_nDet; iDet++)
+ ppcDetValue[iView][iDet] = std::complex<double>(detval[iDet], 0);
+ }
+
+ pProj->calcArrayPolarCoordinates (nx, ny, ppdView, ppdDet, pProj->m_nDet, 1., pProj->m_detInc);
+
+ pProj->interpolatePolar (v, vImag, nx, ny, ppcDetValue, ppdView, ppdDet, pProj->m_nView, pProj->m_nDet,
+ pProj->m_nDet, iInterpolationID);
+
+ for (iView = 0; iView < pProj->m_nView; iView++)
+ delete [] ppcDetValue[iView];
+ delete [] ppcDetValue;
+
+ if (m_geometry == Scanner::GEOMETRY_EQUIANGULAR || m_geometry == Scanner::GEOMETRY_EQUILINEAR)
+ delete pProj;
+
+ return true;
+}
+
+
+bool
+Projections::convertFFTPolar (ImageFile& rIF, int iInterpolationID, int iZeropad)
+{
+#ifndef HAVE_FFTW
+ rIF.arrayDataClear();
+ return false;
+#else
+ unsigned int nx = rIF.nx();
+ unsigned int ny = rIF.ny();
+ ImageFileArray v = rIF.getArray();
+ if (! rIF.isComplex())
+ rIF.convertRealToComplex();
+ ImageFileArray vImag = rIF.getImaginaryArray();
+
+ if (! v || nx == 0 || ny == 0)
+ return false;
+
+ Projections* pProj = this;
+ if (m_geometry == Scanner::GEOMETRY_EQUIANGULAR || m_geometry == Scanner::GEOMETRY_EQUILINEAR)
+ pProj = interpolateToParallel();
+
+ int iInterpDet = static_cast<int>(static_cast<double>(sqrt(nx*nx+ny*ny)));
+ int iNumInterpDetWithZeros = ProcessSignal::addZeropadFactor (iInterpDet, iZeropad);
+ double dProjScale = iInterpDet / (pProj->viewDiameter() * 0.5);
+ double dZeropadRatio = static_cast<double>(iNumInterpDetWithZeros) / static_cast<double>(iInterpDet);
+
+ fftw_plan plan = fftw_create_plan (iNumInterpDetWithZeros, FFTW_FORWARD, FFTW_IN_PLACE | FFTW_ESTIMATE | FFTW_USE_WISDOM);
+
+ fftw_complex* pcIn = new fftw_complex [iNumInterpDetWithZeros];
+ std::complex<double>** ppcDetValue = new std::complex<double>* [pProj->m_nView];
+ //double dInterpScale = (pProj->m_nDet-1) / static_cast<double>(iInterpDet-1);
+ double dInterpScale = pProj->m_nDet / static_cast<double>(iInterpDet);
+
+ double dFFTScale = 1. / static_cast<double>(iInterpDet * iInterpDet);
+ int iMidPoint = iInterpDet / 2;
+ double dMidPoint = static_cast<double>(iInterpDet) / 2.;
+ int iZerosAdded = iNumInterpDetWithZeros - iInterpDet;
+
+ // For each view, interpolate, shift to center at origin, and FFT
+ for (int iView = 0; iView < m_nView; iView++) {
+ DetectorValue* detval = pProj->getDetectorArray(iView).detValues();
+ LinearInterpolator<DetectorValue> projInterp (detval, pProj->m_nDet);
+ for (int iDet = 0; iDet < iInterpDet; iDet++) {
+ double dInterpPos = (m_nDet / 2.) + (iDet - dMidPoint) * dInterpScale;
+ pcIn[iDet].re = projInterp.interpolate (dInterpPos) * dProjScale;
+ pcIn[iDet].im = 0;
+ }
+
+ Fourier::shuffleFourierToNaturalOrder (pcIn, iInterpDet);
+ if (iZerosAdded > 0) {
+ for (int iDet1 = iInterpDet -1; iDet1 >= iMidPoint; iDet1--)
+ pcIn[iDet1+iZerosAdded] = pcIn[iDet1];
+ for (int iDet2 = iMidPoint; iDet2 < iMidPoint + iZerosAdded; iDet2++)
+ pcIn[iDet2].re = pcIn[iDet2].im = 0;
+ }
+
+ fftw_one (plan, pcIn, NULL);
+
+ ppcDetValue[iView] = new std::complex<double> [iNumInterpDetWithZeros];
+ for (int iD = 0; iD < iNumInterpDetWithZeros; iD++) {
+ ppcDetValue[iView][iD] = std::complex<double> (pcIn[iD].re * dFFTScale, pcIn[iD].im * dFFTScale);
+ }
+
+ Fourier::shuffleFourierToNaturalOrder (ppcDetValue[iView], iNumInterpDetWithZeros);
+ }
+ delete [] pcIn;
+
+ fftw_destroy_plan (plan);
+
+ Array2d<double> adView (nx, ny);
+ Array2d<double> adDet (nx, ny);
+ double** ppdView = adView.getArray();
+ double** ppdDet = adDet.getArray();
+ pProj->calcArrayPolarCoordinates (nx, ny, ppdView, ppdDet, iNumInterpDetWithZeros, dZeropadRatio,
+ pProj->m_detInc * dInterpScale);
+
+ pProj->interpolatePolar (v, vImag, nx, ny, ppcDetValue, ppdView, ppdDet, pProj->m_nView, pProj->m_nDet,
+ iNumInterpDetWithZeros, iInterpolationID);
+
+ if (m_geometry == Scanner::GEOMETRY_EQUIANGULAR || m_geometry == Scanner::GEOMETRY_EQUILINEAR)
+ delete pProj;
+
+ for (int i = 0; i < m_nView; i++)
+ delete [] ppcDetValue[i];
+ delete [] ppcDetValue;
+
+ return true;
+#endif
+}
+
+
+void
+Projections::calcArrayPolarCoordinates (unsigned int nx, unsigned int ny, double** ppdView, double** ppdDet,
+ int iNumDetWithZeros, double dZeropadRatio, double dDetInc)
+{
+ double dLength = viewDiameter();
+ double xMin = -dLength / 2;
+ double xMax = xMin + dLength;
+ double yMin = -dLength / 2;
+ double yMax = yMin + dLength;
+ double xCent = (xMin + xMax) / 2;
+ double yCent = (yMin + yMax) / 2;
+
+ xMin = (xMin - xCent) * dZeropadRatio + xCent;
+ xMax = (xMax - xCent) * dZeropadRatio + xCent;
+ yMin = (yMin - yCent) * dZeropadRatio + yCent;
+ yMax = (yMax - yCent) * dZeropadRatio + yCent;
+
+ double xInc = (xMax - xMin) / nx; // size of cells
+ double yInc = (yMax - yMin) / ny;
+
+ double dDetCenter = (iNumDetWithZeros - 1) / 2.; // index refering to L=0 projection
+ // +1 is correct for frequency data, ndet-1 is correct for projections
+ // if (isEven (iNumDetWithZeros))
+ // dDetCenter = (iNumDetWithZeros + 0) / 2;
+
+ // Calculates polar coordinates (view#, det#) for each point on phantom grid
+ double x = xMin + xInc / 2; // Rectang coords of center of pixel
+ for (unsigned int ix = 0; ix < nx; x += xInc, ix++) {
+ double y = yMin + yInc / 2;
+ for (unsigned int iy = 0; iy < ny; y += yInc, iy++) {
+ double r = ::sqrt (x * x + y * y);
+ double phi = atan2 (y, x);
+
+ if (phi <= -m_rotInc / 2)
+ phi += TWOPI;
+ if (phi >= PI - (m_rotInc / 2)) {
+ phi -= PI;
+ r = -r;
+ }
+
+ ppdView[ix][iy] = (phi - m_rotStart) / m_rotInc;
+ ppdDet[ix][iy] = (r / dDetInc) + dDetCenter;
+ }
+ }
+}
+
+void
+Projections::interpolatePolar (ImageFileArray& v, ImageFileArray& vImag,
+ unsigned int nx, unsigned int ny, std::complex<double>** ppcDetValue, double** ppdView,
+ double** ppdDet, unsigned int nView, unsigned int nDet, unsigned int nDetWithZeros, int iInterpolationID)
+{
+ typedef std::complex<double> complexValue;
+
+ BilinearPolarInterpolator<complexValue>* pBilinear = NULL;
+ BicubicPolyInterpolator<complexValue>* pBicubic = NULL;
+ if (iInterpolationID == POLAR_INTERP_BILINEAR)
+ pBilinear = new BilinearPolarInterpolator<complexValue> (ppcDetValue, nView, nDetWithZeros);
+ else if (iInterpolationID == POLAR_INTERP_BICUBIC)
+ pBicubic = new BicubicPolyInterpolator<complexValue> (ppcDetValue, nView, nDetWithZeros);
+
+ for (unsigned int ix = 0; ix < ny; ix++) {
+ for (unsigned int iy = 0; iy < ny; iy++) {
+ if (iInterpolationID == POLAR_INTERP_NEAREST) {
+ unsigned int iView = nearest<int> (ppdView[ix][iy]);
+ unsigned int iDet = nearest<int> (ppdDet[ix][iy]);
+ if (iView == nView)
+ iView = 0;
+ if (iDet >= 0 && iDet < nDetWithZeros && iView >= 0 && iView < nView) {
+ v[ix][iy] = ppcDetValue[iView][iDet].real();
+ if (vImag)
+ vImag[ix][iy] = ppcDetValue[iView][iDet].imag();
+ } else {
+ v[ix][iy] = 0;
+ if (vImag)
+ vImag[ix][iy] = 0;
+ }
+
+ } else if (iInterpolationID == POLAR_INTERP_BILINEAR) {
+ std::complex<double> vInterp = pBilinear->interpolate (ppdView[ix][iy], ppdDet[ix][iy]);
+ v[ix][iy] = vInterp.real();
+ if (vImag)
+ vImag[ix][iy] = vInterp.imag();
+ } else if (iInterpolationID == POLAR_INTERP_BICUBIC) {
+ std::complex<double> vInterp = pBicubic->interpolate (ppdView[ix][iy], ppdDet[ix][iy]);
+ v[ix][iy] = vInterp.real();
+ if (vImag)
+ vImag[ix][iy] = vInterp.imag();
+ }
+ }
+ }
+}
+
+bool
+Projections::initFromSomatomAR_STAR (int iNViews, int iNDets, unsigned char* pData, unsigned long lDataLength)