CR2RE Pipeline Reference Manual 1.6.10
hdrl_bpm_utils-test.c
1/*
2 * This file is part of the HDRL
3 * Copyright (C) 2013 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_bpm_utils.h"
29#include "hdrl_image.h"
30
31#include <cpl.h>
32#include <math.h>
33
34/*----------------------------------------------------------------------------*/
38/*----------------------------------------------------------------------------*/
39
40/*----------------------------------------------------------------------------*/
45/*----------------------------------------------------------------------------*/
46static cpl_error_code hdrl_bpm_test_bpm_to_mask(void)
47{
48 cpl_size nx = 20;
49 cpl_size ny = 20;
50 {
51 cpl_mask * mask = hdrl_bpm_to_mask(NULL, 0);
52 cpl_test_error(CPL_ERROR_NULL_INPUT);
53 cpl_test_null(mask);
54 }
55 /* non int input */
56 {
57 cpl_image * bpm = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
58 cpl_mask * mask = hdrl_bpm_to_mask(bpm, 0);
59 cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
60 cpl_test_null(mask);
61 cpl_image_delete(bpm);
62
63 /* too big mask */
64 bpm = cpl_image_new(nx, ny, CPL_TYPE_INT);
65 mask = hdrl_bpm_to_mask(bpm, ~0LLU);
66 cpl_test_null(mask);
67 cpl_test_error(CPL_ERROR_UNSUPPORTED_MODE);
68
69 cpl_image_delete(bpm);
70 }
71 /* empty bpm */
72 {
73 cpl_image * bpm = cpl_image_new(nx, ny, CPL_TYPE_INT);
74 cpl_mask * mask = hdrl_bpm_to_mask(bpm, 0);
75 cpl_test_nonnull(mask);
76 cpl_test_eq(cpl_mask_count(mask), 0);
77 cpl_image_delete(bpm);
78 cpl_mask_delete(mask);
79 }
80 /* range of codes */
81 {
82 cpl_image * bpm = cpl_image_new(nx, ny, CPL_TYPE_INT);
83 cpl_image_set(bpm, 1, 1, 1);
84 cpl_image_set(bpm, 1, 2, 2);
85 cpl_image_set(bpm, 1, 3, 3);
86 cpl_image_set(bpm, 1, 4, 4);
87
88 cpl_mask * mask;
89
90 mask = hdrl_bpm_to_mask(bpm, 1);
91 cpl_test_nonnull(mask);
92 cpl_test_eq(cpl_mask_count(mask), 2);
93 cpl_mask_delete(mask);
94
95 mask = hdrl_bpm_to_mask(bpm, ~0u);
96 cpl_test_error(CPL_ERROR_NONE);
97 cpl_test_nonnull(mask);
98 cpl_test_eq(cpl_mask_count(mask), 4);
99 cpl_mask_delete(mask);
100
101 cpl_image_delete(bpm);
102 }
103 return cpl_error_get_code();
104}
105
106/*----------------------------------------------------------------------------*/
111/*----------------------------------------------------------------------------*/
112static cpl_error_code hdrl_bpm_test_mask_to_bpm(void)
113{
114 cpl_size nx = 20;
115 cpl_size ny = 20;
116 {
117 cpl_image * bpm = hdrl_mask_to_bpm(NULL, 0);
118 cpl_test_error(CPL_ERROR_NULL_INPUT);
119 cpl_test_null(bpm);
120 }
121 /* empty mask */
122 {
123 cpl_image * bpm;
124 cpl_mask * mask = cpl_mask_new(nx, ny);
125 bpm = hdrl_mask_to_bpm(mask, 0);
126 cpl_test_nonnull(bpm);
127 cpl_test_eq(cpl_image_get_flux(bpm), 0);
128 cpl_image_delete(bpm);
129 cpl_mask_delete(mask);
130 }
131 /* non-empty mask */
132 {
133 cpl_mask * mask = cpl_mask_new(nx, ny);
134 cpl_mask_set(mask, 1, 1, CPL_BINARY_1);
135 cpl_mask_set(mask, 1, 2, CPL_BINARY_1);
136 cpl_mask_set(mask, 1, 3, CPL_BINARY_1);
137 cpl_mask_set(mask, 1, 4, CPL_BINARY_1);
138
139 cpl_image * bpm;
140
141 bpm = hdrl_mask_to_bpm(mask, 1);
142 cpl_test_nonnull(bpm);
143 cpl_test_eq(cpl_image_get_flux(bpm), 4);
144 cpl_image_delete(bpm);
145
146 bpm = hdrl_mask_to_bpm(mask, 5);
147 cpl_test_nonnull(bpm);
148 cpl_test_eq(cpl_image_get_flux(bpm), 5 * 4);
149 cpl_image_delete(bpm);
150
151 cpl_mask_delete(mask);
152 }
153 return cpl_error_get_code();
154}
155
156/*----------------------------------------------------------------------------*/
161/*----------------------------------------------------------------------------*/
162static cpl_error_code hdrl_bpm_test_hdrl_bpm_filter(void)
163{
164 cpl_mask *img_mask = cpl_mask_new(200, 300);
165
166 cpl_mask_set(img_mask, 50, 50, CPL_BINARY_1);
167 cpl_mask_set(img_mask, 100, 100, CPL_BINARY_1);
168 cpl_mask_set(img_mask, 150, 150, CPL_BINARY_1);
169 cpl_mask_set(img_mask, 100, 250, CPL_BINARY_1);
170 cpl_mask_set(img_mask, 100, 252, CPL_BINARY_1);
171 cpl_mask_set(img_mask, 100, 254, CPL_BINARY_1);
172 cpl_mask_set(img_mask, 100, 256, CPL_BINARY_1);
173 cpl_mask_set(img_mask, 102, 252, CPL_BINARY_1);
174 cpl_mask_set(img_mask, 102, 254, CPL_BINARY_1);
175 cpl_mask_set(img_mask, 102, 256, CPL_BINARY_1);
176 cpl_mask_set(img_mask, 198, 252, CPL_BINARY_1);
177 cpl_mask_set(img_mask, 198, 254, CPL_BINARY_1);
178 cpl_mask_set(img_mask, 198, 256, CPL_BINARY_1);
179 cpl_mask_set(img_mask, 200, 252, CPL_BINARY_1);
180 cpl_mask_set(img_mask, 200, 254, CPL_BINARY_1);
181 cpl_mask_set(img_mask, 200, 256, CPL_BINARY_1);
182 cpl_mask_set(img_mask, 199, 300, CPL_BINARY_1);
183 cpl_mask_set(img_mask, 199, 299, CPL_BINARY_1);
184 cpl_mask_set(img_mask, 199, 298, CPL_BINARY_1);
185 cpl_mask_set(img_mask, 200, 300, CPL_BINARY_1);
186 cpl_mask_set(img_mask, 200, 299, CPL_BINARY_1);
187 cpl_mask_set(img_mask, 200, 298, CPL_BINARY_1);
188 /*Test the border behaviour*/
189 cpl_mask_set(img_mask, 199, 200, CPL_BINARY_1);
190 cpl_mask_set(img_mask, 199, 198, CPL_BINARY_1);
191
192
193 /*cpl_mask_save(img_mask, "img_mask.fits", NULL, CPL_IO_CREATE);*/
194
195 {
196 cpl_mask *filtered_mask = hdrl_bpm_filter(img_mask, 3, 3, CPL_FILTER_CLOSING);
197
198 cpl_test_eq(cpl_mask_get(filtered_mask, 100, 255), CPL_BINARY_1);
199 cpl_test_eq(cpl_mask_get(filtered_mask, 101, 255), CPL_BINARY_1);
200 cpl_test_eq(cpl_mask_get(filtered_mask, 102, 255), CPL_BINARY_1);
201 cpl_test_eq(cpl_mask_get(filtered_mask, 103, 255), CPL_BINARY_0);
202
203 cpl_test_eq(cpl_mask_get(filtered_mask, 100, 251), CPL_BINARY_1);
204
205 cpl_test_eq(cpl_mask_get(filtered_mask, 198, 255), CPL_BINARY_1);
206 cpl_test_eq(cpl_mask_get(filtered_mask, 199, 255), CPL_BINARY_1);
207 cpl_test_eq(cpl_mask_get(filtered_mask, 200, 255), CPL_BINARY_1);
208
209 cpl_test_eq(cpl_mask_get(filtered_mask, 198, 254), CPL_BINARY_1);
210 cpl_test_eq(cpl_mask_get(filtered_mask, 199, 254), CPL_BINARY_1);
211 cpl_test_eq(cpl_mask_get(filtered_mask, 200, 254), CPL_BINARY_1);
212
213 /*Test the border behaviour*/
214 cpl_test_eq(cpl_mask_get(filtered_mask, 200, 199), CPL_BINARY_0);
215
216 /*cpl_mask_save(filtered_mask, "filtered_closing_mask.fits", NULL,
217 CPL_IO_CREATE);*/
218 cpl_mask_delete(filtered_mask);
219 }
220
221 /* free the memory */
222 cpl_mask_delete(img_mask);
223
224 return cpl_error_get_code();
225}
226
227/*----------------------------------------------------------------------------*/
233/*----------------------------------------------------------------------------*/
234static cpl_error_code hdrl_bpm_test_bpmgrow(void)
235{
236 const char* img_mask_name = "img_mask.fits";
237 const char* filtered_morpho_mask_name = "filtered_morpho_mask.fits";
238 const char* filtered_average_mask_name = "filtered_average_mask.fits";
239 const char* file_gauss_name = "gauss.fits";
240 const char* filtered_gauss_data_name = "filtered_gauss_data.fits";
241 const char* filtered_gauss_mask_name = "filtered_gauss_mask.fits";
242
243
244 cpl_mask *img_mask = cpl_mask_new(200, 300);
245
246 cpl_mask_set(img_mask, 50, 50, CPL_BINARY_1);
247 cpl_mask_set(img_mask, 100, 100, CPL_BINARY_1);
248 cpl_mask_set(img_mask, 150, 150, CPL_BINARY_1);
249 cpl_mask_set(img_mask, 100, 250, CPL_BINARY_1);
250 cpl_mask_set(img_mask, 100, 252, CPL_BINARY_1);
251 cpl_mask_set(img_mask, 100, 254, CPL_BINARY_1);
252 cpl_mask_set(img_mask, 100, 256, CPL_BINARY_1);
253 cpl_mask_set(img_mask, 102, 252, CPL_BINARY_1);
254 cpl_mask_set(img_mask, 102, 254, CPL_BINARY_1);
255 cpl_mask_set(img_mask, 102, 256, CPL_BINARY_1);
256 cpl_mask_set(img_mask, 198, 252, CPL_BINARY_1);
257 cpl_mask_set(img_mask, 198, 254, CPL_BINARY_1);
258 cpl_mask_set(img_mask, 198, 256, CPL_BINARY_1);
259 cpl_mask_set(img_mask, 200, 252, CPL_BINARY_1);
260 cpl_mask_set(img_mask, 200, 254, CPL_BINARY_1);
261 cpl_mask_set(img_mask, 200, 256, CPL_BINARY_1);
262 cpl_mask_set(img_mask, 199, 300, CPL_BINARY_1);
263 cpl_mask_set(img_mask, 199, 299, CPL_BINARY_1);
264 cpl_mask_set(img_mask, 199, 298, CPL_BINARY_1);
265 cpl_mask_set(img_mask, 200, 300, CPL_BINARY_1);
266 cpl_mask_set(img_mask, 200, 299, CPL_BINARY_1);
267 cpl_mask_set(img_mask, 200, 298, CPL_BINARY_1);
268
269 cpl_mask_save(img_mask, "img_mask.fits", NULL, CPL_IO_CREATE);
270
271 if(1){
272 /* Set all pixels to bad, if there are a predefined number of bad
273 * pixels in the neighborhood - it uses the morpho filter which
274 * is much slower than e.g. the CPL_FILTER_AVERAGE_FAST filter */
275
276 cpl_matrix * kernel = cpl_matrix_new(3, 3);
277 cpl_matrix_fill(kernel, 1.0);
278 cpl_image * result_data = cpl_image_new_from_mask(img_mask);
279
280 cpl_image * filtered_data = cpl_image_new(
281 cpl_image_get_size_x(result_data),
282 cpl_image_get_size_y(result_data),
283 CPL_TYPE_FLOAT);
284
285 cpl_image_filter(filtered_data, result_data, kernel,
286 CPL_FILTER_MORPHO_SCALE, CPL_BORDER_FILTER);
287
288
289 cpl_mask * filtered_mask = cpl_mask_threshold_image_create(
290 filtered_data, 3.-0.5, DBL_MAX);
291
292 cpl_mask_save(filtered_mask, filtered_morpho_mask_name, NULL,
293 CPL_IO_CREATE);
294
295 cpl_mask_delete(filtered_mask);
296 cpl_image_delete(result_data);
297 cpl_image_delete(filtered_data);
298 cpl_matrix_delete(kernel);
299
300 }
301
302 if(1){
303 /* Set all pixels to bad, if there are a predefined number of bad
304 * pixels in the neighborhood - it uses the CPL_FILTER_AVERAGE_FAST
305 * filter. This filter is fast but shrinks the window at the border.
306 * Therefore a simple scaling to the number of bad pixels in the
307 * neighborhood (nx * ny * average) can not be done at the image-border.
308 * Nevertheless one can never detect less, but only more neighboring
309 * bad pixels near the border (the bad pixel density increases at the
310 * border as the windows shrinks) -
311 * so it would be a conservative approach.
312 *
313 * */
314
315 cpl_mask * kernel = cpl_mask_new(3, 3);
316 cpl_mask_not(kernel); /* All values set to unity*/
317
318
319 cpl_image * result_data = cpl_image_new_from_mask(img_mask);
320
321 cpl_image * filtered_data = cpl_image_new(
322 cpl_image_get_size_x(result_data),
323 cpl_image_get_size_y(result_data),
324 CPL_TYPE_FLOAT);
325
326
327
328 cpl_image_filter_mask(filtered_data, result_data, kernel,
329 CPL_FILTER_AVERAGE_FAST, CPL_BORDER_FILTER);
330
331
332
333 cpl_mask * filtered_mask = cpl_mask_threshold_image_create(
334 filtered_data, (3.-0.5)/(3.*3.), DBL_MAX);
335
336
337 cpl_mask_save(filtered_mask, filtered_average_mask_name, NULL, CPL_IO_CREATE);
338
339 cpl_mask_delete(filtered_mask);
340 cpl_image_delete(result_data);
341 cpl_image_delete(filtered_data);
342 cpl_mask_delete(kernel);
343
344 }
345
346 if(1){
347 /* This algo first smoothed the bad pixels by a gaussian kernel and
348 * then one can use a threshold to detect new bad pixels on the
349 * smoothed image. Here it is difficult to find good parameters for the
350 * gaussian and the subsequent thresholding.
351 * */
352
353 double sig_x = 3.; /*Sigma in x for the gaussian distribution.*/
354 double sig_y = 3.; /*Sigma in y for the gaussian distribution.*/
355
356
357 /* creating the Gaussian kernel */
358 cpl_size n = 5;
359 cpl_image * gauss = cpl_image_new(2 * n + 1, 2 * n + 1, CPL_TYPE_DOUBLE);
360
361 cpl_image_fill_gaussian(gauss, n + 1, n + 1, (double)121.0, sig_x, sig_y);
362
363 /* filtering the image */
364 cpl_matrix * kernel = cpl_matrix_wrap(2 * n + 1, 2 * n + 1,
365 cpl_image_get_data_double(gauss));
366 /*cpl_image_filter(im1, im2, gauss_data, CPL_FILTER_LINEAR,
367 CPL_BORDER_FILTER);*/
368
369 /*cpl_matrix * kernel = cpl_matrix_new(3, 3);
370 cpl_matrix_fill(kernel, 1.0);*/
371
372 cpl_image * result_data = cpl_image_new_from_mask(img_mask);
373
374 cpl_image * filtered_data = cpl_image_new(
375 cpl_image_get_size_x(result_data),
376 cpl_image_get_size_y(result_data),
377 CPL_TYPE_DOUBLE);
378
379 cpl_image_filter(filtered_data, result_data, kernel,
380 CPL_FILTER_LINEAR, CPL_BORDER_FILTER);
381
382
383 cpl_mask * filtered_mask = cpl_mask_threshold_image_create(
384 filtered_data, 3.-0.5, DBL_MAX);
385
386 cpl_image_save(filtered_data, filtered_gauss_data_name,
387 CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
388 cpl_image_save(gauss, file_gauss_name,
389 CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE);
390
391 cpl_mask_save(filtered_mask, filtered_gauss_mask_name, NULL, CPL_IO_CREATE);
392
393 cpl_matrix_unwrap(kernel);
394 cpl_image_delete(gauss);
395 cpl_mask_delete(filtered_mask);
396 cpl_image_delete(result_data);
397 cpl_image_delete(filtered_data);
398 }
399
400 /* free the memory */
401 cpl_mask_delete(img_mask);
402
403 /* Remove to disk */
404 remove(img_mask_name);
405 remove(filtered_morpho_mask_name);
406 remove(filtered_average_mask_name);
407 remove(file_gauss_name);
408 remove(filtered_gauss_data_name);
409 remove(filtered_gauss_mask_name);
410
411 return cpl_error_get_code();
412}
413
414/*----------------------------------------------------------------------------*/
420/*----------------------------------------------------------------------------*/
421static cpl_error_code hdrl_bpm_test_apply_masks_to_imagelist(void)
422{
423 #define NUM_IMAGES 2
424
425 int nx = 64;
426 int ny = 64;
427
428
429 /* Create a imagelist */
430 cpl_image *img = cpl_image_fill_test_create(nx, ny);
431 cpl_imagelist *list = cpl_imagelist_new();
432 for (cpl_size i=0; i < NUM_IMAGES; i++) {
433 cpl_imagelist_set(list, cpl_image_duplicate(img), i);
434 }
435 cpl_image_delete(img);
436
437
438 /* join masks -> fill with a new allocated mask the vector*/
439 cpl_mask *new_mask = cpl_mask_new(nx, ny);
440 cpl_mask **orig_masks;
441 hdrl_join_mask_on_imagelist(list, new_mask, &orig_masks);
442 cpl_mask_delete(new_mask);
443
444
445 /* restore original mask */
446 hdrl_set_masks_on_imagelist(list, orig_masks);
447
448
449 /* free memory */
450 cpl_imagelist_delete(list);
451 for (cpl_size i = 0; i < NUM_IMAGES; i++) {
452 cpl_mask_delete(orig_masks[i]);
453 }
454 cpl_free(orig_masks);
455
456 return CPL_ERROR_NONE;
457}
458
459
460/*----------------------------------------------------------------------------*/
464/*----------------------------------------------------------------------------*/
465int main(void)
466{
467 cpl_test_init(PACKAGE_BUGREPORT, CPL_MSG_WARNING);
468
469 hdrl_bpm_test_bpm_to_mask();
470 hdrl_bpm_test_mask_to_bpm();
471 hdrl_bpm_test_hdrl_bpm_filter();
472 hdrl_bpm_test_bpmgrow() ;
473 hdrl_bpm_test_apply_masks_to_imagelist();
474
475 cpl_test_error(CPL_ERROR_NONE);
476
477 return cpl_test_end(0);
478}
cpl_image * hdrl_mask_to_bpm(const cpl_mask *mask, uint64_t flag)
convert cpl_mask to bad pixel information mask
cpl_mask * hdrl_bpm_to_mask(const cpl_image *bpm, uint64_t selection)
convert bad pixel information mask to a cpl_mask
cpl_mask * hdrl_bpm_filter(const cpl_mask *input_mask, cpl_size kernel_nx, cpl_size kernel_ny, cpl_filter_mode filter)
Allows the growing and shrinking of bad pixel masks. It can be used to e.g. set pixels to bad if the ...
cpl_error_code hdrl_join_mask_on_imagelist(cpl_imagelist *list, cpl_mask *new_mask, cpl_mask ***pold_mask)
join mask with existing masks in an imagelist
cpl_error_code hdrl_set_masks_on_imagelist(cpl_imagelist *list, cpl_mask **masks)
apply array of masks to an image list