27#include "hdrl_DER_SNR.h"
28#include "hdrl_image.h"
29#include "hdrl_utils.h"
35static inline cpl_boolean is_strictly_monotonic(
const cpl_array * lambdas);
37static inline cpl_boolean
38should_skip(
const cpl_binary * msk, cpl_size i1, cpl_size i2, cpl_size i3);
41static inline cpl_image *
42estimate_noise_DER_SNR_on_sorted(
const hdrl_data_t * flux,
43 const cpl_binary * msk_in,
const cpl_size length,
44 const cpl_size half_window);
49cpl_table * conv_to_sorted_table(
const hdrl_data_t * flux_in,
50 const cpl_binary * msk_in,
const cpl_array * wavelengths,
51 const cpl_size length);
55static inline cpl_image *
56estimate_noise_DER_SNR_on_unsorted(
const hdrl_data_t * flux_in,
57 const cpl_binary * msk_in,
const cpl_array * wavelengths,
58 const cpl_size length,
const cpl_size half_window);
90 const cpl_binary * msk, cpl_size start, cpl_size stop,
93 const hdrl_data_t factor = CPL_MATH_STD_MAD / sqrt(6.0);
95 cpl_ensure(flux != NULL, CPL_ERROR_NULL_INPUT, NAN);
97 cpl_ensure(start >= 0, CPL_ERROR_INCOMPATIBLE_INPUT, NAN);
98 cpl_ensure(stop > start, CPL_ERROR_INCOMPATIBLE_INPUT, NAN);
101 cpl_ensure(stop < sz, CPL_ERROR_INCOMPATIBLE_INPUT, NAN);
106 const cpl_size max_elems = stop - start + 1;
108 cpl_ensure(max_elems > 0 , CPL_ERROR_INCOMPATIBLE_INPUT, NAN);
110 cpl_array * data = cpl_array_new(max_elems, HDRL_TYPE_ERROR);
111 cpl_array_fill_window_invalid(data, 0, max_elems - 1);
113 for(cpl_size i = start; i <= stop; ++i){
115 const cpl_size i_pre = i - 2;
116 const cpl_size i_post = i + 2;
118 if(should_skip(msk, i, i_pre, i_post))
continue;
120 const hdrl_data_t curr = flux[i];
121 const hdrl_data_t pre = flux[i_pre];
122 const hdrl_data_t next = flux[i_post];
124 const hdrl_error_t noise =
125 (hdrl_error_t)fabs(factor * (2.0 * curr - pre - next));
126 cpl_array_set(data, i - start, noise);
129 hdrl_error_t median = NAN;
132 if(cpl_array_count_invalid(data) < max_elems)
133 median = cpl_array_get_median(data);
135 cpl_array_delete(data);
161 const cpl_array * wavelengths,
const cpl_size length,
162 const cpl_size half_window){
164 cpl_ensure(half_window >= 2, CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
165 cpl_ensure(flux_in != NULL, CPL_ERROR_NULL_INPUT, NULL);
166 cpl_ensure(wavelengths != NULL, CPL_ERROR_NULL_INPUT, NULL);
168 cpl_ensure(length > 4, CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
171 if(is_strictly_monotonic(wavelengths))
172 return estimate_noise_DER_SNR_on_sorted
173 (flux_in, msk_in, length, half_window);
178 return estimate_noise_DER_SNR_on_unsorted(flux_in, msk_in, wavelengths,
179 length, half_window);
186static inline cpl_image *
187estimate_noise_DER_SNR_on_sorted(
const hdrl_data_t * flux,
188 const cpl_binary * msk_in,
const cpl_size length,
189 const cpl_size half_window){
191 cpl_image * to_ret = cpl_image_new(length, 1, HDRL_TYPE_ERROR);
192 cpl_mask * msk = cpl_mask_new(length, 1);
194 for(cpl_size i = 0; i < length; ++i){
196 cpl_boolean rej = msk_in != NULL && msk_in[i];
202 const cpl_size start = CPL_MAX(0, i - half_window);
203 const cpl_size stop = CPL_MIN(length - 1, i + half_window);
207 cpl_image_set(to_ret, i + 1, 1, d);
210 cpl_mask_set(msk, i + 1, 1, CPL_BINARY_1);
214 cpl_mask_delete(cpl_image_set_bpm(to_ret, msk));
219cpl_table * conv_to_sorted_table(
const hdrl_data_t * flux_in,
220 const cpl_binary * msk_in,
const cpl_array * wavelengths,
221 const cpl_size length){
223 cpl_table * tb = cpl_table_new(length);
224 int * map = cpl_calloc(length,
sizeof(
int));
225 int * pmask = cpl_calloc(length,
sizeof(
int));
226 hdrl_data_t * flux = cpl_calloc(length,
sizeof(hdrl_data_t));
227 double * pwlen = cpl_calloc(length,
sizeof(
double));
229 for(cpl_size i = 0; i < length; ++i){
231 pwlen[i] = cpl_array_get(wavelengths, i, NULL);
232 pmask[i] = msk_in == NULL ? 0 : (int)msk_in[i];
233 flux[i] = flux_in[i];
236 cpl_table_wrap_int(tb, map,
"map");
237 cpl_table_wrap_int(tb, pmask,
"bad_pixel_mask");
238 cpl_table_wrap_double(tb, pwlen,
"lambda");
239 hdrl_wrap_table(tb, flux,
"flux");
241 cpl_propertylist * ls = cpl_propertylist_new();
242 cpl_propertylist_append_bool(ls,
"lambda", CPL_FALSE);
243 cpl_table_sort(tb, ls);
244 cpl_propertylist_delete(ls);
248static inline cpl_image *
249estimate_noise_DER_SNR_on_unsorted(
const hdrl_data_t * flux_in,
250 const cpl_binary * msk_in,
const cpl_array * wavelengths,
251 const cpl_size length,
const cpl_size half_window){
253 cpl_binary * msk_sorted = cpl_calloc(length,
sizeof(cpl_binary));
255 cpl_table * tb = conv_to_sorted_table(flux_in, msk_in, wavelengths, length);
258 int * map = (
int*)cpl_table_unwrap(tb,
"map");
259 hdrl_data_t * flux = (hdrl_data_t*)cpl_table_unwrap(tb,
"flux");
260 int * pmask = (
int*)cpl_table_unwrap(tb,
"bad_pixel_mask");
262 cpl_table_delete(tb);
265 for(cpl_size i = 0; i < length; ++i){
266 msk_sorted[i] = pmask[i];
270 cpl_image * img_sorted = estimate_noise_DER_SNR_on_sorted
271 (flux, msk_sorted, length, half_window);
274 cpl_free(msk_sorted);
276 cpl_image * to_ret = cpl_image_new(length, 1, HDRL_TYPE_DATA);
278 for(cpl_size i = 0; i < length; i++){
279 const cpl_size dest_idx = map[i] + 1;
280 const cpl_size source_idx = i + 1;
283 double data = cpl_image_get(img_sorted, source_idx, 1, &rej);
285 cpl_image_reject(to_ret, dest_idx, 1);
288 cpl_image_set(to_ret, dest_idx, 1, data);
293 cpl_image_delete(img_sorted);
297static inline cpl_boolean is_strictly_monotonic(
const cpl_array * lambdas){
298 for(cpl_size i = 0; i < cpl_array_get_size(lambdas) - 1; ++i){
299 if(cpl_array_get(lambdas, i, NULL) >= cpl_array_get(lambdas, i + 1, NULL)){
306static inline cpl_boolean
307should_skip(
const cpl_binary * msk, cpl_size i1, cpl_size i2, cpl_size i3){
310 if(!msk)
return CPL_FALSE;
312 return msk[i1] || msk[i2] || msk[i3];
hdrl_error_t estimate_noise_window(const hdrl_data_t *flux, const cpl_binary *msk, cpl_size start, cpl_size stop, const cpl_size sz)
Estimate the noise in the pixels between [start, stop]. The noise calculation is done using the formu...
cpl_image * estimate_noise_DER_SNR(const hdrl_data_t *flux_in, const cpl_binary *msk_in, const cpl_array *wavelengths, const cpl_size length, const cpl_size half_window)
For every pixel in position i in img_arg, the function estimates the noise using the pixels in the wi...