File indexing completed on 2024-05-12 15:23:43

0001 /*
0002     SPDX-FileCopyrightText: 2017 Bob Majewski <cygnus257@yahoo.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "imageautoguiding.h"
0008 
0009 #include <qglobal.h>
0010 
0011 #include <cmath>
0012 
0013 #define SWAP(a, b) \
0014     tempr = (a);   \
0015     (a)   = (b);   \
0016     (b)   = tempr
0017 #define NR_END   1
0018 #define FREE_ARG char *
0019 
0020 #define TWOPI   6.28318530717959
0021 #define FFITMAX 0.05
0022 
0023 //void ImageAutoGuiding1(float *ref,float *im,int n,float *xshift,float *yshift);
0024 
0025 float ***f3tensorSP(long nrl, long nrh, long ncl, long nch, long ndl, long ndh);
0026 void free_f3tensorSP(float ***t, long nrl, long nrh, long ncl, long nch, long ndl, long ndh);
0027 
0028 float **matrixSP(long nrl, long nrh, long ncl, long nch);
0029 
0030 void free_matrixSP(float **m, long nrl, long nrh, long ncl, long nch);
0031 void nrerrorNR(void);
0032 
0033 void fournNR(float data[], unsigned long nn[], long ndim, long isign);
0034 
0035 void rlft3NR(float ***data, float **speq, unsigned long nn1, unsigned long nn2, unsigned long nn3, long isign);
0036 
0037 void ShiftEST(float ***testimage, float ***refimage, int n, float *xshift, float *yshift, int k);
0038 
0039 namespace ImageAutoGuiding
0040 {
0041 void ImageAutoGuiding1(float *ref, float *im, int n, float *xshift, float *yshift)
0042 {
0043     float ***RefImage, ***TestImage;
0044     int i, j, k;
0045     float x, y;
0046 
0047     /* Allocate memory */
0048 
0049     RefImage  = f3tensorSP(1, 1, 1, n, 1, n);
0050     TestImage = f3tensorSP(1, 1, 1, n, 1, n);
0051 
0052     /* Load Data */
0053 
0054     k = 0;
0055 
0056     for (j = 1; j <= n; ++j)
0057     {
0058         for (i = 1; i <= n; ++i)
0059         {
0060             RefImage[1][j][i]  = ref[k];
0061             TestImage[1][j][i] = im[k];
0062 
0063             k += 1;
0064         }
0065     }
0066 
0067     /* Calculate Image Shifts  */
0068 
0069     ShiftEST(TestImage, RefImage, n, &x, &y, 1);
0070 
0071     *xshift = x;
0072     *yshift = y;
0073 
0074     /* free memory */
0075 
0076     free_f3tensorSP(RefImage, 1, 1, 1, n, 1, n);
0077     free_f3tensorSP(TestImage, 1, 1, 1, n, 1, n);
0078 }
0079 }
0080 
0081 // Calculates Image Shifts
0082 
0083 void ShiftEST(float ***testimage, float ***refimage, int n, float *xshift, float *yshift, int k)
0084 {
0085     int ix, iy, nh, nhplusone;
0086     double deltax, deltay, fx2sum, fy2sum, phifxsum, phifysum, fxfysum;
0087     double fx, fy, ff, fn, re, im, testre, testim, rev, imv, phi;
0088     double power, dem, f2, f2limit;
0089     float **speq;
0090 
0091     f2limit = FFITMAX * FFITMAX;
0092 
0093     speq = matrixSP(1, 1, 1, 2 * n);
0094 
0095     nh        = n / 2;
0096     nhplusone = nh + 1;
0097 
0098     fn = ((float)n);
0099     ff = 1.0 / fn;
0100 
0101     /* FFT of Reference */
0102 
0103     for (ix = 1; ix <= 2 * n; ++ix)
0104     {
0105         speq[1][ix] = 0.0;
0106     }
0107 
0108     rlft3NR(refimage, speq, 1, n, n, 1);
0109 
0110     /* FFT of Test Image */
0111 
0112     for (ix = 1; ix <= 2 * n; ++ix)
0113     {
0114         speq[1][ix] = 0.0;
0115     }
0116 
0117     rlft3NR(testimage, speq, 1, n, n, 1);
0118 
0119     /* Solving for slopes  */
0120 
0121     fx2sum = 0.0;
0122     fy2sum = 0.0;
0123 
0124     phifxsum = 0.0;
0125     phifysum = 0.0;
0126 
0127     fxfysum = 0.0;
0128 
0129     for (ix = 1; ix <= n; ++ix)
0130     {
0131         if (ix <= nhplusone)
0132         {
0133             fx = ff * ((float)(ix - 1));
0134         }
0135         else
0136         {
0137             fx = -ff * ((float)(n + 1 - ix));
0138         }
0139 
0140         for (iy = 1; iy <= nh; ++iy)
0141         {
0142             fy = ff * ((float)(iy - 1));
0143 
0144             f2 = fx * fx + fy * fy;
0145 
0146             /* Limit to Low Spatial Frequencies */
0147 
0148             if (f2 < f2limit)
0149             {
0150                 /* Real part reference image */
0151 
0152                 re = refimage[k][ix][2 * iy - 1];
0153 
0154                 /* Imaginary part reference image */
0155 
0156                 im = refimage[k][ix][2 * iy];
0157 
0158                 power = re * re + im * im;
0159 
0160                 /* Real part test image */
0161 
0162                 testre = testimage[k][ix][2 * iy - 1];
0163 
0164                 /* Imaginary part image */
0165 
0166                 testim = testimage[k][ix][2 * iy];
0167 
0168                 rev = re * testre + im * testim;
0169                 imv = re * testim - im * testre;
0170 
0171                 /* Find Phase */
0172 
0173                 phi = atan2(imv, rev);
0174 
0175                 fx2sum += power * fx * fx;
0176                 fy2sum += power * fy * fy;
0177 
0178                 phifxsum += power * fx * phi;
0179                 phifysum += power * fy * phi;
0180 
0181                 fxfysum += power * fx * fy;
0182             }
0183         }
0184     }
0185 
0186     /* calculate subpixel shift */
0187 
0188     dem = fx2sum * fy2sum - fxfysum * fxfysum;
0189 
0190     deltax = (phifxsum * fy2sum - fxfysum * phifysum) / (dem * TWOPI);
0191     deltay = (phifysum * fx2sum - fxfysum * phifxsum) / (dem * TWOPI);
0192 
0193     free_matrixSP(speq, 1, 1, 1, 2 * n);
0194 
0195     /* You can change the shift mapping here */
0196 
0197     *xshift = deltax;
0198     *yshift = deltay;
0199 }
0200 
0201 // 2 and 3 Dimensional FFT Routine for Real Data
0202 // Numerical Recipes in C Second Edition
0203 // The Art of Scientific Computing
0204 // 1999
0205 
0206 void rlft3NR(float ***data, float **speq, unsigned long nn1, unsigned long nn2, unsigned long nn3, long isign)
0207 {
0208     void fournNR(float data[], unsigned long nn[], long ndim, long isign);
0209     void nrerror();
0210     unsigned long i1, i2, i3, j1, j2, j3, nn[4], ii3;
0211     double theta, wpi, wpr, wtemp;
0212     float c1, c2, h1r, h1i, h2r, h2i;
0213     float wi, wr;
0214 
0215     if ((unsigned long)(1 + &data[nn1][nn2][nn3] - &data[1][1][1]) != nn1 * nn2 * nn3)
0216         nrerrorNR();
0217     c1    = 0.5;
0218     c2    = -0.5 * isign;
0219     theta = isign * (6.28318530717959 / nn3);
0220     wtemp = sin(0.5 * theta);
0221     wpr   = -2.0 * wtemp * wtemp;
0222     wpi   = sin(theta);
0223     nn[1] = nn1;
0224     nn[2] = nn2;
0225     nn[3] = nn3 >> 1;
0226     if (isign == 1)
0227     {
0228         fournNR(&data[1][1][1] - 1, nn, 3, isign);
0229         for (i1 = 1; i1 <= nn1; i1++)
0230             for (i2 = 1, j2 = 0; i2 <= nn2; i2++)
0231             {
0232                 speq[i1][++j2] = data[i1][i2][1];
0233                 speq[i1][++j2] = data[i1][i2][2];
0234             }
0235     }
0236     for (i1 = 1; i1 <= nn1; i1++)
0237     {
0238         j1 = (i1 != 1 ? nn1 - i1 + 2 : 1);
0239         wr = 1.0;
0240         wi = 0.0;
0241         for (ii3 = 1, i3 = 1; i3 <= (nn3 >> 2) + 1; i3++, ii3 += 2)
0242         {
0243             for (i2 = 1; i2 <= nn2; i2++)
0244             {
0245                 if (i3 == 1)
0246                 {
0247                     j2               = (i2 != 1 ? ((nn2 - i2) << 1) + 3 : 1);
0248                     h1r              = c1 * (data[i1][i2][1] + speq[j1][j2]);
0249                     h1i              = c1 * (data[i1][i2][2] - speq[j1][j2 + 1]);
0250                     h2i              = c2 * (data[i1][i2][1] - speq[j1][j2]);
0251                     h2r              = -c2 * (data[i1][i2][2] + speq[j1][j2 + 1]);
0252                     data[i1][i2][1]  = h1r + h2r;
0253                     data[i1][i2][2]  = h1i + h2i;
0254                     speq[j1][j2]     = h1r - h2r;
0255                     speq[j1][j2 + 1] = h2i - h1i;
0256                 }
0257                 else
0258                 {
0259                     j2                    = (i2 != 1 ? nn2 - i2 + 2 : 1);
0260                     j3                    = nn3 + 3 - (i3 << 1);
0261                     h1r                   = c1 * (data[i1][i2][ii3] + data[j1][j2][j3]);
0262                     h1i                   = c1 * (data[i1][i2][ii3 + 1] - data[j1][j2][j3 + 1]);
0263                     h2i                   = c2 * (data[i1][i2][ii3] - data[j1][j2][j3]);
0264                     h2r                   = -c2 * (data[i1][i2][ii3 + 1] + data[j1][j2][j3 + 1]);
0265                     data[i1][i2][ii3]     = h1r + wr * h2r - wi * h2i;
0266                     data[i1][i2][ii3 + 1] = h1i + wr * h2i + wi * h2r;
0267                     data[j1][j2][j3]      = h1r - wr * h2r + wi * h2i;
0268                     data[j1][j2][j3 + 1]  = -h1i + wr * h2i + wi * h2r;
0269                 }
0270             }
0271             wr = (wtemp = wr) * wpr - wi * wpi + wr;
0272             wi = wi * wpr + wtemp * wpi + wi;
0273         }
0274     }
0275     if (isign == -1)
0276         fournNR(&data[1][1][1] - 1, nn, 3, isign);
0277 }
0278 
0279 // Multi-Dimensional FFT Routine for Complex Data
0280 // Numerical Recipes in C Second Edition
0281 // The Art of Scientific Computing
0282 // 1999
0283 // Used in rlft3
0284 
0285 void fournNR(float data[], unsigned long nn[], long ndim, long isign)
0286 {
0287     long idim;
0288     unsigned long i1, i2rev, i3rev, ip1, ip2, ip3, ifp1, ifp2;
0289     unsigned long i2, i3;
0290     unsigned long ibit, k1 = 0, k2, n, nprev, nrem, ntot;
0291     float wi, wr, tempi, tempr;
0292     double theta, wpi, wpr, wtemp;
0293 
0294     for (ntot = 1, idim = 1; idim <= ndim; idim++)
0295         ntot *= nn[idim];
0296     nprev = 1;
0297     for (idim = ndim; idim >= 1; idim--)
0298     {
0299         n     = nn[idim];
0300         nrem  = ntot / (n * nprev);
0301         ip1   = nprev << 1;
0302         ip2   = ip1 * n;
0303         ip3   = ip2 * nrem;
0304         i2rev = 1;
0305         for (i2 = 1; i2 <= ip2; i2 += ip1)
0306         {
0307             if (i2 < i2rev)
0308             {
0309                 for (i1 = i2; i1 <= i2 + ip1 - 2; i1 += 2)
0310                 {
0311                     for (i3 = i1; i3 <= ip3; i3 += ip2)
0312                     {
0313                         i3rev = i2rev + i3 - i2;
0314                         SWAP(data[i3], data[i3rev]);
0315                         SWAP(data[i3 + 1], data[i3rev + 1]);
0316                     }
0317                 }
0318             }
0319             ibit = ip2 >> 1;
0320             while (ibit >= ip1 && i2rev > ibit)
0321             {
0322                 i2rev -= ibit;
0323                 ibit >>= 1;
0324             }
0325             i2rev += ibit;
0326         }
0327         ifp1 = ip1;
0328         while (ifp1 < ip2)
0329         {
0330             ifp2  = ifp1 << 1;
0331             theta = isign * 6.28318530717959 / (ifp2 / ip1);
0332             wtemp = sin(0.5 * theta);
0333             wpr   = -2.0 * wtemp * wtemp;
0334             wpi   = sin(theta);
0335             wr    = 1.0;
0336             wi    = 0.0;
0337             for (i3 = 1; i3 <= ifp1; i3 += ip1)
0338             {
0339                 for (i1 = i3; i1 <= i3 + ip1 - 2; i1 += 2)
0340                 {
0341                     for (i2 = i1; i2 <= ip3; i2 += ifp2)
0342                     {
0343                         k1           = i2;
0344                         k2           = k1 + ifp1;
0345                         tempr        = (double)wr * data[k2] - (double)wi * data[k2 + 1];
0346                         tempi        = (double)wr * data[k2 + 1] + (double)wi * data[k2];
0347                         data[k2]     = data[k1] - tempr;
0348                         data[k2 + 1] = data[k1 + 1] - tempi;
0349                         data[k1] += tempr;
0350                         data[k1 + 1] += tempi;
0351                     }
0352                 }
0353                 wr = (wtemp = wr) * wpr - wi * wpi + wr;
0354                 wi = wi * wpr + wtemp * wpi + wi;
0355             }
0356             ifp1 = ifp2;
0357         }
0358         nprev *= n;
0359     }
0360 }
0361 
0362 void nrerrorNR(void)
0363 {
0364 }
0365 
0366 // Numerical Recipes memory allocation routines
0367 // One based arrays
0368 
0369 float **matrixSP(long nrl, long nrh, long ncl, long nch)
0370 /* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */
0371 {
0372     long i, nrow = nrh - nrl + 1, ncol = nch - ncl + 1;
0373     float **m;
0374 
0375     /* allocate pointers to rows */
0376     m = (float **)malloc((size_t)((nrow + NR_END) * sizeof(float *)));
0377     if (!m)
0378         nrerrorNR();
0379     m += NR_END;
0380     m -= nrl;
0381 
0382     /* allocate rows and set pointers to them */
0383     m[nrl] = (float *)malloc((size_t)((nrow * ncol + NR_END) * sizeof(float)));
0384     if (!m[nrl])
0385         nrerrorNR();
0386     m[nrl] += NR_END;
0387     m[nrl] -= ncl;
0388 
0389     for (i = nrl + 1; i <= nrh; i++)
0390         m[i] = m[i - 1] + ncol;
0391 
0392     /* return pointer to array of pointers to rows */
0393     return m;
0394 }
0395 
0396 float ***f3tensorSP(long nrl, long nrh, long ncl, long nch, long ndl, long ndh)
0397 /* allocate a float 3tensor with range t[nrl..nrh][ncl..nch][ndl..ndh] */
0398 {
0399     long i, j, nrow = nrh - nrl + 1, ncol = nch - ncl + 1, ndep = ndh - ndl + 1;
0400     float ***t;
0401 
0402     /* allocate pointers to pointers to rows */
0403     t = (float ***)malloc((size_t)((nrow + NR_END) * sizeof(float **)));
0404     if (!t)
0405         nrerrorNR();
0406     t += NR_END;
0407     t -= nrl;
0408 
0409     /* allocate pointers to rows and set pointers to them */
0410     t[nrl] = (float **)malloc((size_t)((nrow * ncol + NR_END) * sizeof(float *)));
0411     if (!t[nrl])
0412         nrerrorNR();
0413     t[nrl] += NR_END;
0414     t[nrl] -= ncl;
0415 
0416     /* allocate rows and set pointers to them */
0417     t[nrl][ncl] = (float *)malloc((size_t)((nrow * ncol * ndep + NR_END) * sizeof(float)));
0418     if (!t[nrl][ncl])
0419         nrerrorNR();
0420     t[nrl][ncl] += NR_END;
0421     t[nrl][ncl] -= ndl;
0422 
0423     for (j = ncl + 1; j <= nch; j++)
0424         t[nrl][j] = t[nrl][j - 1] + ndep;
0425     for (i = nrl + 1; i <= nrh; i++)
0426     {
0427         t[i]      = t[i - 1] + ncol;
0428         t[i][ncl] = t[i - 1][ncl] + ncol * ndep;
0429         for (j = ncl + 1; j <= nch; j++)
0430             t[i][j] = t[i][j - 1] + ndep;
0431     }
0432 
0433     /* return pointer to array of pointers to rows */
0434     return t;
0435 }
0436 
0437 void free_matrixSP(float **m, long nrl, long nrh, long ncl, long nch)
0438 /* free a float matrix allocated by matrix() */
0439 {
0440     Q_UNUSED(nrh);
0441     Q_UNUSED(nch);
0442     free((FREE_ARG)(m[nrl] + ncl - NR_END));
0443     free((FREE_ARG)(m + nrl - NR_END));
0444 }
0445 
0446 void free_f3tensorSP(float ***t, long nrl, long nrh, long ncl, long nch, long ndl, long ndh)
0447 /* free a float f3tensor allocated by f3tensor() */
0448 {
0449     Q_UNUSED(nrh);
0450     Q_UNUSED(nch);
0451     Q_UNUSED(ndh);
0452     free((FREE_ARG)(t[nrl][ncl] + ndl - NR_END));
0453     free((FREE_ARG)(t[nrl] + ncl - NR_END));
0454     free((FREE_ARG)(t + nrl - NR_END));
0455 }