CR2RE Pipeline Reference Manual 1.6.2
hdrl_fpn-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/*----------------------------------------------------------------------------*/
28/*----------------------------------------------------------------------------*/
29
30#include "hdrl_fpn.h"
31
32#include "hdrl_random.h"
33#include "hdrl_bpm_utils.h"
34
35#include <cpl.h>
36#include <complex.h>
37
38
39/*----------------------------------------------------------------------------*/
43/*----------------------------------------------------------------------------*/
44
45#define HDRL_DELTA_COMPARE_QC HDRL_EPS_DATA * 2.0e1
46#define HDRL_DELTA_COMPARE_IMAGE HDRL_EPS_DATA * 1.5e1
47
48
49#define HDRL_FPN_TEST_EVEN_IMG_OUT "even_img_out.fits"
50#define HDRL_FPN_TEST_EVEN_MASK_OUT "even_mask_out.fits"
51
52#define HDRL_FPN_TEST_ODD_IMG_OUT "odd_img_out.fits"
53#define HDRL_FPN_TEST_ODD_MASK_OUT "odd_mask_out.fits"
54
55#define HDRL_FPN_TEST_FILTER_IMG_OUT "filter_img_out.fits"
56#define HDRL_FPN_TEST_FILTER_MASK_OUT "filter_mask_out.fits"
57
58#define HDRL_FPN_TEST_FILTER_MASK_IMG_OUT "filter_with_mask_img_out.fits"
59#define HDRL_FPN_TEST_FILTER_MASK_MASK_OUT "filter_with_mask_mask_out.fits"
60
61
62const double const_even_img[][4] = {
63 { 0.84, -0.27, 0.07, 0.74 },
64 { 0.57, -0.265, -0.07, 0.32 },
65 { 0.25, -0.268, 0.07, 0.72 },
66 { -0.9, -0.2, -0.05, 0.57 }
67};
68
69const double const_odd_img[][5] = {
70 { 0.84, -0.27, 0.07, 0.74, 0.28 },
71 { -1.2, -0.255, -0.06, 0.65, 0.74 },
72 { -1.5, -0.25, 0.06, 0.64, 0.63 },
73 { -0.84, -0.248, -0.06, -0.63, 0.56 },
74 { -0.9, -0.2, -0.05, 0.57, -1.05 }
75};
76
77const double const_filter_img[][5] = {
78 { 0.84, -0.27, 0.07, 0.74, 0.28 },
79 { 0.57, -0.265, -0.07, 0.32, 0.37 },
80 { 0.25, -0.268, 0.07, 0.72, 0.47 },
81 { -1.2, -0.255, -0.06, 0.65, 0.74 },
82 { -1.5, -0.25, 0.06, 0.64, 0.63 },
83 { -0.84, -0.248, -0.06, -0.63, 0.56 },
84 { 0.84, -0.236, 0.06, 0.59, 0.26 },
85 { 0.94, -0.244, -0.06, 0.69, -0.16 },
86 { -0.84, -0.23, 0.05, 0.43, -0.50 },
87 { -0.9, -0.2, -0.05, 0.57, -1.05 }
88};
89
90const double const_even_img_out_python[][4] = {
91 { 0.2827580625, 0.1036180625, 0.2962080625, 0.1036180625 },
92 { 0.7368880625, 0.1449405625, 0.1099405625, 0.1804230625 },
93 { 0.0200930625, 0.2151505625, 0.0874680625, 0.2151505625 },
94 { 0.7368880625, 0.1804230625, 0.1099405625, 0.1449405625 }
95};
96
97const double const_odd_img_out_python[][5] = {
98 { 0.12013156, 0.383159364837234, 0.265579755162766, 0.265579755162766, 0.383159364837234 },
99 { 1.54915433534651, 0.400709353348878, 0.29934484816896, 0.369019554281073, 0.0991814702143874 },
100 { 0.359162784653486, 0.467499565718927, 0.400883766651123, 0.0112476497856126, 0.72090627183104 },
101 { 0.359162784653486, 0.72090627183104, 0.0112476497856126, 0.400883766651123, 0.467499565718927 },
102 { 1.54915433534651, 0.0991814702143874, 0.369019554281073, 0.29934484816896, 0.400709353348878 }
103};
104
105const double const_filter_img_out_python[][10] = {
106 { 0.08193152, 0.063075752708677, 0.822150095300018, 0.344980107291323, 0.0179478446999824, 0.28697888, 0.0179478446999824, 0.344980107291323, 0.822150095300018, 0.0630757527086773 },
107 { 1.58489635987986, 0.220252697693417, 0.896622688396041, 0.0654115585573622, 0.0653615133387257, 0.0349653602187383, 0.0286088875424546, 0.0741165605524927, 0.633926559509007, 0.179705468727281 },
108 { 0.089400680120138, 0.595806301442638, 0.211423052457545, 0.125587391272719, 0.156505251603959, 0.0308983997812617, 0.0250233804909936, 0.0969931623065833, 0.786391426661275, 0.722799299447507 },
109 { 0.089400680120138, 0.722799299447507, 0.786391426661275, 0.0969931623065836, 0.0250233804909936, 0.0308983997812617, 0.156505251603959, 0.125587391272719, 0.211423052457545, 0.595806301442638 },
110 { 1.58489635987986, 0.179705468727281, 0.633926559509007, 0.0741165605524925, 0.0286088875424546, 0.0349653602187383, 0.0653615133387257, 0.0654115585573621, 0.896622688396041, 0.220252697693417 }
111};
112
113
114
115/*----------------------------------------------------------------------------*/
120/*----------------------------------------------------------------------------*/
121
122/*----------------------------------------------------------------------------*/
127/*----------------------------------------------------------------------------*/
128static void hdrl_fpn_tests(void)
129{
130 /*** Create DUMMY images ***/
131
132 /* Even image */
133 cpl_size even_img_nx = 4;
134 cpl_size even_img_ny = 4;
135 cpl_image *even_img = cpl_image_new(even_img_nx, even_img_ny, CPL_TYPE_DOUBLE);
136 for(cpl_size x = 0; x < even_img_nx; x++){
137 for(cpl_size y = 0; y < even_img_ny; y++){
138 cpl_image_set(even_img, x + 1, y + 1, const_even_img[x][y]);
139 }
140 }
141 /* cpl_image_save(even_img, "even_img_in.fits", CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE); */
142
143 /* Odd image */
144 cpl_size odd_img_nx = 5;
145 cpl_size odd_img_ny = 5;
146 cpl_image *odd_img = cpl_image_new(odd_img_nx, odd_img_ny, CPL_TYPE_DOUBLE);
147 for(cpl_size x = 0; x < odd_img_nx; x++){
148 for(cpl_size y = 0; y < odd_img_ny; y++){
149 cpl_image_set(odd_img, x + 1, y + 1, const_odd_img[x][y]);
150 }
151 }
152 /* cpl_image_save(odd_img, "odd_img_in.fits", CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE); */
153
154 /* Filter image */
155 cpl_size filter_img_nx = 10;
156 cpl_size filter_img_ny = 5;
157 cpl_image *filter_img = cpl_image_new(filter_img_nx, filter_img_ny, CPL_TYPE_DOUBLE);
158 for(cpl_size x = 0; x < filter_img_nx; x++){
159 for(cpl_size y = 0; y < filter_img_ny; y++){
160 cpl_image_set(filter_img, x + 1, y + 1, const_filter_img[x][y]);
161 }
162 }
163 /* cpl_image_save(filter_img, "filter_img_in.fits", CPL_TYPE_DOUBLE, NULL, CPL_IO_CREATE); */
164
165
166 /*** Output variables ***/
167 cpl_image *out_img = NULL;
168 cpl_image *out_mask;
169 cpl_propertylist *qclist;
170 double rms;
171 double mad;
172 int null;
173
174
175 /*** TESTS: Non-valid inputs ***/
176
177 /* Null img_in */
178 hdrl_fpn_compute(NULL, NULL, 1, 1, &out_img, &rms, &mad);
179 cpl_test_error(CPL_ERROR_NULL_INPUT);
180
181 /* Bad dc_mask_x */
182 hdrl_fpn_compute(filter_img, NULL, 0, 1, &out_img, &rms, &mad);
183 cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
184
185 /* Bad dc_mask_y */
186 hdrl_fpn_compute(filter_img, NULL, 1, 0, &out_img, &rms, &mad);
187 cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
188
189 /* Bad power_spectrum in the input */
190 cpl_image *in_img_dummy = cpl_image_new(2, 2, CPL_TYPE_DOUBLE);
191 hdrl_fpn_compute(filter_img, NULL, 1, 1, &in_img_dummy, &rms, &mad);
192 cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
193 cpl_image_delete(in_img_dummy);
194
195 /* Bad img_in because contain reject pixels */
196 cpl_image *filter_img_reject = cpl_image_duplicate(filter_img);
197 cpl_image_reject(filter_img_reject, 1, 1);
198 hdrl_fpn_compute(filter_img_reject, NULL, 1, 1, &out_img, &rms, &mad);
199 cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
200 cpl_image_delete(filter_img_reject);
201
202 /* Bad size in the input mask */
203 cpl_mask *mask_wrong_img = cpl_mask_new(filter_img_nx - 1, filter_img_ny - 1);
204 hdrl_fpn_compute(filter_img, mask_wrong_img, 1, 1, &out_img, &rms, &mad);
205 cpl_test_error(CPL_ERROR_INCOMPATIBLE_INPUT);
206 cpl_mask_delete(mask_wrong_img);
207
208
209 /*** TEST: Even image ***/
210 out_img = NULL;
211 hdrl_fpn_compute(even_img, NULL, 1, 1, &out_img, &rms, &mad);
212 cpl_test_error(CPL_ERROR_NONE);
213 cpl_test_nonnull(out_img);
214
215 /* Test files with python output (See python fpn code at the end of this function) */
216 out_mask = cpl_image_new_from_mask(cpl_image_get_bpm(out_img));
217 qclist = cpl_propertylist_new();
218 cpl_propertylist_update_double(qclist, "ESO QC FPN RMS", rms);
219 cpl_propertylist_update_double(qclist, "ESO QC FPN MAD", mad);
220 cpl_image_save(out_img, HDRL_FPN_TEST_EVEN_IMG_OUT, CPL_TYPE_DOUBLE, qclist, CPL_IO_CREATE);
221 cpl_image_save(out_mask, HDRL_FPN_TEST_EVEN_MASK_OUT, CPL_TYPE_DOUBLE, qclist, CPL_IO_CREATE);
222
223 /* cpl_msg_info(cpl_func, "EVEN image -> rms=%g, mad=%g", rms, mad); */
224 cpl_test_rel(rms, 0.217609641787739, HDRL_DELTA_COMPARE_QC);
225 cpl_test_rel(mad, 0.0612647385, HDRL_DELTA_COMPARE_QC);
226
227 /* Test output values with python */
228 for(cpl_size x = 0; x < even_img_nx; x++){
229 for(cpl_size y = 0; y < even_img_ny; y++){
230 if (!cpl_image_get(out_mask, x + 1, y + 1, &null)) {
231 cpl_test_rel(cpl_image_get(out_img, x + 1, y + 1, &null), const_even_img_out_python[y][x], HDRL_DELTA_COMPARE_IMAGE);
232 }
233 }
234 }
235
236 cpl_image_delete( out_img );
237 cpl_image_delete( out_mask );
238 cpl_propertylist_delete( qclist );
239 cpl_image_delete( even_img );
240
241
242 /*** TEST: Odd image ***/
243 out_img = NULL;
244 hdrl_fpn_compute(odd_img, NULL, 1, 1, &out_img, &rms, &mad);
245 cpl_test_error(CPL_ERROR_NONE);
246 cpl_test_nonnull(out_img);
247
248 /* Test files with python output (See python fpn code at the end of this function) */
249 out_mask = cpl_image_new_from_mask(cpl_image_get_bpm(out_img));
250 qclist = cpl_propertylist_new();
251 cpl_propertylist_update_double(qclist, "ESO QC FPN RMS", rms);
252 cpl_propertylist_update_double(qclist, "ESO QC FPN MAD", mad);
253 cpl_image_save(out_img, HDRL_FPN_TEST_ODD_IMG_OUT, CPL_TYPE_DOUBLE, qclist, CPL_IO_CREATE);
254 cpl_image_save(out_mask, HDRL_FPN_TEST_ODD_MASK_OUT, CPL_TYPE_DOUBLE, qclist, CPL_IO_CREATE);
255
256 /* cpl_msg_info(cpl_func, "ODD image -> rms=%g, mad=%g", rms, mad); */
257 cpl_test_rel(rms, 0.381960894533284, HDRL_DELTA_COMPARE_QC);
258 cpl_test_rel(mad, 0.124653092119791, HDRL_DELTA_COMPARE_QC);
259
260 /* Test output values with python */
261 for(cpl_size x = 0; x < odd_img_nx; x++){
262 for(cpl_size y = 0; y < odd_img_ny; y++){
263 if (!cpl_image_get(out_mask, x + 1, y + 1, &null)) {
264 cpl_test_rel(cpl_image_get(out_img, x + 1, y + 1, &null), const_odd_img_out_python[y][x], HDRL_DELTA_COMPARE_IMAGE);
265 }
266 }
267 }
268
269 cpl_image_delete( out_img );
270 cpl_image_delete( out_mask );
271 cpl_propertylist_delete( qclist );
272 cpl_image_delete( odd_img );
273
274
275
276 /*** TEST: filter image ***/
277 out_img = NULL;
278 hdrl_fpn_compute(filter_img, NULL, 3, 3, &out_img, &rms, &mad);
279 cpl_test_error(CPL_ERROR_NONE);
280 cpl_test_nonnull(out_img);
281
282 /* Duplicate mask for the TEST: filter image with mask */
283 cpl_mask *filter_mask = cpl_mask_duplicate(cpl_image_get_bpm(out_img));
284
285 /* Test files with python output (See python fpn code at the end of this function) */
286 out_mask = cpl_image_new_from_mask(cpl_image_get_bpm(out_img));
287 qclist = cpl_propertylist_new();
288 cpl_propertylist_update_double(qclist, "ESO QC FPN RMS", rms);
289 cpl_propertylist_update_double(qclist, "ESO QC FPN MAD", mad);
290 cpl_image_save(out_img, HDRL_FPN_TEST_FILTER_IMG_OUT, CPL_TYPE_DOUBLE, qclist, CPL_IO_CREATE);
291 cpl_image_save(out_mask, HDRL_FPN_TEST_FILTER_MASK_OUT, CPL_TYPE_DOUBLE, qclist, CPL_IO_CREATE);
292
293 /* cpl_msg_info(cpl_func, "FILTER image -> rms=%g, mad=%g", rms, mad); */
294 cpl_test_rel(rms, 0.346571043362885, HDRL_DELTA_COMPARE_QC);
295 cpl_test_rel(mad, 0.140385898785234, HDRL_DELTA_COMPARE_QC);
296
297 /* Test output values with python */
298 for(cpl_size x = 0; x < filter_img_nx; x++){
299 for(cpl_size y = 0; y < filter_img_ny; y++){
300 if (!cpl_image_get(out_mask, x + 1, y + 1, &null)) {
301 cpl_test_rel(cpl_image_get(out_img, x + 1, y + 1, &null), const_filter_img_out_python[y][x], HDRL_DELTA_COMPARE_IMAGE);
302 }
303 }
304 }
305
306 cpl_image_delete( out_img );
307 cpl_image_delete( out_mask );
308 cpl_propertylist_delete( qclist );
309
310
311 /*** TEST: filter image with mask ***/
312 out_img = NULL;
313 cpl_mask_set(filter_mask, 1, 1, CPL_BINARY_0); /* Unset the peak */
314 hdrl_fpn_compute(filter_img, filter_mask, 1, 1, &out_img, &rms, &mad);
315 cpl_test_error(CPL_ERROR_NONE);
316 cpl_test_nonnull(out_img);
317
318 /* Test files with python output (See python fpn code at the end of this function) */
319 const cpl_mask *out_filter_mask = cpl_image_get_bpm(out_img);
320 out_mask = cpl_image_new_from_mask(out_filter_mask);
321 qclist = cpl_propertylist_new();
322 cpl_propertylist_update_double(qclist, "ESO QC FPN RMS", rms);
323 cpl_propertylist_update_double(qclist, "ESO QC FPN MAD", mad);
324 cpl_image_save(out_img, HDRL_FPN_TEST_FILTER_MASK_IMG_OUT, CPL_TYPE_DOUBLE, qclist, CPL_IO_CREATE);
325 cpl_image_save(out_mask, HDRL_FPN_TEST_FILTER_MASK_MASK_OUT, CPL_TYPE_DOUBLE, qclist, CPL_IO_CREATE);
326
327 /* cpl_msg_info(cpl_func, "FILTER image -> rms=%g, mad=%g", rms, mad); */
328 cpl_test_rel(rms, 0.346571043362885, HDRL_DELTA_COMPARE_QC);
329 cpl_test_rel(mad, 0.140385898785234, HDRL_DELTA_COMPARE_QC);
330
331 /* Test output values with python */
332 for(cpl_size x = 0; x < filter_img_nx; x++){
333 for(cpl_size y = 0; y < filter_img_ny; y++){
334 if (!cpl_image_get(out_mask, x + 1, y + 1, &null)) {
335 cpl_test_rel(cpl_image_get(out_img, x + 1, y + 1, &null), const_filter_img_out_python[y][x], HDRL_DELTA_COMPARE_IMAGE);
336 }
337 }
338 }
339
340 /* Test output mask */
341 for(cpl_size x = 1; x <= filter_img_nx; x++){
342 for(cpl_size y = 1; y <= filter_img_ny; y++){
343 cpl_binary bpm_pixel = cpl_mask_get(out_filter_mask, x, y);
344 if (x <= 3 && y <= 3) {
345 cpl_test_eq(bpm_pixel, CPL_BINARY_1);
346 } else {
347 cpl_test_eq(bpm_pixel, CPL_BINARY_0);
348 }
349 }
350 }
351
352 /* Cleanup */
353 cpl_image_delete( out_img );
354 cpl_image_delete( out_mask );
355 cpl_propertylist_delete( qclist );
356 cpl_mask_delete( filter_mask );
357 cpl_image_delete( filter_img );
358
359 /* Remove files */
360 cpl_test_zero(remove(HDRL_FPN_TEST_EVEN_IMG_OUT ));
361 cpl_test_zero(remove(HDRL_FPN_TEST_EVEN_MASK_OUT ));
362 cpl_test_zero(remove(HDRL_FPN_TEST_ODD_IMG_OUT ));
363 cpl_test_zero(remove(HDRL_FPN_TEST_ODD_MASK_OUT ));
364 cpl_test_zero(remove(HDRL_FPN_TEST_FILTER_IMG_OUT ));
365 cpl_test_zero(remove(HDRL_FPN_TEST_FILTER_MASK_OUT ));
366 cpl_test_zero(remove(HDRL_FPN_TEST_FILTER_MASK_IMG_OUT ));
367 cpl_test_zero(remove(HDRL_FPN_TEST_FILTER_MASK_MASK_OUT));
368
369
370/*
371 * Python code to crosscheck the output power spectrum files
372 * =========================================================
373
374import numpy as np
375import math
376import pyfits
377import os
378import glob
379
380feven=pyfits.open("even_img_in.fits")
381fodd=pyfits.open("odd_img_in.fits")
382ffilter=pyfits.open("filter_img_in.fits")
383
384pseven = np.abs(np.fft.fft2(feven[0].data))**2
385psodd = np.abs(np.fft.fft2(fodd[0].data))**2
386psfilter = np.abs(np.fft.fft2(ffilter[0].data))**2
387
388pseven /= pseven.size
389psodd /= psodd.size
390psfilter /= psfilter.size
391
392feven[0].data=pseven
393fodd[0].data=psodd
394ffilter[0].data=psfilter
395
396feven[0].writeto("even_img_out_python.fits", clobber=True)
397fodd[0].writeto("odd_img_out_python.fits", clobber=True)
398ffilter[0].writeto("filter_img_out_python.fits", clobber=True)
399
400*/
401
402}
403
404/*----------------------------------------------------------------------------*/
409/*----------------------------------------------------------------------------*/
410int main(void)
411{
412 cpl_test_init(PACKAGE_BUGREPORT, CPL_MSG_WARNING);
413
414
415 /* Tests with noise files */
416 hdrl_fpn_tests();
417
418
419 cpl_test_error(CPL_ERROR_NONE);
420
421 return cpl_test_end(0);
422}
cpl_error_code hdrl_fpn_compute(cpl_image *img_in, const cpl_mask *mask_in, const cpl_size dc_mask_x, const cpl_size dc_mask_y, cpl_image **power_spectrum, double *std, double *std_mad)
Algorithms to compute fixed pattern noise on a single image.
Definition: hdrl_fpn.c:113