CR2RE Pipeline Reference Manual 1.6.10
hdrl_bpm_fit.c
1/*
2 * This file is part of the HDRL
3 * Copyright (C) 2014 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 02110-1301 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24/*-----------------------------------------------------------------------------
25 Includes
26-----------------------------------------------------------------------------*/
27
28#include "hdrl_types.h"
29#include "hdrl_image.h"
30#include "hdrl_imagelist.h"
31#include "hdrl_utils.h"
32#include "hdrl_fit.h"
33#include "hdrl_bpm_fit.h"
34
35#include <cpl.h>
36#include <string.h>
37#include <math.h>
38
39/*-----------------------------------------------------------------------------
40 Static
41 -----------------------------------------------------------------------------*/
42
43/*----------------------------------------------------------------------------*/
64/*----------------------------------------------------------------------------*/
65
70double igamc(double, double);
71
72/*-----------------------------------------------------------------------------
73 BPM Parameters Definition
74 -----------------------------------------------------------------------------*/
75typedef struct {
76 HDRL_PARAMETER_HEAD;
77 int degree;
78 double pval;
79 double rel_chi_l;
80 double rel_chi_h;
81 double rel_coef_l;
82 double rel_coef_h;
83} hdrl_bpm_fit_parameter;
84
85/* Parameter type */
86static hdrl_parameter_typeobj hdrl_bpm_fit_parameter_type = {
87 HDRL_PARAMETER_BPM_FIT, /* type */
88 (hdrl_alloc *)&cpl_malloc, /* fp_alloc */
89 (hdrl_free *)&cpl_free, /* fp_free */
90 NULL, /* fp_destroy */
91 sizeof(hdrl_bpm_fit_parameter), /* obj_size */
92};
93
94
95/* ---------------------------------------------------------------------------*/
106/* ---------------------------------------------------------------------------*/
107static hdrl_parameter *
108hdrl_bpm_fit_parameter_create_all(int degree, double pval,
109 double rel_chi_l, double rel_chi_h,
110 double rel_coef_l, double rel_coef_h)
111{
112 hdrl_bpm_fit_parameter * p = (hdrl_bpm_fit_parameter *)
113 hdrl_parameter_new(&hdrl_bpm_fit_parameter_type);
114 p->degree = degree;
115 p->pval = pval;
116 p->rel_chi_l = rel_chi_l;
117 p->rel_chi_h = rel_chi_h;
118 p->rel_coef_l = rel_coef_l;
119 p->rel_coef_h = rel_coef_h;
120 if (hdrl_bpm_fit_parameter_verify((const hdrl_parameter *)p) ==
121 CPL_ERROR_NONE) {
122 return (hdrl_parameter *)p;
123 }
124 else {
125 hdrl_parameter_delete((hdrl_parameter*)p);
126 return NULL;
127 }
128}
129
132/* ---------------------------------------------------------------------------*/
140/* ---------------------------------------------------------------------------*/
141hdrl_parameter *
143{
144 return hdrl_bpm_fit_parameter_create_all(degree, pval, -1, -1, -1, -1);
145}
146
147/* ---------------------------------------------------------------------------*/
156/* ---------------------------------------------------------------------------*/
157hdrl_parameter *
159 double rel_chi_low, double rel_chi_high)
160{
161 return hdrl_bpm_fit_parameter_create_all(degree, -1,
162 rel_chi_low, rel_chi_high, -1, -1);
163}
164
165/* ---------------------------------------------------------------------------*/
174/* ---------------------------------------------------------------------------*/
175hdrl_parameter *
177 double rel_coef_low, double rel_coef_high)
178{
179 return hdrl_bpm_fit_parameter_create_all(degree, -1,
180 -1, -1, rel_coef_low, rel_coef_high);
181}
182
183/*----------------------------------------------------------------------------*/
189/*----------------------------------------------------------------------------*/
190cpl_boolean hdrl_bpm_fit_parameter_check(const hdrl_parameter * self)
191{
192 return hdrl_parameter_check_type(self, &hdrl_bpm_fit_parameter_type);
193}
194
195/* ---------------------------------------------------------------------------*/
201/* ---------------------------------------------------------------------------*/
202cpl_error_code hdrl_bpm_fit_parameter_verify(const hdrl_parameter * p)
203{
204 cpl_ensure(p, CPL_ERROR_NULL_INPUT, 0);
205 cpl_ensure(hdrl_bpm_fit_parameter_check(p),
206 CPL_ERROR_INCOMPATIBLE_INPUT, 0);
207 const hdrl_bpm_fit_parameter * par = (const hdrl_bpm_fit_parameter *)p;
208 int have_par = 0;
209 if (par->degree < 0) {
210 return cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
211 "degree must be positive");
212 }
213
214 if (par->pval >= 0) {
215 if (par->pval > 100.) {
216 return cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
217 "pval must be between 0 and 100%%");
218 }
219 have_par = 1;
220 }
221
222 if (par->rel_chi_l >= 0 || par->rel_chi_h >= 0) {
223 if (have_par) {
224 return cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
225 "Only one rejection criteria is allowed, "
226 "set the others to negative values");
227 }
228 if (!(par->rel_chi_l >= 0 && par->rel_chi_h >= 0)) {
229 return cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
230 "Upper and lower rejection criteria must be >= 0");
231 }
232 have_par = 1;
233 }
234
235 if (par->rel_coef_l >= 0 || par->rel_coef_h >= 0) {
236 if (have_par) {
237 return cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
238 "Only one rejection criteria is allowed, "
239 "set the others to negative values");
240 }
241 if (!(par->rel_coef_l >= 0 && par->rel_coef_h >= 0)) {
242 return cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
243 "Upper and lower rejection criteria must be >= 0");
244 }
245 have_par = 1;
246 }
247
248 if (!have_par) {
249 return cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
250 "Only no bad pixel parameter given, the chosen threshold "
251 "must have a value larger than zero");
252 }
253 return CPL_ERROR_NONE;
254}
255
256/* ---------------------------------------------------------------------------*/
262/* ---------------------------------------------------------------------------*/
263int hdrl_bpm_fit_parameter_get_degree(const hdrl_parameter * p)
264{
265 cpl_ensure(p, CPL_ERROR_NULL_INPUT, 0);
266 cpl_ensure(hdrl_bpm_fit_parameter_check(p),
267 CPL_ERROR_INCOMPATIBLE_INPUT, 0);
268 return ((const hdrl_bpm_fit_parameter *)p)->degree;
269}
270
271/* ---------------------------------------------------------------------------*/
277/* ---------------------------------------------------------------------------*/
278double hdrl_bpm_fit_parameter_get_pval( const hdrl_parameter * p)
279{
280 cpl_ensure(p, CPL_ERROR_NULL_INPUT, -1.);
281 cpl_ensure(hdrl_bpm_fit_parameter_check(p),
282 CPL_ERROR_INCOMPATIBLE_INPUT, -1.);
283 return ((const hdrl_bpm_fit_parameter *)p)->pval;
284}
285
286/* ---------------------------------------------------------------------------*/
292/* ---------------------------------------------------------------------------*/
293double hdrl_bpm_fit_parameter_get_rel_chi_low(const hdrl_parameter * p)
294{
295 cpl_ensure(p, CPL_ERROR_NULL_INPUT, -1.);
296 cpl_ensure(hdrl_bpm_fit_parameter_check(p),
297 CPL_ERROR_INCOMPATIBLE_INPUT, -1.);
298 return ((const hdrl_bpm_fit_parameter *)p)->rel_chi_l;
299}
300
301/* ---------------------------------------------------------------------------*/
307/* ---------------------------------------------------------------------------*/
308double hdrl_bpm_fit_parameter_get_rel_chi_high(const hdrl_parameter * p)
309{
310 cpl_ensure(p, CPL_ERROR_NULL_INPUT, -1.);
311 cpl_ensure(hdrl_bpm_fit_parameter_check(p),
312 CPL_ERROR_INCOMPATIBLE_INPUT, -1.);
313 return ((const hdrl_bpm_fit_parameter *)p)->rel_chi_h;
314}
315
316/* ---------------------------------------------------------------------------*/
322/* ---------------------------------------------------------------------------*/
323double hdrl_bpm_fit_parameter_get_rel_coef_low(const hdrl_parameter * p)
324{
325 cpl_ensure(p, CPL_ERROR_NULL_INPUT, -1.);
326 cpl_ensure(hdrl_bpm_fit_parameter_check(p),
327 CPL_ERROR_INCOMPATIBLE_INPUT, -1.);
328 return ((const hdrl_bpm_fit_parameter *)p)->rel_coef_l;
329}
330
331/* ---------------------------------------------------------------------------*/
337/* ---------------------------------------------------------------------------*/
338double hdrl_bpm_fit_parameter_get_rel_coef_high(const hdrl_parameter * p)
339{
340 cpl_ensure(p, CPL_ERROR_NULL_INPUT, -1.);
341 cpl_ensure(hdrl_bpm_fit_parameter_check(p),
342 CPL_ERROR_INCOMPATIBLE_INPUT, -1.);
343 return ((const hdrl_bpm_fit_parameter *)p)->rel_coef_h;
344}
345
346/*----------------------------------------------------------------------------*/
362/*----------------------------------------------------------------------------*/
364 const char *base_context,
365 const char *prefix,
366 const hdrl_parameter *defaults)
367{
368 cpl_ensure(prefix && base_context && defaults,
369 CPL_ERROR_NULL_INPUT, NULL);
370
371 cpl_ensure(hdrl_bpm_fit_parameter_check(defaults),
372 CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
373
374 cpl_parameterlist *parlist = cpl_parameterlist_new();
375
376 int degree_default = hdrl_bpm_fit_parameter_get_degree(defaults);
377 double pval_default = hdrl_bpm_fit_parameter_get_pval(defaults) ;
378 double rel_chi_low_default =
380 double rel_chi_high_default =
382 double rel_coef_low_default =
384 double rel_coef_high_default =
386
387 hdrl_setup_vparameter(parlist, prefix, ".", "", "degree", base_context,
388 "Degree of polynomial to fit.", CPL_TYPE_INT, degree_default);
389
390 hdrl_setup_vparameter(parlist, prefix, ".", "", "pval", base_context,
391 "p-value threshold (in percent). Fits with a p-value below "
392 "this threshold are considered bad pixels.",
393 CPL_TYPE_DOUBLE, pval_default);
394
395 hdrl_setup_vparameter(parlist, prefix, ".", "", "rel-chi-low", base_context,
396 "Relative chi threshold. Pixels with with a chi value "
397 "smaller than mean - rel-threshold * stdev-of-chi are "
398 "considered bad pixels.", CPL_TYPE_DOUBLE, rel_chi_low_default);
399
400 hdrl_setup_vparameter(parlist, prefix, ".", "", "rel-chi-high", base_context,
401 "Relative chi threshold. Pixels with with a chi value larger "
402 "than mean + rel-threshold * stdev-of-chi are "
403 "considered bad pixels.", CPL_TYPE_DOUBLE, rel_chi_high_default);
404
405 hdrl_setup_vparameter(parlist, prefix, ".", "", "rel-coef-low", base_context,
406 "Relative fit coefficient threshold. Pixels with with a "
407 "coefficient value smaller than "
408 "mean +- rel-threshold * stdev-of-coeff are "
409 "considered bad pixels.", CPL_TYPE_DOUBLE, rel_coef_low_default);
410
411 hdrl_setup_vparameter(parlist, prefix, ".", "", "rel-coef-high", base_context,
412 "Relative fit coefficient threshold. Pixels with with a "
413 "coefficient value larger than "
414 "mean +- rel-threshold * stdev-of-coeff are "
415 "considered bad pixels.", CPL_TYPE_DOUBLE, rel_coef_high_default);
416
417 if (cpl_error_get_code()) {
418 cpl_parameterlist_delete(parlist);
419 return NULL;
420 }
421
422 return parlist;
423}
424
425/*----------------------------------------------------------------------------*/
441/*----------------------------------------------------------------------------*/
443 const cpl_parameterlist * parlist,
444 const char * prefix)
445{
446 cpl_ensure(prefix && parlist, CPL_ERROR_NULL_INPUT, NULL);
447 char * name;
448 const cpl_parameter * par;
449 double pval = -1;
450 double rel_chi_l = -1;
451 double rel_chi_h = -1;
452 double rel_coef_l = -1;
453 double rel_coef_h = -1;
454 int degree;
455
456 name = hdrl_join_string(".", 2, prefix, "degree");
457 par = cpl_parameterlist_find_const(parlist, name);
458 if (par == NULL) {
459 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
460 "Parameter %s not found", name);
461 cpl_free(name);
462 return NULL;
463 }
464 degree = cpl_parameter_get_int(par);
465 cpl_free(name);
466
467 name = hdrl_join_string(".", 2, prefix, "pval");
468 par = cpl_parameterlist_find_const(parlist, name);
469 if (par) {
470 pval = cpl_parameter_get_double(par);
471 }
472 cpl_free(name) ;
473
474 name = hdrl_join_string(".", 2, prefix, "rel-chi-low");
475 par = cpl_parameterlist_find_const(parlist, name);
476 if (par) {
477 rel_chi_l = cpl_parameter_get_double(par);
478 }
479 cpl_free(name) ;
480
481 name = hdrl_join_string(".", 2, prefix, "rel-chi-high");
482 par = cpl_parameterlist_find_const(parlist, name);
483 if (par) {
484 rel_chi_h = cpl_parameter_get_double(par);
485 }
486 cpl_free(name) ;
487
488 name = hdrl_join_string(".", 2, prefix, "rel-coef-low");
489 par = cpl_parameterlist_find_const(parlist, name);
490 if (par) {
491 rel_coef_l = cpl_parameter_get_double(par);
492 }
493 cpl_free(name);
494
495 name = hdrl_join_string(".", 2, prefix, "rel-coef-high");
496 par = cpl_parameterlist_find_const(parlist, name);
497 if (par) {
498 rel_coef_h = cpl_parameter_get_double(par);
499 }
500 cpl_free(name);
501
502 if (cpl_error_get_code()) {
503 return NULL;
504 }
505 /* does verification */
506 return hdrl_bpm_fit_parameter_create_all(degree, pval,
507 rel_chi_l, rel_chi_h, rel_coef_l, rel_coef_h);
508}
509
510/* ---------------------------------------------------------------------------*/
520/* ---------------------------------------------------------------------------*/
521static cpl_image *
522bpm_from_rel(cpl_image * img, double kappa_low, double kappa_high, int mad)
523{
524 cpl_image * r;
525 double m, s;
526 if (mad) {
527 m = cpl_image_get_mad(img, &s);
528 s *= CPL_MATH_STD_MAD;
529 s = CX_MAX(DBL_EPSILON, s);
530 }
531 else {
532 m = cpl_image_get_mean(img);
533 s = cpl_image_get_stdev(img);
534 }
535 cpl_mask * bpm = cpl_mask_threshold_image_create(img, m - s * kappa_low,
536 m + s * kappa_high);
537 cpl_mask_not(bpm);
538 r = cpl_image_new_from_mask(bpm);
539 cpl_mask_delete(bpm);
540 return r;
541}
542
543
544
545/* ---------------------------------------------------------------------------*/
585/* ---------------------------------------------------------------------------*/
586cpl_error_code
587hdrl_bpm_fit_compute(const hdrl_parameter * par,
588 const hdrl_imagelist * data,
589 const cpl_vector * sample_pos,
590 cpl_image ** out_mask)
591{
592 cpl_image * out_chi2 = NULL, * out_dof = NULL;
593 hdrl_imagelist * out_coef = NULL;
594 if (hdrl_bpm_fit_parameter_verify(par) != CPL_ERROR_NONE)
595 return cpl_error_get_code();
596
597 int degree = hdrl_bpm_fit_parameter_get_degree(par);
598
599 /* TODO check for 0 error,
600 * in that case set to 1 and do not allow pval */
601
602 cpl_error_code err = hdrl_fit_polynomial_imagelist(data, sample_pos, degree,
603 &out_coef, &out_chi2, &out_dof);
604 if (err) {
605 return cpl_error_set_message(cpl_func, CPL_ERROR_FILE_NOT_FOUND,
606 "Fit failed");
607 }
608
609 if (cpl_image_count_rejected(out_chi2) ==
610 (cpl_image_get_size_x(out_chi2) * cpl_image_get_size_y(out_chi2))) {
611 cpl_msg_error(cpl_func, "Too few good pixels to fit polynomial of "
612 "degree %d in all pixels", degree);
613 goto end;
614 }
615
616 {
617 cpl_image * bpm = NULL;
618 double pval = hdrl_bpm_fit_parameter_get_pval(par);
619 double rel_chi_l = hdrl_bpm_fit_parameter_get_rel_chi_low(par);
620 double rel_chi_h = hdrl_bpm_fit_parameter_get_rel_chi_high(par);
621 double rel_coef_l = hdrl_bpm_fit_parameter_get_rel_coef_low(par);
622 double rel_coef_h = hdrl_bpm_fit_parameter_get_rel_coef_high(par);
623
624 if (rel_chi_l >= 0) {
625 /* chi is symmetric */
626 cpl_image_power(out_chi2, 0.5);
627 bpm = bpm_from_rel(out_chi2, rel_chi_l, rel_chi_h, 1);
628 }
629 else if (rel_coef_l >= 0) {
630 for (cpl_size i = 0; i < hdrl_imagelist_get_size(out_coef); i++) {
631 hdrl_image * coef = hdrl_imagelist_get(out_coef, i);
632 cpl_image * b = bpm_from_rel(hdrl_image_get_image(coef),
633 rel_coef_l, rel_coef_h, 0);
634
635 /* bits of bpm defines which coefficient "bad" */
636 if (bpm) {
637 cpl_image_multiply_scalar(b, pow(2, i));
638 cpl_image_add(bpm, b);
639 cpl_image_delete(b);
640 }
641 else {
642 bpm = b;
643 }
644 }
645 }
646 else if (pval >= 0) {
647 pval /= 100.;
648 bpm = cpl_image_new(cpl_image_get_size_x(out_chi2),
649 cpl_image_get_size_y(out_chi2),
650 CPL_TYPE_INT);
651 int * md = cpl_image_get_data_int(bpm);
652 hdrl_data_t * cd = cpl_image_get_data(out_chi2);
653 hdrl_data_t * dd = cpl_image_get_data(out_dof);
654 for (size_t i = 0; i < (size_t)cpl_image_get_size_x(out_chi2) *
655 cpl_image_get_size_y(out_chi2); i++) {
656 double pv = igamc(dd[i] / 2., cd[i] / 2.);
657 md[i] = (pv < pval);
658 }
659 }
660 *out_mask = bpm;
661 }
662
663end:
664 hdrl_imagelist_delete(out_coef);
665 cpl_image_delete(out_chi2);
666 cpl_image_delete(out_dof);
667
668 return cpl_error_get_code();
669}
670
hdrl_parameter * hdrl_bpm_fit_parameter_create_rel_coef(int degree, double rel_coef_low, double rel_coef_high)
create bpm_fit parameter with relative coefficient bpm treshold
Definition: hdrl_bpm_fit.c:176
hdrl_parameter * hdrl_bpm_fit_parameter_parse_parlist(const cpl_parameterlist *parlist, const char *prefix)
Parse a parameterlist to create input parameters for the BPM_FIT.
Definition: hdrl_bpm_fit.c:442
double hdrl_bpm_fit_parameter_get_rel_chi_high(const hdrl_parameter *p)
get relative chi distribution upper threshold
Definition: hdrl_bpm_fit.c:308
double hdrl_bpm_fit_parameter_get_rel_coef_high(const hdrl_parameter *p)
get relative fit coefficient distribution upper threshold
Definition: hdrl_bpm_fit.c:338
int hdrl_bpm_fit_parameter_get_degree(const hdrl_parameter *p)
get degree of polynomial fit of parameter
Definition: hdrl_bpm_fit.c:263
cpl_error_code hdrl_bpm_fit_parameter_verify(const hdrl_parameter *p)
verify that the parameter is a valid bpm_fit_parameter
Definition: hdrl_bpm_fit.c:202
cpl_parameterlist * hdrl_bpm_fit_parameter_create_parlist(const char *base_context, const char *prefix, const hdrl_parameter *defaults)
Create a parameter list for the BPM_FIT computation.
Definition: hdrl_bpm_fit.c:363
hdrl_parameter * hdrl_bpm_fit_parameter_create_pval(int degree, double pval)
create bpm_fit parameter with p-value bpm treshold
Definition: hdrl_bpm_fit.c:142
double hdrl_bpm_fit_parameter_get_pval(const hdrl_parameter *p)
get p-value bpm treshold
Definition: hdrl_bpm_fit.c:278
double hdrl_bpm_fit_parameter_get_rel_chi_low(const hdrl_parameter *p)
get relative chi distribution lower threshold
Definition: hdrl_bpm_fit.c:293
hdrl_parameter * hdrl_bpm_fit_parameter_create_rel_chi(int degree, double rel_chi_low, double rel_chi_high)
create bpm_fit parameter with relative chi bpm treshold
Definition: hdrl_bpm_fit.c:158
cpl_boolean hdrl_bpm_fit_parameter_check(const hdrl_parameter *self)
Check that the parameter is a bpm_fit parameter.
Definition: hdrl_bpm_fit.c:190
double hdrl_bpm_fit_parameter_get_rel_coef_low(const hdrl_parameter *p)
get relative fit coefficient distribution lower threshold
Definition: hdrl_bpm_fit.c:323
cpl_error_code hdrl_bpm_fit_compute(const hdrl_parameter *par, const hdrl_imagelist *data, const cpl_vector *sample_pos, cpl_image **out_mask)
compute bad pixel map based on fitting a stack of images
Definition: hdrl_bpm_fit.c:587
cpl_error_code hdrl_fit_polynomial_imagelist(const hdrl_imagelist *list, const cpl_vector *samplepos, const int degree, hdrl_imagelist **coef, cpl_image **chi2, cpl_image **dof)
weighted least squares polynomial fit of each pixel of a imagelist
Definition: hdrl_fit.c:367
cpl_image * hdrl_image_get_image(hdrl_image *himg)
get data as cpl image
Definition: hdrl_image.c:105
void hdrl_imagelist_delete(hdrl_imagelist *himlist)
Free all memory used by a hdrl_imagelist object including the images.
cpl_size hdrl_imagelist_get_size(const hdrl_imagelist *himlist)
Get the number of images in the imagelist.
hdrl_image * hdrl_imagelist_get(const hdrl_imagelist *himlist, cpl_size inum)
Get an image from a list of images.
void hdrl_parameter_delete(hdrl_parameter *obj)
shallow delete of a parameter
char * hdrl_join_string(const char *sep_, int n,...)
join strings together
Definition: hdrl_utils.c:812