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 }