X-shooter Pipeline Reference Manual 3.8.15
xsh_remove_crh_single.c
Go to the documentation of this file.
1/* *
2 * This file is part of the ESO X-shooter Pipeline *
3 * Copyright (C) 2006 European Southern Observatory *
4 * *
5 * This library 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, 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA *
18 * */
19
20/*
21 * $Author: amodigli $
22
23 * $Date: 2012-11-15 16:23:46 $
24 * $Revision: 1.61 $
25 */
26
27#ifdef HAVE_CONFIG_H
28# include <config.h>
29#endif
30
31/*----------------------------------------------------------------------------*/
38/*----------------------------------------------------------------------------*/
41/*-----------------------------------------------------------------------------
42 Includes
43-----------------------------------------------------------------------------*/
44
45#include <math.h>
46
47#include <xsh_drl.h>
48#include <xsh_data_pre.h>
49#include <xsh_dfs.h>
50#include <xsh_pfits.h>
51#include <xsh_error.h>
52#include <xsh_msg.h>
53#include <cpl.h>
54#include <xsh_badpixelmap.h>
55#include <xsh_parameters.h>
56#include <xsh_utils_wrappers.h>
57#include <xsh_qc_handling.h>
58/*-----------------------------------------------------------------------------
59 Functions prototypes
60 -----------------------------------------------------------------------------*/
61
62/*-----------------------------------------------------------------------------
63 Implementation
64 -----------------------------------------------------------------------------*/
65
66/* This should be defined in a more clever way, a parameter for example */
67#define REGDEBUG_FULL 0
68
69
70
71
72
73cpl_frame * xsh_abs_remove_crh_single( cpl_frame *sci_frame,
75 xsh_remove_crh_single_param * single_par,
76 const char * res_tag)
77{
78 cpl_frame *result_frame = NULL;
79 cpl_frame *abs_frame = NULL;
80 cpl_frame *sign_frame = NULL;
81 cpl_frame *rmcrh_frame = NULL;
82 const char* name = NULL;
83 cpl_propertylist *header = NULL;
84 int qc_ncrh =0;
85
86 XSH_ASSURE_NOT_NULL( sci_frame);
87
88 check( name = cpl_frame_get_filename( sci_frame));
89 check( header = cpl_propertylist_load( name, 0));
90 if(cpl_propertylist_has(header,XSH_QC_CRH_NUMBER)) {
91 check( qc_ncrh = xsh_pfits_get_qc_ncrh( header));
92 } else {
93 qc_ncrh =0;
94 }
95 /* cosmics detection already done */
96 if (qc_ncrh > 0){
97 xsh_msg( "Not use remove crh single");
98 check( result_frame = cpl_frame_duplicate( sci_frame));
99 }
100 else{
101 check( abs_frame = xsh_frame_abs( sci_frame, instrument, &sign_frame));
102 check( rmcrh_frame = xsh_remove_crh_single( abs_frame, instrument,NULL,
103 single_par, res_tag));
104 check( result_frame = xsh_frame_mult( rmcrh_frame, instrument, sign_frame));
105 }
106
107 cleanup:
108 if (cpl_error_get_code() != CPL_ERROR_NONE){
109 xsh_free_frame( &result_frame);
110 }
111 xsh_free_propertylist( &header);
112 xsh_free_frame( &abs_frame);
113 xsh_free_frame( &sign_frame);
114 xsh_free_frame( &rmcrh_frame);
115 return result_frame;
116}
117
118/*****************************************************************************/
133/*****************************************************************************/
134cpl_frame * xsh_remove_crh_single(cpl_frame * in_sci_frame,
135 xsh_instrument * instrument, cpl_mask* sky_map,
136 xsh_remove_crh_single_param * single_par,
137 const char * res_tag) {
138 int i, j,k,l,m;
139 double sigma_lim, f_lim;
140 /* Only pointers */
141 cpl_frame* res_frame = NULL;
142 char* res_name = NULL;
143 /* Need to be free */
144 cpl_image* laplacian_image = NULL;
145 cpl_image* laplacian_redu_image = NULL; /* rebinned Laplacian */
146
147 cpl_image* two_sub_sample = NULL;
148 cpl_image* noise_image = NULL;
149 cpl_image* s_median_image = NULL;
150 cpl_image* s_image = NULL;
151 cpl_image* sci_median3_image = NULL;
152 cpl_image* sci_median3_7_image = NULL;
153 cpl_image* f_image = NULL;
154 cpl_image* r_image = NULL;
155 int two_sub_sample_nx = 0;
156 int two_sub_sample_ny = 0;
157 xsh_pre* in_sci_pre = NULL;
158 xsh_pre* sci_pre = NULL;
160 cpl_image* sci_image = NULL;
161 cpl_image* sci_copy = NULL;
162 cpl_image* err_image = NULL;
163 cpl_image* qua_image = NULL;
165 /* Only pointers */
166 float* sci_data = NULL;
167 float* err_data = NULL;
168 int* qua_data = NULL;
169 cpl_binary* msk_data = NULL;
170
171 float* two_sub_sample_data = NULL;
172 float* laplacian_data = NULL;
173 float* laplacian_redu_data = NULL;
174
175 float* sci_median3_data = NULL;
176 float* sci_median3_7_data = NULL;
177
178 float* s_data = NULL;
179 float* s_median_data = NULL;
180
181 float* f_data = NULL;
182 float* r_data = NULL;
183 /* Need to be free */
184
185 cpl_matrix* laplacian_kernel = NULL;
186 cpl_matrix* median3_kernel = NULL;
187 cpl_matrix* median5_kernel = NULL;
188 cpl_matrix* median7_kernel = NULL;
189 int new_crh = 1, nb_crh = 0;
190 int nbiter = 1;
191 int max_iter=1;
192 cpl_vector* median = NULL;
193
194 int nx = 0;
195 int ny = 0;
196 int j_nx=0;
197
198 /* Check parameters */XSH_ASSURE_NOT_NULL_MSG( in_sci_frame,"Null input science frame" );
199 XSH_ASSURE_NOT_NULL_MSG( single_par,"Null input parameters" );
200 XSH_ASSURE_NOT_NULL_MSG( instrument,"Null instrument setting" );
201
202 sigma_lim = single_par->sigma_lim;
203 f_lim = single_par->f_lim;
204 max_iter = single_par->nb_iter;
206 " Params: sigma_lim %.2f f_lim %.2f, iter %d", sigma_lim, f_lim, max_iter);
207
208 check( in_sci_pre = xsh_pre_load( in_sci_frame, instrument));
209 check( sci_pre = xsh_pre_duplicate( in_sci_pre ) );
210 xsh_pre_free(&in_sci_pre);
211 check( sci_image = xsh_pre_get_data( sci_pre));
212 check( sci_copy = cpl_image_duplicate( sci_image));
213 check( err_image = xsh_pre_get_errs( sci_pre));
214 check( qua_image = xsh_pre_get_qual( sci_pre));
215
216 if (sky_map != NULL) {
217 cpl_image_reject_from_mask(sci_copy,sky_map);
218 msk_data = cpl_mask_get_data( sky_map);
219 }
220
221
222 nx = sci_pre->nx;
223 ny = sci_pre->ny;
224
225 /* Preparing different kernels */
226
227 xsh_msg_dbg_low("--remove-crh-single : Preparing kernels");
228 /* Laplacian */
229 check( laplacian_kernel = cpl_matrix_new(3,3));
230 cpl_matrix_set(laplacian_kernel, 0, 0, 0.0);
231 cpl_matrix_set(laplacian_kernel, 0, 1, -1.0);
232 cpl_matrix_set(laplacian_kernel, 0, 2, 0.0);
233 cpl_matrix_set(laplacian_kernel, 1, 0, -1.0);
234 cpl_matrix_set(laplacian_kernel, 1, 1, 4.0);
235 cpl_matrix_set(laplacian_kernel, 1, 2, -1.0);
236 cpl_matrix_set(laplacian_kernel, 2, 0, 0.0);
237 cpl_matrix_set(laplacian_kernel, 2, 1, -1.0);
238 cpl_matrix_set(laplacian_kernel, 2, 2, 0.0);
239
240 /* Median 3x3*/
241 check( median3_kernel = cpl_matrix_new(3,3));
242 for (j = 0; j < 3; j++) {
243 for (i = 0; i < 3; i++) {
244 cpl_matrix_set(median3_kernel, i, j, 1.0);
245 }
246 }
247
248 /* Median 5x5 */
249 check( median5_kernel = cpl_matrix_new(5,5));
250 for (j = 0; j < 5; j++) {
251 for (i = 0; i < 5; i++) {
252 cpl_matrix_set(median5_kernel, i, j, 1.0);
253 }
254 }
255
256 /* Median 7x7 */
257 check( median7_kernel = cpl_matrix_new(7,7));
258 for (j = 0; j < 7; j++) {
259 for (i = 0; i < 7; i++) {
260 cpl_matrix_set(median7_kernel, i, j, 1.0);
261 }
262 }
263
264 /* Allocate images and pointers */
265 check(sci_data = cpl_image_get_data_float( sci_copy));
266 check(err_data = cpl_image_get_data_float( err_image));
267 check(qua_data = cpl_image_get_data_int( qua_image));
268
269 two_sub_sample_nx = nx * 2;
270 two_sub_sample_ny = ny * 2;
271 check(
272 two_sub_sample = cpl_image_new( two_sub_sample_nx, two_sub_sample_ny, CPL_TYPE_FLOAT));
273 check(two_sub_sample_data = cpl_image_get_data_float( two_sub_sample));
274 check( laplacian_redu_image = cpl_image_new(nx,ny, CPL_TYPE_FLOAT));
275 check(laplacian_redu_data = cpl_image_get_data_float( laplacian_redu_image));
276 check( noise_image = cpl_image_new(nx,ny, CPL_TYPE_FLOAT));
277
278 check( s_image = cpl_image_new(nx,ny, CPL_TYPE_FLOAT));
279 check( s_data = cpl_image_get_data_float( s_image));
280
281
282 check( f_image = cpl_image_new(nx,ny, CPL_TYPE_FLOAT));
283 check( f_data = cpl_image_get_data_float( f_image));
284 check( r_image = cpl_image_new(nx,ny, CPL_TYPE_FLOAT));
285
286 check( r_data = cpl_image_get_data_float( r_image));
287
288 /* LGG - Added limit limit on nb iterations */
289 while (new_crh > 0 && nbiter <= max_iter) {
290 xsh_msg_dbg_low("Iteration %d", nbiter);
291
292
293 /* Super sample data:
294 Create a 2n x 2n images like this
295 | 1 | 2 | => | 1 | 1 | 2 | 2 |
296 | 3 | 4 | | 1 | 1 | 2 | 2 |
297 | 3 | 3 | 4 | 4 |
298 | 3 | 3 | 4 | 4 | */
299 xsh_msg_dbg_medium("Create super-sampled image");
300 int j_2_two_sub_sample_nx = 0;
301 int pix = 0;
302 for (j = 0; j < ny; j++) {
303 j_2_two_sub_sample_nx = j * 2 * two_sub_sample_nx;
304 j_nx = j*nx;
305 for (i = 0; i < nx; i++) {
306 float val = sci_data[i + j_nx];
307 pix = i * 2 + j_2_two_sub_sample_nx;
308 two_sub_sample_data[pix] = val;
309 two_sub_sample_data[pix + two_sub_sample_nx] = val;
310 pix++;
311 two_sub_sample_data[pix] = val;
312 two_sub_sample_data[pix + two_sub_sample_nx] = val;
313 }
314 }
315
316
317 /* Doing the Laplacian convolution and set negative pixels to
318 0 in the Laplacian image
319
320 0 -1 0
321 -1 4 -1
322 0 -1 0 */
323 xsh_msg_dbg_medium("Doing Laplacian convolution");
324 check(
325 laplacian_image = xsh_image_filter_linear( two_sub_sample, laplacian_kernel));
326
327 check(laplacian_data = cpl_image_get_data_float( laplacian_image));
328 for (i = 0; i < two_sub_sample_nx * two_sub_sample_ny; i++) {
329 if (laplacian_data[i] < 0.0) {
330 laplacian_data[i] = 0.0;
331 } else {
332 laplacian_data[i] *= 8.0;
333 }
334 }
335
336
337#if REGDEBUG_FULL
338 xsh_msg_dbg_medium("Save Lpositive");
339 cpl_image_save(laplacian_image, "Lpositive.fits", CPL_BPP_IEEE_FLOAT, NULL,
340 CPL_IO_DEFAULT);
341#endif
342
343
344
345 /* resample to the original size
346 | 1 | 1 | 2 | 2 | | 1 | 2 |
347 | 1 | 1 | 2 | 2 | | 3 | 4 |
348 | 3 | 3 | 4 | 4 | =>
349 | 3 | 3 | 4 | 4 | */
350
351 xsh_msg_dbg_medium("Resample to the original size");
352 for (j = 0; j < ny; j++) {
353 j_2_two_sub_sample_nx = j * 2 * two_sub_sample_nx;
354 j_nx = j*nx;
355 for (i = 0; i < nx; i++) {
356 pix = i * 2 + j_2_two_sub_sample_nx;
357 laplacian_redu_data[i + j_nx] = (laplacian_data[pix]
358 + laplacian_data[pix + 1] + laplacian_data[pix + two_sub_sample_nx]
359 + laplacian_data[pix + two_sub_sample_nx + 1]) * 0.25;
360 }
361 }
362
363#if REGDEBUG_FULL
364 cpl_image_save(laplacian_redu_image, "Lplus.fits", CPL_BPP_IEEE_FLOAT,
365 NULL, CPL_IO_DEFAULT);
366#endif
367
368
369 /* compute S image */
370 xsh_msg_dbg_medium("Compute S");
371 for (i = 0; i < nx * ny; i++) {
372 s_data[i] = 0.5 * laplacian_redu_data[i] / err_data[i];
373 }
374
375 /* compute S median image */
376 xsh_msg_dbg_medium("Compute S median");
377 check( s_median_image = xsh_image_filter_median( s_image, median5_kernel));
378 check( s_median_data = cpl_image_get_data_float( s_median_image));
379
380
381 /* compute s2 */
382 xsh_msg_dbg_medium("Compute s2");
383 for (i = 0; i < nx * ny; i++) {
384 s_data[i] -= s_median_data[i];
385 }
386#if REGDEBUG_FULL
387 cpl_image_save( s_image, "S2.fits", CPL_BPP_IEEE_FLOAT, NULL,
388 CPL_IO_DEFAULT);
389#endif
390
391
392 /* Apply 3x3 median filter on data */
393 xsh_msg_dbg_medium("Apply 3x3 filter");
394 check(sci_median3_image = xsh_image_filter_median( sci_copy, median3_kernel));
395 check( sci_median3_data = cpl_image_get_data_float( sci_median3_image));
396
397 /* Apply 7x7 median filter */
398 xsh_msg_dbg_medium("Apply 7x7 filter");
399 check(
400 sci_median3_7_image = xsh_image_filter_median( sci_median3_image, median7_kernel));
401 check( sci_median3_7_data = cpl_image_get_data_float( sci_median3_7_image));
402
403
404
405 /* compute F: fine structure image */
406 xsh_msg_dbg_medium("Compute F");
407 for (i = 0; i < nx * ny; i++) {
408 f_data[i] = sci_median3_data[i] - sci_median3_7_data[i];
409 if (f_data[i] < 0.01) {
410 f_data[i] = 0.01;
411 }
412 }
413#if REGDEBUG_FULL
414 cpl_image_save( f_image, "F.fits", CPL_BPP_IEEE_FLOAT, NULL,
415 CPL_IO_DEFAULT);
416#endif
417
418 /* compute R: the ratio of Laplacian to the fine structure image */
419 xsh_msg_dbg_medium("Compute R");
420 for (i = 0; i < nx * ny; i++) {
421 r_data[i] = laplacian_redu_data[i] / f_data[i];
422 }
423#if REGDEBUG_FULL
424 cpl_image_save( r_image, "R.fits", CPL_BPP_IEEE_FLOAT, NULL,
425 CPL_IO_DEFAULT);
426#endif
427
428
429 /* Search for cosmics */
430 xsh_msg_dbg_medium("Search for cosmic ray hits");
431 new_crh = 0;
432 median = cpl_vector_new(24);
433 for (j = 0; j < ny - 1; j++) {
434
435 double *data = NULL;
436 cpl_vector* med_vect = NULL;
437
438 j_nx = j*nx;
439 for (i = 0; i < nx - 1 ; i++) {
440 int i_plus_j_nx = i + j_nx;
441 if ( (msk_data != NULL) && (msk_data[i + j_nx] != CPL_BINARY_1) ) {
442 /* if the pixel was already flagged in input sky map
443 * does not search for CRH
444 */
445 //xsh_msg("found a bad pixel at j=%d i=%d",j,i);
446
447 } else {
448 if ( s_data[i_plus_j_nx] > sigma_lim ) {
449 if ( r_data[i_plus_j_nx] > f_lim ) {
450
451 /* we flag the CRH in the science frame */
452 qua_data[i + j_nx] |= QFLAG_COSMIC_RAY_UNREMOVED;
453 new_crh++;
454
455 /* we replace the CRH with median of the surroundings pixels
456 in a box 5x5 pixels */
457 int li, lj, ui, uj;
458 li = i - 2;
459 lj = j - 2;
460 ui = i + 2;
461 uj = j + 2;
462 m = 0;
463
464 if (li < 0) { li = 0; }
465 if (ui >= nx) { ui = nx - 1; }
466 if (lj < 0) { lj = 0; }
467 if (uj >= ny) { uj = ny - 1;}
468
469 for (k = lj; k <= uj; k++) {
470 int k_nx = k*nx;
471 for (l = li; l <= ui; l++) {
472 int l_plus_k_nx = l + k_nx;
473 if (s_data[l_plus_k_nx] <= sigma_lim) {
474 cpl_vector_set(median, m, sci_data[l_plus_k_nx]);
475 m++;
476 continue;
477 }
478 if (r_data[l_plus_k_nx] <= f_lim) {
479 cpl_vector_set(median, m, sci_data[l_plus_k_nx]);
480 m++;
481 }
482 }
483 }
484 /* if no good pixel has been found skip pixel value
485 replacement */
486 if(m==0) continue;
487 /* Replace CRH value with median of computed values on
488 good pixels */
489 check( data = cpl_vector_get_data( median));
490 check( med_vect = cpl_vector_wrap( m, data));
491 check( sci_data[i_plus_j_nx] = cpl_vector_get_median(med_vect));
492 cpl_vector_unwrap(med_vect);
493
494
495 }/* end check on 2nd threshold */
496 } /* end check on 1st threshold */
497 }/* end check if given point should not be checked as flagged in map */
498 } /* end loop over image columns */
499 } /* end loop over image rows */
500
501 xsh_free_vector(&median);
502
503 nb_crh += new_crh;
505 " new cosmics %d, total %d [%d pixels]", new_crh, nb_crh, nx*ny);
506 nbiter++;
507 xsh_free_image(&laplacian_image);
508 xsh_free_image(&sci_median3_7_image);
509 xsh_free_image(&sci_median3_image);
510 xsh_free_image(&s_median_image);
511 }
512#if REGDEBUG_FULL
513 cpl_image_save( qua_image, "CRH_SINGLE.fits", CPL_BPP_32_SIGNED, NULL,
514 CPL_IO_DEFAULT);
515#endif
516
517
518
519 res_name = xsh_stringcat_any(res_tag, ".fits", (void*)NULL);
520 xsh_msg_dbg_high( "Saving Result Frame '%s'", res_name);
521 check( xsh_add_qc_crh( sci_pre, nb_crh, 1) );
522 check( res_frame = xsh_pre_save( sci_pre, res_name, res_tag,0 ) );
523 check( cpl_frame_set_tag( res_frame, res_tag ) );
524 XSH_FREE( res_name);
525
526 cleanup:
527 xsh_pre_free(&sci_pre);
528
529 /* free kernel */
530 xsh_free_matrix(&laplacian_kernel);
531 xsh_free_matrix(&median3_kernel);
532 xsh_free_matrix(&median5_kernel);
533 xsh_free_matrix(&median7_kernel);
534 /* free images */
535 xsh_free_image(&laplacian_image);
536 xsh_free_image(&laplacian_redu_image);
537 xsh_free_image(&two_sub_sample);
538 xsh_free_image(&noise_image);
539 xsh_free_image(&s_median_image);
540 xsh_free_image(&s_image);
541 xsh_free_image(&sci_median3_image);
542 xsh_free_image(&sci_median3_7_image);
543 xsh_free_image(&sci_copy);
544 xsh_free_image(&f_image);
545 xsh_free_image(&r_image);
546 /* free tab */
547 return res_frame;
548}
549
550
static xsh_instrument * instrument
cpl_image * xsh_pre_get_data(xsh_pre *pre)
Get data.
xsh_pre * xsh_pre_duplicate(const xsh_pre *pre)
Copy a PRE structure.
Definition: xsh_data_pre.c:953
xsh_pre * xsh_pre_load(cpl_frame *frame, xsh_instrument *instr)
Load a xsh_pre structure from a frame.
Definition: xsh_data_pre.c:849
cpl_image * xsh_pre_get_qual(xsh_pre *pre)
Get qual.
void xsh_pre_free(xsh_pre **pre)
Free a xsh_pre structure.
Definition: xsh_data_pre.c:823
cpl_image * xsh_pre_get_errs(xsh_pre *pre)
Get errs.
cpl_frame * xsh_pre_save(const xsh_pre *pre, const char *filename, const char *tag, int temp)
Save PRE on disk.
#define XSH_ASSURE_NOT_NULL_MSG(pointer, msg)
Definition: xsh_error.h:103
#define check(COMMAND)
Definition: xsh_error.h:71
#define XSH_ASSURE_NOT_NULL(pointer)
Definition: xsh_error.h:99
#define xsh_msg_dbg_medium(...)
Definition: xsh_msg.h:44
#define xsh_msg(...)
Print a message on info level.
Definition: xsh_msg.h:121
#define xsh_msg_dbg_low(...)
Definition: xsh_msg.h:48
#define xsh_msg_dbg_high(...)
Definition: xsh_msg.h:40
int xsh_pfits_get_qc_ncrh(const cpl_propertylist *plist)
Find out the QC NCRH value.
Definition: xsh_pfits_qc.c:74
void xsh_add_qc_crh(xsh_pre *pre, int nbcrh, int nframes)
cpl_frame * xsh_abs_remove_crh_single(cpl_frame *sci_frame, xsh_instrument *instrument, xsh_remove_crh_single_param *single_par, const char *res_tag)
cpl_frame * xsh_remove_crh_single(cpl_frame *in_sci_frame, xsh_instrument *instrument, cpl_mask *sky_map, xsh_remove_crh_single_param *single_par, const char *res_tag)
Remove cosmic rays from a single frame.
void xsh_free_vector(cpl_vector **v)
Deallocate a vector and set the pointer to NULL.
Definition: xsh_utils.c:2284
void xsh_free_image(cpl_image **i)
Deallocate an image and set the pointer to NULL.
Definition: xsh_utils.c:2116
void xsh_free_frame(cpl_frame **f)
Deallocate a frame and set the pointer to NULL.
Definition: xsh_utils.c:2269
cpl_frame * xsh_frame_mult(cpl_frame *in, xsh_instrument *instr, cpl_frame *sign)
Computes product of two input frames.
Definition: xsh_utils.c:4061
cpl_frame * xsh_frame_abs(cpl_frame *in, xsh_instrument *instr, cpl_frame **sign)
Computes absolute value of a frame.
Definition: xsh_utils.c:3911
char * xsh_stringcat_any(const char *s,...)
Concatenate an arbitrary number of strings.
Definition: xsh_utils.c:1925
void xsh_free_matrix(cpl_matrix **m)
Deallocate a matrix and set the pointer to NULL.
Definition: xsh_utils.c:2209
void xsh_free_propertylist(cpl_propertylist **p)
Deallocate a property list and set the pointer to NULL.
Definition: xsh_utils.c:2179
#define QFLAG_COSMIC_RAY_UNREMOVED
int nx
int m
Definition: xsh_detmon_lg.c:91
int ny
#define XSH_QC_CRH_NUMBER
#define XSH_FREE(POINTER)
Definition: xsh_utils.h:92
cpl_image * xsh_image_filter_median(const cpl_image *img, const cpl_matrix *mx)
cpl_image * xsh_image_filter_linear(const cpl_image *img, const cpl_matrix *mx)