CR2RE Pipeline Reference Manual 1.7.0
cr2res_detlin.c
1/*
2 * This file is part of the CR2RES Pipeline
3 * Copyright (C) 2002,2003 European Southern Observatory
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24/*-----------------------------------------------------------------------------
25 Includes
26 -----------------------------------------------------------------------------*/
27
28#include <math.h>
29#include <cpl.h>
30#include "cr2res_detlin.h"
31#include "cr2res_pfits.h"
32#include "cr2res_qc.h"
33
34/*-----------------------------------------------------------------------------
35 Defines
36 -----------------------------------------------------------------------------*/
37
38#define pow2(x) (x)*(x)
39#define pow3(x) (x)*(x)*(x)
40
41/*-----------------------------------------------------------------------------
42 Functions prototypes
43 -----------------------------------------------------------------------------*/
44
45static int cr2res_detlin_frames_dit_compare(
46 const cpl_frame * in1,
47 const cpl_frame * in2) ;
48static void cr2res_matrix_fill_normal_vandermonde(cpl_matrix * self,
49 cpl_matrix * mx,
50 const cpl_vector * xhat,
51 cpl_boolean is_eqdist,
52 cpl_size mindeg,
53 const cpl_vector * values);
54
55/*----------------------------------------------------------------------------*/
59/*----------------------------------------------------------------------------*/
60
62
63/*----------------------------------------------------------------------------*/
70/*----------------------------------------------------------------------------*/
72 hdrl_image * in,
73 const hdrl_imagelist * detlin)
74{
75 const cpl_image * ima ;
76 const cpl_image * erra ;
77 const cpl_image * imb ;
78 const cpl_image * errb ;
79 const cpl_image * imc ;
80 const cpl_image * errc ;
81 const double * pima ;
82 const double * perra ;
83 const double * pimb ;
84 const double * perrb ;
85 const double * pimc ;
86 const double * perrc ;
87 cpl_image * cur_ima ;
88 double * pdata ;
89 double * perr ;
90 int nx, ny ;
91 double correction_factor;
92 int i ;
93
94 /* Test entries */
95 if (!in || !detlin) return -1 ;
96
97 /* Initialise */
98 pdata = cpl_image_get_data_double(hdrl_image_get_image(in)) ;
99 perr = cpl_image_get_data_double(hdrl_image_get_error(in)) ;
100
101
102 /* Load the 3 coeffs images */
109
110 if (!ima || !imb || !imc ) {
111 cpl_msg_error(cpl_func, "Cannot access the detlin images") ;
112 return -1 ;
113 }
114 pima = cpl_image_get_data_double_const(ima) ;
115 pimb = cpl_image_get_data_double_const(imb) ;
116 pimc = cpl_image_get_data_double_const(imc) ;
117 perra = cpl_image_get_data_double_const(erra);
118 perrb = cpl_image_get_data_double_const(errb);
119 perrc = cpl_image_get_data_double_const(errc);
120
121 /* Test sizes */
122 cur_ima = hdrl_image_get_image(in) ;
123 nx = cpl_image_get_size_x(cur_ima) ;
124 ny = cpl_image_get_size_y(cur_ima) ;
125 if ((cpl_image_get_size_x(ima) != nx) ||
126 (cpl_image_get_size_x(imb) != nx) ||
127 (cpl_image_get_size_x(imc) != nx) ||
128 (cpl_image_get_size_y(ima) != ny) ||
129 (cpl_image_get_size_y(imb) != ny) ||
130 (cpl_image_get_size_y(imc) != ny)) {
131 cpl_msg_error(cpl_func, "Incompatible sizes") ;
132 return -1 ;
133 }
134
135 /* Loop on pixels */
136 for (i=0 ; i<nx*ny ; i++) {
137
138 // Only correct non-linear regime
139 if (pdata[i] < CR2RES_DETLIN_THRESHOLD) continue ;
140
141 // for each pixel p' = (a + b * p + c * p * p) * p
142 // PIPE-12658 turn off error propagation for now, see ticket for discussion.
143 /*perr[i] = pow2(perra[i] * pdata[i]) + pow2(perrb[i] * pow2(pdata[i]))
144 + pow2(perrc[i] * pow3(pdata[i]))
145 + pow2(perr[i] * (pima[i] + 2. * pimb[i] * pdata[i]
146 + 3. * pimc[i] * pow2(pdata[i])));
147 perr[i] = sqrt(perr[i]);*/
148
149 correction_factor = pima[i] + \
150 ((pimb[i] + pimc[i] * pdata[i]) * pdata[i]);
151 pdata[i] = pdata[i] * correction_factor;
152 }
153 /* return */
154 return 0 ;
155}
156
157/*----------------------------------------------------------------------------*/
175/*----------------------------------------------------------------------------*/
177 const cpl_vector * dits,
178 const cpl_vector * adus,
179 cpl_size max_degree,
180 cpl_polynomial ** fitted,
181 cpl_vector ** error)
182{
183 cpl_matrix * samppos ;
184 cpl_polynomial * fitted_local ;
185 cpl_vector * error_local ;
186 cpl_vector * adusPsec ;
187 cpl_vector * y_tofit, *tmp;
188 cpl_vector * adus_loc, *dits_loc;
189 double aduPsec;
190 cpl_size i=0, first_satur=-1 ;
191 int count_linear=0;
192
193 /* Test entries */
194 if (fitted == NULL || dits == NULL || adus == NULL) return -1 ;
195 if (cpl_vector_get_size(dits) != cpl_vector_get_size(adus))
196 return -1 ;
197
198 /* Determine true ADU/s by assuming it is linear up to threshold */
199 if (cpl_vector_get_min(adus) > CR2RES_DETLIN_THRESHOLD) return -1;
200 if (cpl_vector_get_max(adus) < CR2RES_DETLIN_THRESHOLD) return -1;
201 for (i = 0; i < cpl_vector_get_size(adus); i++) {
202 if (cpl_vector_get(adus,i) < CR2RES_DETLIN_THRESHOLD ) count_linear++;
203 if (cpl_vector_get(adus,i)>CR2RES_DETLIN_MAXFIT && first_satur==-1)
204 first_satur=i;
205 }
206
207 // in case no adus above threshold
208 if (first_satur==-1) first_satur= cpl_vector_get_size(dits);
209 // in case, we have more linear points than the saturation
210 if (count_linear > first_satur-1) count_linear = first_satur-1;
211
212 adus_loc = cpl_vector_extract(adus, 0, first_satur-1, 1);
213 dits_loc = cpl_vector_extract(dits, 0, first_satur-1, 1);
214
215
216 adusPsec = cpl_vector_duplicate(adus_loc);
217 cpl_vector_divide(adusPsec, dits_loc);
218 tmp = cpl_vector_extract(adusPsec,0,count_linear-1,1);
219 aduPsec = cpl_vector_get_median(tmp);
220 cpl_vector_delete(tmp);
221
222 samppos = cpl_matrix_wrap(1,
223 cpl_vector_get_size(adus_loc),
224 cpl_vector_get_data(adus_loc)) ;
225
226 y_tofit = cpl_vector_new(cpl_vector_get_size(dits_loc));
227 for(i = 0; i < cpl_vector_get_size(dits_loc); i++) {
228 double y;
229 // We fit the ratio of true ADU/s over the measured ones.
230 y = aduPsec / cpl_vector_get(adusPsec,i);
231 cpl_vector_set(y_tofit, i, y);
232 }
233 cpl_vector_delete(adusPsec);
234
235 /* Fit */
236 fitted_local = cpl_polynomial_new(1);
237 if (
238 cpl_polynomial_fit(fitted_local, samppos, NULL, y_tofit, NULL,
239 CPL_FALSE, NULL, &max_degree) != CPL_ERROR_NONE) {
240
241 /* Failed Fit - Fill the coefficients */
242 cpl_vector_delete(adus_loc);
243 cpl_vector_delete(dits_loc);
244 cpl_matrix_unwrap(samppos) ;
245 cpl_vector_delete(y_tofit);
246 cpl_polynomial_delete(fitted_local) ;
247 cpl_error_reset() ;
248 return -1 ;
249 }
250
251 /* Compute the error */
252 error_local = cpl_vector_new(max_degree+1) ;
253 cpl_size nc = max_degree + 1;
254 cpl_size ndata = cpl_vector_get_size(y_tofit);
255 if (nc >= ndata){
256 // No uncertainty as fit should be perfectly aligned with data points
257 for (i = 0; i < max_degree + 1; i++) {
258 cpl_vector_set(error_local, i, 0);
259 }
260 } else {
261 // lhs = vandermode(x, order)
262 // hankel = dot(lhs.T, lhs)
263 // cov = inv(hankel)
264 // cov *= sum(abs(resids)) / (len(x) - order)
265 // error_local = sqrt(diag(cov))
266
267 cpl_matrix * hankel = cpl_matrix_new(nc, nc);
268 cpl_matrix * mx = cpl_matrix_new(nc, 1); // just a temporary matrix
269
270 // this actually returns the hankel matrix, not vandermode
271 // also directly copied from the cpl source code (cpl_polynomial.c)
272 cr2res_matrix_fill_normal_vandermonde(hankel, mx, adus_loc, CPL_FALSE,
273 0, y_tofit);
274 cpl_matrix * inverse = cpl_matrix_invert_create(hankel);
275 cpl_vector * resids = cpl_vector_new(ndata);
276
277 cpl_vector_fill_polynomial_fit_residual(resids, y_tofit, NULL,
278 fitted_local, samppos, NULL);
279 for (i = 0; i < ndata; i++) {
280 cpl_vector_set(resids, i, fabs(cpl_vector_get(resids, i)));
281 }
282
283 cpl_matrix_multiply_scalar(inverse,
284 cpl_vector_get_sum(resids) / (double)(ndata - nc));
285
286 for (i = 0; i < max_degree + 1; i++) {
287 cpl_vector_set(error_local, i, sqrt(cpl_matrix_get(inverse, i, i)));
288 }
289 cpl_matrix_delete(hankel);
290 cpl_matrix_delete(mx);
291 cpl_matrix_delete(inverse);
292 cpl_vector_delete(resids);
293 }
294 cpl_vector_delete(y_tofit);
295 cpl_matrix_unwrap(samppos) ;
296 cpl_vector_delete(dits_loc);
297 cpl_vector_delete(adus_loc);
298
299 /* Check Result - Polynomial coefficients are NaN sometimes */
300 for (i=0 ; i<=max_degree ; i++) {
301 double cur_coeff;
302 cur_coeff = cpl_polynomial_get_coeff(fitted_local, &i) ;
303 if (isnan(cur_coeff)) {
304 cpl_polynomial_delete(fitted_local) ;
305 cpl_vector_delete(error_local) ;
306 *fitted = NULL ;
307 *error = NULL ;
308 return -1 ;
309 }
310 }
311
312 /* Catch an error in CPL */
313 if (cpl_error_get_code()) {
314 cpl_error_reset() ;
315 cpl_polynomial_delete(fitted_local) ;
316 cpl_vector_delete(error_local) ;
317 *fitted = NULL ;
318 *error = NULL ;
319 return -1 ;
320 }
321
322 /* Return */
323 *fitted = fitted_local ;
324 if (error != NULL) *error = error_local ;
325 else cpl_vector_delete(error_local) ;
326 return 0 ;
327}
328
329/*----------------------------------------------------------------------------*/
335/*----------------------------------------------------------------------------*/
337 const cpl_frameset * in)
338{
339 cpl_frameset * sorted ;
340
341 /* Check Inputs */
342 if (in == NULL) return NULL ;
343
344 sorted = cpl_frameset_duplicate(in) ;
345 if (cpl_frameset_sort(sorted,
346 cr2res_detlin_frames_dit_compare) != CPL_ERROR_NONE) {
347 cpl_frameset_delete(sorted) ;
348 return NULL ;
349 }
350 return sorted ;
351}
352
354
355/*----------------------------------------------------------------------------*/
362/*----------------------------------------------------------------------------*/
363static int cr2res_detlin_frames_dit_compare(
364 const cpl_frame * in1,
365 const cpl_frame * in2)
366{
367 cpl_propertylist * plist1 ;
368 cpl_propertylist * plist2 ;
369 double dit1, dit2 ;
370
371 /* Test entries */
372 if (in1==NULL || in2==NULL) return 0 ;
373
374 /* Get property lists */
375 plist1=cpl_propertylist_load(cpl_frame_get_filename(in1),0) ;
376 plist2=cpl_propertylist_load(cpl_frame_get_filename(in2),0) ;
377
378 /* Get DITs */
379 dit1 = cr2res_pfits_get_dit(plist1) ;
380 dit2 = cr2res_pfits_get_dit(plist2) ;
381 if (plist1 != NULL) cpl_propertylist_delete(plist1) ;
382 if (plist2 != NULL) cpl_propertylist_delete(plist2) ;
383 if (cpl_error_get_code()) return 0 ;
384
385 if (dit1<dit2) return -1 ;
386 else if (dit1>dit2) return 1 ;
387 return 0 ;
388}
389
390/*----------------------------------------------------------------------------*/
404/*----------------------------------------------------------------------------*/
405static void cr2res_matrix_fill_normal_vandermonde(cpl_matrix * self,
406 cpl_matrix * mx,
407 const cpl_vector * xhat,
408 cpl_boolean is_eqdist,
409 cpl_size mindeg,
410 const cpl_vector * values)
411{
412
413
414 const double * dval = cpl_vector_get_data_const(values);
415 const double * xval = cpl_vector_get_data_const(xhat);
416 cpl_vector * phat = cpl_vector_duplicate(xhat); /* Powers of xhat */
417 cpl_vector * qhat = NULL; /* mindeg Power of xhat */
418 double * dhat = cpl_vector_get_data(phat);
419 double * ehat = NULL;
420 const cpl_size nc = cpl_matrix_get_ncol(self);
421 const cpl_size np = cpl_vector_get_size(xhat);
422 cpl_size i,j;
423
424 /* Fill Hankel matrix from top-left to main skew diagonal
425 - on and above (non-skew) main diagonal */
426 /* Also compute transpose(V) * b */
427 /* Peel off 1st iteration */
428 if (mindeg > 0) {
429 double hsum = 0.0;
430 cpl_size k;
431
432 qhat = mindeg == 1 ? cpl_vector_duplicate(xhat) : cpl_vector_new(np);
433 ehat = cpl_vector_get_data(qhat);
434
435 /* Raise xhat to the power of mindeg */
436 for (k=0; k < np; k++) {
437 const double x = xval[k];
438
439 if (mindeg > 1) ehat[k] = pow(x, (int)mindeg);
440 dhat[k] *= ehat[k];
441
442 hsum += ehat[k] * ehat[k];
443 }
444 cpl_matrix_set(self, 0, 0, hsum);
445 } else {
446 cpl_matrix_set(self, 0, 0, (double)np);
447 }
448 /* qhat is xhat to the power of mindeg, iff mindeg > 0 */
449 /* dhat is xhat to the power of 1+mindeg, iff mindeg > 0 */
450 for (j=1; j < 2; j++) {
451 double vsum0 = 0.0;
452 double hsum = 0.0;
453 double vsum = 0.0;
454 cpl_size k;
455
456 for (k=0; k < np; k++) {
457 const double y = dval[k];
458
459 hsum += mindeg > 0 ? ehat[k] * dhat[k] : dhat[k];
460 vsum += y * dhat[k];
461 vsum0 += mindeg > 0 ? ehat[k] * y : y;
462 }
463 cpl_matrix_set(mx, 0, 0, vsum0);
464 cpl_matrix_set(mx, j, 0, vsum);
465 if (is_eqdist) continue;
466 k = j;
467 for (i=0; i <= k; i++, k--) {
468 cpl_matrix_set(self, i, k, hsum);
469 }
470 }
471 for (; j < nc; j++) {
472 double hsum = 0.0;
473 double vsum = 0.0;
474 cpl_size k;
475
476 for (k=0; k < np; k++) {
477 const double x = xval[k];
478 const double y = dval[k];
479
480 dhat[k] *= x;
481 hsum += mindeg > 0 ? ehat[k] * dhat[k] : dhat[k];
482 vsum += y * dhat[k];
483 }
484 cpl_matrix_set(mx, j, 0, vsum);
485 if (is_eqdist && (j&1)) continue;
486 k = j;
487 for (i=0; i <= k; i++, k--) {
488 cpl_matrix_set(self, i, k, hsum);
489 }
490 }
491 /* Fill remaining Hankel matrix - on and above (non-skew) main diagonal */
492
493 if (mindeg > 0) {
494 cpl_vector_multiply(phat, qhat);
495 cpl_vector_delete(qhat);
496 }
497
498 for (i = 1; i < nc; i++) {
499 cpl_size k;
500 double hsum = 0.0;
501
502 if (is_eqdist && ((i+nc)&1)==0) {
503 cpl_vector_multiply(phat, xhat);
504 continue;
505 }
506
507 for (k=0; k < np; k++) {
508 const double x = xval[k];
509
510 dhat[k] *= x;
511 hsum += dhat[k];
512 }
513 k = i;
514 for (j = nc-1; k <= j; k++, j--) {
515 cpl_matrix_set(self, k, j, hsum);
516 }
517 }
518
519 cpl_vector_delete(phat);
520
521}
522
cpl_frameset * cr2res_detlin_sort_frames(const cpl_frameset *in)
Sort the frames by increasing DIT.
int cr2res_detlin_compute(const cpl_vector *dits, const cpl_vector *adus, cpl_size max_degree, cpl_polynomial **fitted, cpl_vector **error)
Fits the response of a given pixel to the illumination increase.
int cr2res_detlin_correct(hdrl_image *in, const hdrl_imagelist *detlin)
Apply the detector linearity correction.
double cr2res_pfits_get_dit(const cpl_propertylist *plist)
find out the DIT value
cpl_image * hdrl_image_get_error(hdrl_image *himg)
get error as cpl image
Definition hdrl_image.c:131
const cpl_image * hdrl_image_get_error_const(const hdrl_image *himg)
get error as cpl image
Definition hdrl_image.c:144
cpl_image * hdrl_image_get_image(hdrl_image *himg)
get data as cpl image
Definition hdrl_image.c:105
const cpl_image * hdrl_image_get_image_const(const hdrl_image *himg)
get data as cpl image
Definition hdrl_image.c:118
const hdrl_image * hdrl_imagelist_get_const(const hdrl_imagelist *himlist, cpl_size inum)
Get an image from a list of images.