1 |
tplarson |
1.1 |
|
2 |
|
|
/* |
3 |
|
|
* imageinterp (modified from obs2helio) |
4 |
|
|
* |
5 |
|
|
* Purpose: |
6 |
|
|
* Interpolate CCD data to estimate value that would |
7 |
|
|
* be obtained at specified equal incrememts of heliographic |
8 |
|
|
* longitude and sine of latitude. |
9 |
|
|
* |
10 |
|
|
* Description: |
11 |
|
|
* |
12 |
|
|
* Employs bi-linear or cubic convolution interpolation to map a |
13 |
|
|
* portion of the solar disk to a rectangular array "cols" by "rows" in |
14 |
|
|
* width and height respectively. |
15 |
|
|
* |
16 |
|
|
* Reference: |
17 |
|
|
* |
18 |
|
|
* Green, Robin M. "Spherical Astronomy," Cambridge University |
19 |
|
|
* Press, Cambridge, 1985. |
20 |
|
|
* |
21 |
|
|
* Responsible: Kay Leibrand KLeibrand@solar.Stanford.EDU |
22 |
|
|
* |
23 |
|
|
* Restrictions: |
24 |
|
|
* The number of output map rows must be even. |
25 |
|
|
* The number of output map columns must be less than MAXCOLS. |
26 |
|
|
* Assumes orientation is a 4 character string with one of the following |
27 |
|
|
* 8 legal values: SESW SENE SWSE SWNW NWNE NWSW NENW NESE |
28 |
|
|
* |
29 |
|
|
* Bugs: |
30 |
|
|
* Possible division by 0 |
31 |
|
|
* |
32 |
|
|
* Planned updates: |
33 |
|
|
* Optimize. |
34 |
|
|
* |
35 |
|
|
* Revision history is at end of file. |
36 |
|
|
*/ |
37 |
|
|
|
38 |
|
|
#include <math.h> |
39 |
tplarson |
1.4 |
#include "projection.h" |
40 |
tplarson |
1.1 |
|
41 |
tplarson |
1.4 |
char *cvsinfo_imageinterp = "cvsinfo: $Header: imageinterp.c,v $"; |
42 |
tplarson |
1.1 |
|
43 |
|
|
const int kMaxCols = 8192; |
44 |
|
|
const double kOmegaCarr = (360 / 27.27527); /* degrees/day - synodic Carrington rotation rate */ |
45 |
|
|
const double kRadsPerDegree = M_PI/180.; |
46 |
|
|
|
47 |
|
|
static void Ccker(double *u, double s); |
48 |
|
|
static double Ccintd(double *f, int nx, int ny, double x, double y); |
49 |
|
|
static double Linintd(double *f, int nx, int ny, double x, double y); |
50 |
|
|
static void Distort(double x, |
51 |
|
|
double y, |
52 |
|
|
double rsun, |
53 |
|
|
int sign, |
54 |
|
|
double *xd, |
55 |
|
|
double *yd, |
56 |
tplarson |
1.4 |
const LIBPROJECTION_Dist_t *distpars); |
57 |
tplarson |
1.1 |
|
58 |
|
|
/* Calculate the interpolation kernel. */ |
59 |
|
|
void Ccker(double *u, double s) |
60 |
|
|
{ |
61 |
|
|
double s2, s3; |
62 |
|
|
|
63 |
|
|
s2= s * s; |
64 |
|
|
s3= s2 * s; |
65 |
|
|
u[0] = s2 - 0.5 * (s3 + s); |
66 |
|
|
u[1] = 1.5*s3 - 2.5*s2 + 1.0; |
67 |
|
|
u[2] = -1.5*s3 + 2.0*s2 + 0.5*s; |
68 |
|
|
u[3] = 0.5 * (s3 - s2); |
69 |
|
|
} |
70 |
|
|
|
71 |
|
|
/* Cubic convolution interpolation */ |
72 |
|
|
/* |
73 |
|
|
* Cubic convolution interpolation, based on GONG software, received Apr-88 |
74 |
|
|
* Interpolation by cubic convolution in 2 dimensions with 32-bit double data |
75 |
|
|
* |
76 |
|
|
* Reference: |
77 |
|
|
* R.G. Keys in IEEE Trans. Acoustics, Speech, and Signal Processing, |
78 |
|
|
* Vol. 29, 1981, pp. 1153-1160. |
79 |
|
|
* |
80 |
|
|
* Usage: |
81 |
|
|
* double ccintd (double *f, int nx, int ny, double x, double y) |
82 |
|
|
* |
83 |
|
|
* Bugs: |
84 |
|
|
* Currently interpolation within one pixel of edge is not |
85 |
|
|
* implemented. If x or y is in this range or off the picture, the |
86 |
|
|
* function value returned is zero. |
87 |
|
|
* Only works for double data. |
88 |
|
|
*/ |
89 |
|
|
double Ccintd(double *f, int nx, int ny, double x, double y) |
90 |
|
|
{ |
91 |
|
|
double ux[4], uy[4]; |
92 |
|
|
/* Sum changed to double to speed up things */ |
93 |
|
|
double sum; |
94 |
|
|
|
95 |
|
|
int ix, iy, ix1, iy1, i, j; |
96 |
|
|
|
97 |
|
|
if (x < 1. || x >= (double)(nx-2) || |
98 |
|
|
y < 1. || y >= (double)(ny-2)) |
99 |
|
|
return 0.0; |
100 |
|
|
|
101 |
|
|
ix = (int)x; |
102 |
|
|
iy = (int)y; |
103 |
|
|
Ccker(ux, x - (double)ix); |
104 |
|
|
Ccker(uy, y - (double)iy); |
105 |
|
|
|
106 |
|
|
ix1 = ix - 1; |
107 |
|
|
iy1 = iy - 1; |
108 |
|
|
sum = 0.; |
109 |
|
|
for (i = 0; i < 4; i++) |
110 |
|
|
for (j = 0; j < 4; j++) |
111 |
|
|
sum = sum + f[(iy1+i) * nx + ix1 + j] * uy[i] * ux[j]; |
112 |
|
|
return sum; |
113 |
|
|
} |
114 |
|
|
|
115 |
|
|
/* |
116 |
|
|
* Bilinear interpolation, based on pipeLNU remap. |
117 |
|
|
* |
118 |
|
|
* Reference: |
119 |
|
|
* Abramowitz, Milton, and Stegun, Irene, "Handbook of Mathematical |
120 |
|
|
* Functions," Dover Publications, New York, 1964. |
121 |
|
|
* |
122 |
|
|
* Usage: |
123 |
|
|
* double linintd (double *f, int nx, int ny, double x, double y) |
124 |
|
|
* |
125 |
|
|
* Bugs: |
126 |
|
|
* Only works for double data. |
127 |
|
|
*/ |
128 |
|
|
|
129 |
|
|
double Linintd(double *f, int nx, int ny, double x, double y) |
130 |
|
|
{ |
131 |
|
|
double p0, p1, q0, q1; /* weights */ |
132 |
|
|
int ilow, jlow; /* selected CCD pixels */ |
133 |
|
|
double *fptr; /* input array temp */ |
134 |
|
|
double u; |
135 |
|
|
|
136 |
|
|
ilow = (int)floor(x); |
137 |
|
|
jlow = (int)floor(y); |
138 |
|
|
if (ilow < 0) ilow = 0; |
139 |
|
|
if (ilow+1 >= nx) ilow -= 1; |
140 |
|
|
if (jlow < 0) jlow = 0; |
141 |
|
|
if (jlow+1 >= ny) jlow -= 1; |
142 |
|
|
p1 = x - ilow; |
143 |
|
|
p0 = 1.0 - p1; |
144 |
|
|
q1 = y - jlow; |
145 |
|
|
q0 = 1.0 - q1; |
146 |
|
|
|
147 |
|
|
/* Bilinear interpolation from four data points. */ |
148 |
|
|
u = 0.0; |
149 |
|
|
fptr = f + jlow*nx + ilow; |
150 |
|
|
u += p0 * q0 * *fptr++; |
151 |
|
|
u += p1 * q0 * *fptr; |
152 |
|
|
fptr += nx - 1; |
153 |
|
|
u += p0 * q1 * *fptr++; |
154 |
|
|
u += p1 * q1 * *fptr; |
155 |
|
|
return u; |
156 |
|
|
} |
157 |
|
|
|
158 |
|
|
|
159 |
|
|
int SetDistort(int dist, |
160 |
|
|
double cubic, |
161 |
|
|
double alpha, |
162 |
|
|
double beta, |
163 |
|
|
double feff, |
164 |
tplarson |
1.4 |
LIBPROJECTION_Dist_t *dOut) |
165 |
tplarson |
1.1 |
{ |
166 |
|
|
int error = 0; |
167 |
|
|
|
168 |
|
|
if (dOut != NULL) |
169 |
|
|
{ |
170 |
|
|
int status = 0; |
171 |
|
|
|
172 |
|
|
dOut->disttype = dist; |
173 |
|
|
|
174 |
|
|
/* disttype == 0 is 'no distortion' and is not an error */ |
175 |
|
|
if (dOut->disttype != 0) |
176 |
|
|
{ |
177 |
|
|
if (dOut->disttype == 1) |
178 |
|
|
{ |
179 |
|
|
/* FD */ |
180 |
|
|
dOut->xc = 511.5; |
181 |
|
|
dOut->yc = 511.5; |
182 |
|
|
dOut->scale = 1.0; |
183 |
|
|
} |
184 |
|
|
else if (dOut->disttype == 2) |
185 |
|
|
{ |
186 |
|
|
/* vw */ |
187 |
|
|
dOut->xc = 95.1; |
188 |
|
|
dOut->yc = 95.1; |
189 |
|
|
dOut->scale = 5.0; |
190 |
|
|
} |
191 |
|
|
else |
192 |
|
|
{ |
193 |
|
|
error = 1; |
194 |
|
|
} |
195 |
|
|
|
196 |
|
|
if (!error) |
197 |
|
|
{ |
198 |
|
|
dOut->feff = feff; |
199 |
|
|
dOut->alpha = alpha * kRadsPerDegree; |
200 |
|
|
beta *= kRadsPerDegree; |
201 |
|
|
dOut->cosbeta = cos(beta); |
202 |
|
|
dOut->sinbeta = sin(beta); |
203 |
|
|
dOut->cdist = cubic; |
204 |
|
|
|
205 |
|
|
if (status != CMDPARAMS_SUCCESS) |
206 |
|
|
{ |
207 |
|
|
error = 1; |
208 |
|
|
} |
209 |
|
|
|
210 |
|
|
} |
211 |
|
|
|
212 |
|
|
} /* disttype != 0*/ |
213 |
|
|
} |
214 |
|
|
else |
215 |
|
|
{ |
216 |
|
|
error = 1; |
217 |
|
|
} |
218 |
|
|
|
219 |
|
|
return error; |
220 |
|
|
} |
221 |
|
|
|
222 |
|
|
|
223 |
|
|
void Distort(double x, |
224 |
|
|
double y, |
225 |
|
|
double rsun, |
226 |
|
|
int sign, |
227 |
|
|
double *xd, |
228 |
|
|
double *yd, |
229 |
tplarson |
1.4 |
const LIBPROJECTION_Dist_t *distpars) |
230 |
tplarson |
1.1 |
{ |
231 |
|
|
/* |
232 |
|
|
For sign=+1 transforms ideal coordinates (x,y) to distorted |
233 |
|
|
coordinates (xd,yd). rsun needed to correct for scale error. |
234 |
|
|
For sign=-1 ideal and distorted coordinates are swapped. |
235 |
|
|
Units are pixels from lower left corner. |
236 |
|
|
Adapted from /home/schou/calib/dist/distort.pro |
237 |
|
|
Note that rsun must be passed in FD pixels! |
238 |
|
|
*/ |
239 |
|
|
|
240 |
|
|
double xx,yy,xxl,yyl,x0,y0,x00,y00,x0l,y0l,epsx,epsy,rdist; |
241 |
|
|
|
242 |
|
|
if (distpars->disttype == 0) |
243 |
|
|
{ |
244 |
|
|
*xd=x; |
245 |
|
|
*yd=y; |
246 |
|
|
return; |
247 |
|
|
} |
248 |
|
|
/* Convert fo FD pixel scale*/ |
249 |
|
|
|
250 |
|
|
rsun=rsun*distpars->scale; |
251 |
|
|
|
252 |
|
|
/* Don't do anyway since rsun already corrected. Don't get me started... */ |
253 |
|
|
/* above comment no longer applies, rsun is now untouched in o2helio (v2helio) */ |
254 |
|
|
|
255 |
|
|
/* Shift zero point to nominal image center and convert to FD pixel scale */ |
256 |
|
|
|
257 |
|
|
x00=distpars->scale*(x-distpars->xc); |
258 |
|
|
y00=distpars->scale*(y-distpars->yc); |
259 |
|
|
|
260 |
|
|
/* Radial distortion */ |
261 |
|
|
|
262 |
|
|
rdist=distpars->cdist*(x00*x00+y00*y00-rsun*rsun); |
263 |
|
|
|
264 |
|
|
x0=x00+rdist*x00; |
265 |
|
|
y0=y00+rdist*y00; |
266 |
|
|
|
267 |
|
|
/* Distortion due to CCD tilt */ |
268 |
|
|
|
269 |
|
|
/* First rotate coordinate system */ |
270 |
|
|
x0l=x0*distpars->cosbeta+y0*distpars->sinbeta; |
271 |
|
|
y0l=-x0*distpars->sinbeta+y0*distpars->cosbeta; |
272 |
|
|
|
273 |
|
|
/* Apply distortion */ |
274 |
|
|
xxl=x0l*(1.-distpars->alpha*distpars->alpha/4.+y0l/distpars->feff*distpars->alpha); |
275 |
|
|
yyl=y0l*(1.+distpars->alpha*distpars->alpha/4.+y0l/distpars->feff*distpars->alpha) - |
276 |
|
|
rsun*rsun/distpars->feff*distpars->alpha; |
277 |
|
|
|
278 |
|
|
/* Rotate coordinates back */ |
279 |
|
|
xx=xxl*distpars->cosbeta-yyl*distpars->sinbeta; |
280 |
|
|
yy=xxl*distpars->sinbeta+yyl*distpars->cosbeta; |
281 |
|
|
|
282 |
|
|
/* Total distortion */ |
283 |
|
|
|
284 |
|
|
epsx=xx-x00; |
285 |
|
|
epsy=yy-y00; |
286 |
|
|
|
287 |
|
|
/* Return distorted values. Cheating with inverse transform. */ |
288 |
|
|
|
289 |
|
|
*xd=x+sign*epsx/distpars->scale; |
290 |
|
|
*yd=y+sign*epsy/distpars->scale; |
291 |
|
|
} |
292 |
|
|
|
293 |
|
|
|
294 |
|
|
int imageinterp( |
295 |
|
|
float *V, /* input velocity array */ |
296 |
|
|
/* assumed declared V[ypixels][xpixels] */ |
297 |
|
|
float *U, /* output projected array */ |
298 |
|
|
|
299 |
tplarson |
1.2 |
int xpixels, /* x width of input array */ |
300 |
|
|
int ypixels, /* y width of input array */ |
301 |
|
|
double x0, /* x pixel address of disk center */ |
302 |
|
|
double y0, /* y pixel address of disk center */ |
303 |
|
|
double P, /* angle between CCD y-axis and solar vertical */ |
304 |
|
|
/* positive to the east (CCW) */ |
305 |
tplarson |
1.1 |
double rsun, /* pixels */ |
306 |
tplarson |
1.3 |
double Rmax, /* maximum disk radius to use (e.g. 0.95) */ |
307 |
|
|
int NaN_beyond_rmax, |
308 |
tplarson |
1.1 |
int interpolation, /* option */ |
309 |
|
|
int cols, /* width of output array */ |
310 |
|
|
int rows, /* height of output array */ |
311 |
|
|
double vsign, |
312 |
tplarson |
1.4 |
const LIBPROJECTION_Dist_t *distpars) |
313 |
tplarson |
1.1 |
{ |
314 |
|
|
|
315 |
|
|
float u; /* output temp */ |
316 |
|
|
double x, y; /* CCD location of desired point */ |
317 |
|
|
int row, col; /* index into output array */ |
318 |
|
|
int rowoffset; |
319 |
tplarson |
1.3 |
double xratio, yratio, Rmax2; |
320 |
tplarson |
1.1 |
|
321 |
|
|
long i; |
322 |
|
|
double *vdp; |
323 |
|
|
float *vp; |
324 |
tplarson |
1.2 |
double xtmp, ytmp; |
325 |
tplarson |
1.1 |
|
326 |
|
|
double *VD; |
327 |
|
|
VD=(double *)(malloc(xpixels*ypixels*sizeof(double))); |
328 |
|
|
vdp=VD; |
329 |
|
|
vp=V; |
330 |
|
|
for (i=0;i<xpixels*ypixels;i++) *vdp++=(double)*vp++; |
331 |
tplarson |
1.3 |
|
332 |
|
|
Rmax2 = Rmax*Rmax*rsun*rsun; |
333 |
tplarson |
1.1 |
|
334 |
|
|
if (cols > kMaxCols) |
335 |
|
|
{ |
336 |
tplarson |
1.4 |
return kLIBPROJECTION_DimensionMismatch; |
337 |
tplarson |
1.1 |
} |
338 |
|
|
|
339 |
|
|
|
340 |
tplarson |
1.4 |
if (interpolation != kLIBPROJECTION_InterCubic && interpolation != kLIBPROJECTION_InterBilinear) |
341 |
tplarson |
1.1 |
{ |
342 |
tplarson |
1.4 |
return kLIBPROJECTION_UnsupportedInterp; |
343 |
tplarson |
1.1 |
} |
344 |
|
|
|
345 |
|
|
xratio=(double)xpixels/cols; |
346 |
|
|
yratio=(double)ypixels/rows; |
347 |
|
|
|
348 |
|
|
for (row = 0; row < rows; row++) { |
349 |
|
|
|
350 |
|
|
rowoffset = row*cols; |
351 |
|
|
|
352 |
|
|
for (col = 0; col < cols; col++) { |
353 |
|
|
|
354 |
tplarson |
1.3 |
xtmp = (col + 0.5)*xratio - 0.5 - x0; |
355 |
|
|
ytmp = (row + 0.5)*yratio - 0.5 - y0; |
356 |
|
|
if ((xtmp*xtmp + ytmp*ytmp) >= Rmax2) |
357 |
|
|
{ |
358 |
|
|
*(U + rowoffset + col) = (NaN_beyond_rmax) ? DRMS_MISSING_FLOAT : (float)0.0; |
359 |
|
|
continue; |
360 |
|
|
} |
361 |
|
|
x= x0 + xtmp*cos(P) - ytmp*sin(P); |
362 |
|
|
y= y0 + xtmp*sin(P) + ytmp*cos(P); |
363 |
tplarson |
1.1 |
|
364 |
|
|
Distort(x, y, rsun, +1, &x, &y, distpars); |
365 |
|
|
|
366 |
tplarson |
1.4 |
if (interpolation == kLIBPROJECTION_InterCubic) |
367 |
tplarson |
1.1 |
{ |
368 |
|
|
u = (float)(vsign * Ccintd (VD,xpixels,ypixels,x,y)); |
369 |
|
|
} |
370 |
tplarson |
1.4 |
else if (interpolation == kLIBPROJECTION_InterBilinear) |
371 |
tplarson |
1.1 |
{ |
372 |
|
|
u = (float)(vsign * Linintd (VD,xpixels,ypixels,x,y)); |
373 |
|
|
} |
374 |
|
|
|
375 |
|
|
*(U + rowoffset + col) = u; |
376 |
|
|
} |
377 |
|
|
} |
378 |
|
|
free(VD); |
379 |
tplarson |
1.4 |
return kLIBPROJECTION_Success; |
380 |
tplarson |
1.1 |
} |