CR2RE Pipeline Reference Manual 1.6.10
cr2res_bpm.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_bpm.h"
31#include "cr2res_utils.h"
32#include "cr2res_io.h"
33
34/*-----------------------------------------------------------------------------
35 Functions prototypes
36 -----------------------------------------------------------------------------*/
37
38static cpl_mask * cr2res_bpm_compute_global_stats(
39 cpl_image * img,
40 double kappa) ;
41static cpl_mask * cr2res_bpm_compute_local_stats(
42 cpl_image * img,
43 double kappa,
44 int size) ;
45static cpl_mask * cr2res_bpm_compute_running_filter(
46 cpl_image * img,
47 double kappa,
48 int size) ;
49
50/*----------------------------------------------------------------------------*/
54/*----------------------------------------------------------------------------*/
55
58cr2res_bpm_type bpm_types[CR2RES_NB_BPM_TYPES] = {
59 CR2RES_BPM_DARK,
60 CR2RES_BPM_FLAT,
61 CR2RES_BPM_DETLIN,
62 CR2RES_BPM_OUTOFORDER,
63 CR2RES_BPM_EDGEPIX};
64
65/*----------------------------------------------------------------------------*/
77/*----------------------------------------------------------------------------*/
79 cpl_image * in,
80 cr2res_bpm_method method,
81 double kappa,
82 double lines_ratio,
83 int clean_flag)
84{
85 cpl_mask * bpm ;
86 cpl_binary * pmask_cur ;
87 int nx, ny, j, k ;
88
89 /* Test entries */
90 if (in == NULL) return NULL ;
91
92 /* This first method works for SW, not L and M */
93 if (method == CR2RES_BPM_GLOBAL_STATS) {
94 if ((bpm = cr2res_bpm_compute_global_stats(in, kappa)) == NULL) {
95 cpl_msg_error(__func__, "Cannot create bad pixels map") ;
96 return NULL ;
97 }
98 } else if (method == CR2RES_BPM_LOCAL_STATS) {
99 if ((bpm = cr2res_bpm_compute_local_stats(in, kappa, 10)) == NULL) {
100 cpl_msg_error(__func__, "Cannot create bad pixels map") ;
101 return NULL ;
102 }
103 } else if (method == CR2RES_BPM_RUNNING_FILTER) {
104 if ((bpm = cr2res_bpm_compute_running_filter(in, kappa, 10)) == NULL) {
105 cpl_msg_error(__func__, "Cannot create bad pixels map") ;
106 return NULL ;
107 }
108 } else {
109 return NULL ;
110 }
111
112 /*
113 Post processing : Big zones of bad pixels are not considered as
114 bad pixels. Each line containing more than lines_ratio percent bad
115 pixels is reset to contain only good pixels.
116 */
117 nx = cpl_mask_get_size_x(bpm) ;
118 ny = cpl_mask_get_size_y(bpm) ;
119 pmask_cur = cpl_mask_get_data(bpm) ;
120 for (j=0 ; j<ny ; j++) {
121 int cur_bp_nb;
122 cur_bp_nb = cpl_mask_count_window(bpm, 1, j+1, nx, j+1) ;
123 /* Check if the line has too many bad pixels */
124 if (cur_bp_nb > lines_ratio * nx) {
125 /* Reset the bad pixels on the current line */
126 for (k=0 ; k<nx ; k++) {
127 pmask_cur[k+j*nx] = CPL_BINARY_0 ;
128 }
129 }
130 }
131
132 /* Clean the image using the computed BPM */
133 if (clean_flag) {
134 cpl_image_reject_from_mask(in, bpm) ;
135 cpl_detector_interpolate_rejected(in) ;
136 }
137
138 return bpm ;
139}
140/*----------------------------------------------------------------------------*/
147/*----------------------------------------------------------------------------*/
149 cpl_image * bpm,
150 cr2res_bpm_type type)
151{
152 cpl_image * tmp ;
153 int count ;
154
155 /* Check Entries */
156 if (bpm == NULL) return -1 ;
157
158 tmp = cpl_image_duplicate(bpm);
159 cpl_image_xor_scalar(tmp, NULL, type);
160 cpl_image_reject_value(tmp, CPL_VALUE_ZERO);
161 count = cpl_image_count_rejected(tmp);
162 cpl_image_delete(tmp);
163
164 return count ;
165}
166
167/*----------------------------------------------------------------------------*/
174/*----------------------------------------------------------------------------*/
176 cpl_mask * mask,
177 cr2res_bpm_type type)
178{
179 cpl_image * bpm_ima ;
180
181 /* Check Entries */
182 if (mask == NULL) return NULL ;
183
184 bpm_ima = cpl_image_new_from_mask(mask) ;
185 cpl_image_multiply_scalar(bpm_ima, type) ;
186 return bpm_ima ;
187}
188
189/*----------------------------------------------------------------------------*/
198/*----------------------------------------------------------------------------*/
200 cpl_image * in,
201 const char * bpm,
202 int chip,
203 int correct)
204{
205 cpl_image * bpm_im ;
206 cpl_mask * bpm_im_bin ;
207
208 /* Check entries */
209 if (in == NULL || bpm == NULL) return -1 ;
210 if (chip < 1 || chip > CR2RES_NB_DETECTORS) return -1 ;
211
212 /* Load the bpm */
213 if ((bpm_im = cr2res_io_load_BPM(bpm, chip, 1)) == NULL) {
214 cpl_msg_error(__func__, "Cannot load the bpm") ;
215 return -1 ;
216 }
217 /* Convert the map to binary */
218 bpm_im_bin = cpl_mask_threshold_image_create(bpm_im, -0.5, 0.5) ;
219 cpl_mask_not(bpm_im_bin) ;
220 cpl_image_delete(bpm_im) ;
221
222 /* Set the Bad pixels */
223 cpl_image_reject_from_mask(in, bpm_im_bin);
224 cpl_mask_delete(bpm_im_bin) ;
225
226 /* Apply the bad pixels cleaning */
227 if (correct) {
228 if (cpl_detector_interpolate_rejected(in) != CPL_ERROR_NONE) {
229 cpl_error_reset();
230 cpl_msg_error(__func__, "Cannot clean the BPM") ;
231 return -1 ;
232 }
233 }
234
235 return 0 ;
236}
237
238
239/*----------------------------------------------------------------------------*/
246/*----------------------------------------------------------------------------*/
248 const cpl_image * bpm_ima,
249 cr2res_bpm_type bpm_type)
250{
251 const int * pbpm_ima ;
252 cpl_mask * bpm ;
253 cpl_binary * pbpm ;
254 cpl_size i, j, nx, ny, idx ;
255
256 /* Check entries */
257 if (bpm_ima == NULL) return NULL ;
258
259 /* Initialize */
260 pbpm_ima = cpl_image_get_data_int_const(bpm_ima) ;
261 nx = cpl_image_get_size_x(bpm_ima) ;
262 ny = cpl_image_get_size_y(bpm_ima) ;
263
264 /* Create output mask */
265 bpm = cpl_mask_new(nx, ny) ;
266 pbpm = cpl_mask_get_data(bpm) ;
267
268 /* Loop on the pixels */
269 for (j=0 ; j<ny ; j++) {
270 for (i=0 ; i<nx ; i++) {
271 idx = i+j*ny ;
272 if (pbpm_ima[idx] & bpm_type) pbpm[idx] = CPL_BINARY_1 ;
273 }
274 }
275 return bpm ;
276}
277
278/*----------------------------------------------------------------------------*/
286/*----------------------------------------------------------------------------*/
288 cpl_image * bpm_ima,
289 cpl_mask * bpm,
290 int bpm_code)
291{
292 int * pbpm_ima ;
293 cpl_binary * pbpm ;
294 cpl_size i, j, nx, ny, idx ;
295
296 /* Check entries */
297 if (bpm_ima == NULL || bpm == NULL) return -1 ;
298 if (cpl_image_get_type(bpm_ima) != CPL_TYPE_INT) return -1 ;
299
300 /* Initialise */
301 nx = cpl_image_get_size_x(bpm_ima) ;
302 ny = cpl_image_get_size_y(bpm_ima) ;
303 if (nx != cpl_mask_get_size_x(bpm) || ny != cpl_mask_get_size_y(bpm))
304 return -1 ;
305 pbpm_ima = cpl_image_get_data_int(bpm_ima) ;
306 pbpm = cpl_mask_get_data(bpm) ;
307
308 /* Loop on the pixels */
309 for (j=0 ; j<ny ; j++) {
310 for (i=0 ; i<nx ; i++) {
311 idx = i+j*ny ;
312 if (pbpm[idx]) pbpm_ima[idx] = pbpm_ima[idx] | bpm_code ;
313 }
314 }
315 return 0 ;
316}
317
320/*----------------------------------------------------------------------------*/
327/*----------------------------------------------------------------------------*/
328static cpl_mask * cr2res_bpm_compute_global_stats(
329 cpl_image * img,
330 double kappa)
331{
332 cpl_mask * out ;
333 double low, high, med, sigma ;
334
335 /* Compute Thresholds */
336 med = cpl_image_get_median_dev(img, &sigma) ;
337 if (cpl_error_get_code()) {
338 cpl_msg_error(__func__, "Cannot compute statistics") ;
339 return NULL ;
340 }
341 low = med - kappa * sigma ;
342 high = med + kappa * sigma ;
343
344 cpl_msg_debug(__func__,
345 "Median %.1f, Sigma %.1f" "BPM_low %.1f, BPM_hi %.1f",
346 med, sigma, low, high);
347
348 /* Threshold to get the BPMs */
349 if ((out = cpl_mask_threshold_image_create(img, low, high)) == NULL) {
350 cpl_msg_error(__func__, "Cannot create bad pixels map") ;
351 return NULL ;
352 }
353 cpl_mask_not(out) ;
354
355 return out ;
356}
357
358/*----------------------------------------------------------------------------*/
366/*----------------------------------------------------------------------------*/
367static cpl_mask * cr2res_bpm_compute_local_stats(
368 cpl_image * img,
369 double kappa,
370 int size)
371{
372 cpl_mask * out ;
373 cpl_binary * pout ;
374 double threshold, med, sigma ;
375 int badpix;
376 cpl_size i, j, nx, ny, llx, lly, urx, ury ;
377
378 /* Check Entries */
379 if (img == NULL) return NULL ;
380 nx = cpl_image_get_size_x(img) ;
381 ny = cpl_image_get_size_y(img) ;
382
383 /* Create Output mask */
384 out = cpl_mask_new(nx, ny) ;
385 pout = cpl_mask_get_data(out) ;
386
387 /* Loop on the pixels */
388 for (i = 0; i < nx ; i++) {
389 for (j = 0; j < ny ; j++) {
390 llx = i+1-size ;
391 lly = j+1-size ;
392 urx = i+1+size ;
393 ury = j+1+size ;
394 if (llx < 1) llx = 1 ;
395 if (lly < 1) lly = 1 ;
396 if (urx > nx) urx = nx ;
397 if (ury > ny) ury = ny ;
398
399 /* Local statistics */
400 med = cpl_image_get_median_dev_window(img, llx, lly, urx,
401 ury, &sigma);
402
403 /* Compute Threshold */
404 threshold = med + kappa*sigma ;
405
406 /* Set Bad Pixel */
407 if (fabs(cpl_image_get(img, i+1, j+1, &badpix)) > threshold)
408 pout[i + j*nx] = CPL_BINARY_1 ;
409 }
410 }
411 return out;
412}
413
414/*----------------------------------------------------------------------------*/
428/*----------------------------------------------------------------------------*/
429static cpl_mask * cr2res_bpm_compute_running_filter(
430 cpl_image * img,
431 double kappa,
432 int size)
433{
434 cpl_mask * out ;
435 cpl_binary * pout ;
436 cpl_image * copy ;
437 cpl_mask * kernel ;
438 double mad, median;
439 int badpix;
440 double threshold;
441 cpl_size i, j, nx, ny ;
442
443 /* Check Entries */
444 if (img == NULL) return NULL ;
445 nx = cpl_image_get_size_x(img) ;
446 ny = cpl_image_get_size_y(img) ;
447 if (nx < size || ny < size) return NULL ;
448 if (size % 2 != 1) return NULL ;
449
450 /* Local copy */
451 copy = cpl_image_duplicate(img);
452
453 /* Filtering Kernel */
454 kernel = cpl_mask_new(size, 1);
455 cpl_mask_not(kernel);
456
457 /* Apply Filter */
458 cpl_image_filter_mask(copy, img, kernel, CPL_FILTER_MEDIAN,
459 CPL_BORDER_FILTER);
460 cpl_mask_delete(kernel);
461
462 /* Reject 0 values */
463 for (i = 1; i <= nx ; i++) {
464 for (j = 1; j <= ny ; j++) {
465 if (cpl_image_get(copy, i, j, &badpix) == 0)
466 cpl_image_reject(copy, i, j);
467 }
468 }
469
470 /* Subtract smoothed image */
471 cpl_image_subtract(copy, img);
472
473 /* Apply running thresholding */
474 median = cpl_image_get_mad(copy, &mad);
475 mad *= CPL_MATH_STD_MAD;
476 cpl_image_subtract_scalar(copy, median);
477 cpl_image_abs(copy);
478
479 threshold = kappa * mad;
480 out = cpl_mask_new(nx, ny) ;
481 pout = cpl_mask_get_data(out) ;
482
483 for (i = 0; i < nx ; i++) {
484 for (j = 0; j < ny ; j++) {
485 if (cpl_image_get(copy, i+1, j+1, &badpix) > threshold)
486 pout[i + j*nx] = CPL_BINARY_1 ;
487 }
488 }
489 cpl_image_delete(copy);
490 return out;
491}
492
493
494/*----------------------------------------------------------------------------*/
504/*----------------------------------------------------------------------------*/
505cpl_image * cr2res_bpm_mask_edgepix(cpl_image * bpm){
506 cpl_size i,j,sx,sy;
507 cpl_image * out;
508 out = cpl_image_duplicate(bpm);
509
510 sx = cpl_image_get_size_x(bpm);
511 sy = cpl_image_get_size_y(bpm);
512
513 // Image is too small for edgepixels, just keep it as it is
514 if ((sx <= CR2RES_NB_BPM_EDGEPIX+1) | (sy <= CR2RES_NB_BPM_EDGEPIX+1))
515 return out;
516
517 for (i=1; i<=sx; i++){
518 for (j=1; j<=CR2RES_NB_BPM_EDGEPIX; j++){
519 cpl_image_set(out,i,j,CR2RES_BPM_EDGEPIX);
520 cpl_image_set(out,i,CR2RES_DETECTOR_SIZE-j+1,CR2RES_BPM_EDGEPIX);
521 cpl_image_set(out,CR2RES_DETECTOR_SIZE-j+1,i,CR2RES_BPM_EDGEPIX);
522 cpl_image_set(out,j,i,CR2RES_BPM_EDGEPIX);
523 }
524 }
525 return out;
526};
int cr2res_bpm_add_mask(cpl_image *bpm_ima, cpl_mask *bpm, int bpm_code)
Add a mask to a BPM image with a dedicated code
Definition: cr2res_bpm.c:287
cpl_image * cr2res_bpm_from_mask(cpl_mask *mask, cr2res_bpm_type type)
Create a BPM from a mask.
Definition: cr2res_bpm.c:175
int cr2res_bpm_set_and_correct_image(cpl_image *in, const char *bpm, int chip, int correct)
Set the BPM and optionally apply the correction to an image.
Definition: cr2res_bpm.c:199
cpl_mask * cr2res_bpm_compute(cpl_image *in, cr2res_bpm_method method, double kappa, double lines_ratio, int clean_flag)
The BPM computation with min/max threshold.
Definition: cr2res_bpm.c:78
int cr2res_bpm_count(cpl_image *bpm, cr2res_bpm_type type)
Count BPM of a given type.
Definition: cr2res_bpm.c:148
cpl_mask * cr2res_bpm_extract_mask(const cpl_image *bpm_ima, cr2res_bpm_type bpm_type)
Extract a mask from a BPM image.
Definition: cr2res_bpm.c:247
cpl_image * cr2res_io_load_BPM(const char *filename, int detector, int data)
Load an image from a BPM.
Definition: cr2res_io.c:957