27#include "hdrl_correlation.h"
45double calculate_xcorr_sample(
const cpl_size shift,
const cpl_array * arr1,
46 const cpl_array * arr2,
const double mean1,
const double mean2,
47 const double stdev1,
const double stdev2);
50mean_and_stdev calculate_mean_and_stdev(
const cpl_array * arr1);
52static inline cpl_error_code
53hdrl_compute_xcorrelation_refine(hdrl_xcorrelation_result* xcorr_res,
54 const double bin,
const double wrange);
78hdrl_xcorrelation_result *
80 const cpl_size half_window){
82 cpl_ensure(x_corr != NULL, CPL_ERROR_NULL_INPUT, NULL);
83 cpl_ensure(max_idx >= 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
84 cpl_ensure(max_idx < cpl_array_get_size(x_corr),
85 CPL_ERROR_ILLEGAL_INPUT, NULL);
87 hdrl_xcorrelation_result * to_ret = cpl_calloc(1,
sizeof(*to_ret));
89 to_ret->xcorr = x_corr;
90 to_ret->pix_peakpos = max_idx;
91 to_ret->half_window = half_window;
102 if(self == NULL)
return;
104 cpl_array_delete(self->xcorr);
120 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, 0);
122 return self->pix_peakpos;
137 (
const hdrl_xcorrelation_result * self){
139 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, 0);
141 return self->peakpos;
154 (
const hdrl_xcorrelation_result * self){
156 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, 0);
158 return self->half_window;
173 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, 0);
190 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, NULL);
210 const cpl_array * arr1,
const cpl_array * arr2,
211 const cpl_size half_window,
const cpl_boolean normalize){
213 cpl_ensure(half_window > 1, CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
215 const mean_and_stdev not_normalized = {0.0, 1.0};
217 cpl_ensure(arr1 != NULL && arr2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
219 cpl_size xcorr_length = 2 * half_window + 1;
220 cpl_array * corr = cpl_array_new(xcorr_length, HDRL_TYPE_DATA);
222 const mean_and_stdev d1 = normalize ?
223 calculate_mean_and_stdev(arr1) : not_normalized;
224 const mean_and_stdev d2 = normalize ?
225 calculate_mean_and_stdev(arr2) : not_normalized;
227 cpl_size max_idx = -1;
228 double max_corr = 0.0;
230 for(cpl_size i = -half_window; i <= half_window; ++i){
231 const double cr = calculate_xcorr_sample(i, arr1, arr2, d1.mean, d2.mean,
234 const cpl_size idx = i + half_window;
235 cpl_array_set(corr, idx, cr);
237 if(isnan(cr))
continue;
239 if(cr >= max_corr || max_idx < 0){
249cpl_error_code check_if_bad(
const hdrl_xcorrelation_result * gfit,
250 const cpl_boolean check_refine){
252 cpl_ensure_code(gfit != NULL, CPL_ERROR_ILLEGAL_OUTPUT);
254 CPL_ERROR_ILLEGAL_OUTPUT);
259 cpl_ensure_code(px >= 0.0 && !isnan(px), CPL_ERROR_ILLEGAL_OUTPUT);
262 cpl_ensure_code( sigma > 0.0 && !isnan(sigma),CPL_ERROR_ILLEGAL_OUTPUT);
265 return CPL_ERROR_NONE;
269cpl_boolean check_and_delete_if_bad(hdrl_xcorrelation_result ** gfit_arg,
270 const cpl_boolean check_refine){
272 cpl_error_code fail = check_if_bad(*gfit_arg, check_refine);
279 return fail ? CPL_FALSE : CPL_TRUE;
298 const cpl_array * arr1,
299 const cpl_array * arr2,
300 const cpl_size half_win,
const cpl_boolean normalize,
301 const double bin,
const double wrange){
303 cpl_ensure(half_win > 1, CPL_ERROR_ILLEGAL_INPUT, NULL);
304 cpl_ensure(arr1 != NULL, CPL_ERROR_NULL_INPUT, NULL);
305 cpl_ensure(arr2 != NULL, CPL_ERROR_NULL_INPUT, NULL);
307 hdrl_xcorrelation_result * gfit =
309 normalize, bin, wrange);
311 cpl_ensure(gfit != NULL, CPL_ERROR_ILLEGAL_OUTPUT, NULL);
313 const cpl_size half_win2 =
314 (cpl_size)(3. * CPL_MATH_FWHM_SIG * gfit->sigma / bin);
319 normalize, bin, wrange);
339 const cpl_array * arr1,
const cpl_array * arr2,
340 const cpl_size half_win,
const cpl_boolean normalize,
341 const double bin,
const double wrange){
343 hdrl_xcorrelation_result * res =
346 if(!check_and_delete_if_bad(&res, CPL_FALSE))
return NULL;
348 cpl_error_code fail =
349 hdrl_compute_xcorrelation_refine(res, bin, wrange);
356 if(!check_and_delete_if_bad(&res, CPL_TRUE))
return NULL;
372static inline cpl_error_code
373hdrl_compute_xcorrelation_refine(hdrl_xcorrelation_result* xcorr_res,
374 const double bin,
const double wrange){
379 const cpl_size xcorr_size = cpl_array_get_size(xcorr);
380 const cpl_size pre_idx = CPL_MAX(0, maxpos - 1);
381 const cpl_size post_idx = CPL_MIN(maxpos + 1, xcorr_size - 1);
383 const double a = cpl_array_get(xcorr, pre_idx, NULL);
384 const double b = cpl_array_get(xcorr, post_idx, NULL);
385 const double c = cpl_array_get(xcorr, maxpos, NULL);
387 const double fraction = (b - a) / ( 4. * c - 2. * a - 2. * b );
388 const double subpix_offset = maxpos -
fraction;
390 xcorr_res->peakpos = subpix_offset * bin;
391 xcorr_res->sigma = bin * 10;
392 xcorr_res->area = 1.0;
394 cpl_size num_elems = 0;
396 cpl_vector * wavs_windowed = cpl_vector_new(xcorr_size);
397 cpl_vector * corr_windowed = cpl_vector_new(xcorr_size);
399 for(cpl_size i = 0; i < xcorr_size; ++i){
400 const double w = i * bin;
402 const double xcorr_data = cpl_array_get(xcorr, i, &rej);
404 if(rej || isnan(xcorr_data))
continue;
405 if(w < xcorr_res->peakpos - wrange
406 || w > xcorr_res->peakpos + wrange)
continue;
408 cpl_vector_set(corr_windowed, num_elems, xcorr_data);
409 cpl_vector_set(wavs_windowed, num_elems, w);
415 cpl_vector_delete(wavs_windowed);
416 cpl_vector_delete(corr_windowed);
417 cpl_ensure_code(CPL_FALSE, CPL_ERROR_ILLEGAL_OUTPUT);
420 cpl_vector_set_size(corr_windowed, num_elems);
421 cpl_vector_set_size(wavs_windowed, num_elems);
423 cpl_error_code code = cpl_vector_fit_gaussian(wavs_windowed, NULL,
424 corr_windowed, NULL, CPL_FIT_ALL, &xcorr_res->peakpos, &xcorr_res->sigma,
425 &xcorr_res->area, &xcorr_res->offset, &xcorr_res->mse, NULL, NULL);
430 if(code == CPL_ERROR_CONTINUE){
434 cpl_vector_delete(wavs_windowed);
435 cpl_vector_delete(corr_windowed);
437 return cpl_error_get_code();
441double calculate_xcorr_sample(
const cpl_size shift,
442 const cpl_array * arr1,
const cpl_array * arr2,
443 const double mean1,
const double mean2,
444 const double stdev1,
const double stdev2){
449 const double norm = 1.00 / sqrt(stdev1 * stdev2);
451 const cpl_size l1 = cpl_array_get_size(arr1);
452 const cpl_size l2 = cpl_array_get_size(arr2);
454 for(cpl_size i = 0; i < l2; i++){
455 const cpl_size j = i + shift;
456 int rej1 = 0, rej2 = 0;
458 if(j >= l1)
continue;
460 const double v1 = cpl_array_get(arr1, j, &rej1);
461 const double v2 = cpl_array_get(arr2, i, &rej2);
463 if(rej1 || rej2)
continue;
465 const double val = norm * (v1 - mean1) * (v2 - mean2);
470 return d / (double)num_el;
474mean_and_stdev calculate_mean_and_stdev(
const cpl_array * arr1){
476 const double mean = cpl_array_get_mean(arr1);
477 const double stdev = cpl_array_get_stdev(arr1);
479 return (mean_and_stdev){mean, stdev};
void hdrl_xcorrelation_result_delete(hdrl_xcorrelation_result *self)
Destructor for hdrl_xcorrelation_result.
hdrl_xcorrelation_result * hdrl_compute_xcorrelation(const cpl_array *arr1, const cpl_array *arr2, const cpl_size half_window, const cpl_boolean normalize)
Calculate cross-correlation.
const cpl_array * hdrl_xcorrelation_result_get_correlation(const hdrl_xcorrelation_result *self)
Getter for the cross correlation.
cpl_size hdrl_xcorrelation_result_get_peak_pixel(const hdrl_xcorrelation_result *self)
Get the index where the cross correlation reaches its maximum.
cpl_size hdrl_xcorrelation_result_get_half_window(const hdrl_xcorrelation_result *self)
Get the half_window used to calculate the cross-correlation.
hdrl_xcorrelation_result * hdrl_compute_offset_gaussian_internal(const cpl_array *arr1, const cpl_array *arr2, const cpl_size half_win, const cpl_boolean normalize, const double bin, const double wrange)
Calculate gaussian fit on cross-correlation.
hdrl_xcorrelation_result * hdrl_compute_offset_gaussian(const cpl_array *arr1, const cpl_array *arr2, const cpl_size half_win, const cpl_boolean normalize, const double bin, const double wrange)
Calculate gaussian fit on cross-correlation, does a second fitting for refinement.
double hdrl_xcorrelation_result_get_peak_subpixel(const hdrl_xcorrelation_result *self)
Get the index where the cross correlation reaches its maximum, with sub-pixel precision.
double hdrl_xcorrelation_result_get_sigma(const hdrl_xcorrelation_result *self)
Get the estimated standard deviation of the correlation.
hdrl_xcorrelation_result * hdrl_xcorrelation_result_wrap(cpl_array *x_corr, const cpl_size max_idx, const cpl_size half_window)
Constructor for hdrl_xcorrelation_result.
double fraction(double x, double y, double r_out)
Fraction of pixel bounded.