UVES Pipeline Reference Manual  5.4.6
uves_utils_cpl.c
1 /* *
2  * This file is part of the ESO UVES Pipeline *
3  * Copyright (C) 2004,2005 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  * $Date: 2013-02-12 10:56:25 $
23  * $Revision: 1.92 $
24  * $Name: not supported by cvs2svn $
25  * $Log: not supported by cvs2svn $
26  * Revision 1.91 2012/10/27 15:26:23 amodigli
27  * fixed mem leak
28  *
29  * Revision 1.90 2012/03/02 16:53:31 amodigli
30  * fixed warning related to upgrade to CPL6
31  *
32  * Revision 1.89 2011/12/08 13:59:32 amodigli
33  * Fox warnings with CPL6
34  *
35  * Revision 1.88 2010/09/24 09:32:08 amodigli
36  * put back QFITS dependency to fix problem spot by NRI on FIBER mode (with MIDAS calibs) data
37  *
38  * Revision 1.86 2010/02/13 12:22:31 amodigli
39  * removed inlines (let's do work to compiler)
40  *
41  * Revision 1.85 2010/01/07 07:49:17 amodigli
42  * added some 'check_nomsg' statementsuves_utils.c
43  *
44  * Revision 1.84 2008/09/29 07:00:55 amodigli
45  * add #include <string.h>
46  *
47  * Revision 1.83 2007/08/21 13:08:26 jmlarsen
48  * Removed irplib_access module, largely deprecated by CPL-4
49  *
50  * Revision 1.82 2007/06/06 08:17:33 amodigli
51  * replace tab with 4 spaces
52  *
53  * Revision 1.81 2007/04/24 12:50:29 jmlarsen
54  * Replaced cpl_propertylist -> uves_propertylist which is much faster
55  *
56  * Revision 1.80 2007/04/10 07:11:35 jmlarsen
57  * Added check on input image type
58  *
59  * Revision 1.79 2007/03/05 10:20:22 jmlarsen
60  * Support slope parameter in 1d fitting
61  *
62  * Revision 1.78 2007/02/27 14:08:46 jmlarsen
63  * Extended interface of uves_find_property
64  *
65  * Revision 1.77 2007/01/29 12:14:49 jmlarsen
66  * Added uves_find_property()
67  *
68  * Revision 1.76 2007/01/15 08:48:20 jmlarsen
69  * Exported get_kth function
70  *
71  * Revision 1.75 2006/12/07 08:28:18 jmlarsen
72  * compute median as average of two middle elements
73  *
74  * Revision 1.74 2006/11/15 15:02:15 jmlarsen
75  * Implemented const safe workarounds for CPL functions
76  *
77  * Revision 1.72 2006/11/15 14:04:08 jmlarsen
78  * Removed non-const version of parameterlist_get_first/last/next which is already
79  * in CPL, added const-safe wrapper, unwrapper and deallocator functions
80  *
81  * Revision 1.71 2006/11/06 15:19:42 jmlarsen
82  * Removed unused include directives
83  *
84  * Revision 1.70 2006/09/19 07:17:08 jmlarsen
85  * Reformatted line
86  *
87  * Revision 1.69 2006/09/08 14:06:04 jmlarsen
88  * Added uves_tools_get_median()
89  *
90  * Revision 1.68 2006/08/23 09:33:03 jmlarsen
91  * Renamed local variables shadowing POSIX reserved names
92  *
93  * Revision 1.67 2006/08/18 14:21:03 jmlarsen
94  * Added code to support CPL3 median filtering
95  *
96  * Revision 1.66 2006/08/17 14:11:25 jmlarsen
97  * Use assure_mem macro to check for memory allocation failure
98  *
99  * Revision 1.65 2006/08/17 13:56:53 jmlarsen
100  * Reduced max line length
101  *
102  * Revision 1.64 2006/08/14 12:19:59 jmlarsen
103  * Removed unused functions
104  *
105  * Revision 1.63 2006/08/11 14:56:06 amodigli
106  * removed Doxygen warnings
107  *
108  * Revision 1.62 2006/08/10 10:54:09 jmlarsen
109  * Removed CX_PI definition
110  *
111  * Revision 1.61 2006/08/08 11:27:18 amodigli
112  * upgrade to CPL3
113  *
114  * Revision 1.60 2006/07/03 13:21:41 jmlarsen
115  * Changed 1d-fit parameter estimation method when only sky needs to be determined
116  *
117  * Revision 1.59 2006/06/13 12:02:22 jmlarsen
118  * Renamed y0 -> y_0
119  *
120  * Revision 1.58 2006/06/01 14:43:17 jmlarsen
121  * Added missing documentation
122  *
123  * Revision 1.57 2006/05/12 15:13:04 jmlarsen
124  * Pass image bpm as extra parameter to fitting routine for efficiency reasons
125  *
126  * Revision 1.56 2006/04/24 09:27:48 jmlarsen
127  * Allow fixing background in gauss. fit
128  *
129  * Revision 1.55 2006/03/09 13:54:44 jmlarsen
130  * Optimization of median computation
131  *
132  * Revision 1.54 2006/03/09 10:51:19 jmlarsen
133  * Changed order of for loops
134  *
135  * Revision 1.53 2006/03/03 13:54:11 jmlarsen
136  * Changed syntax of check macro
137  *
138  * Revision 1.52 2006/02/21 14:24:45 jmlarsen
139  * Parameterized behaviour of median filter near image border
140  *
141  * Revision 1.51 2006/01/31 08:25:49 jmlarsen
142  * Renamed uves_fit_gaussian_2d -> uves_fit_gaussian_2d_image
143  *
144  * Revision 1.50 2006/01/25 16:13:20 jmlarsen
145  * Changed interface of gauss.fitting routine
146  *
147  * Revision 1.49 2006/01/12 15:41:14 jmlarsen
148  * Moved gauss. fitting to irplib
149  *
150  * Revision 1.48 2005/12/20 08:11:44 jmlarsen
151  * Added CVS entry
152  *
153  */
154 
155 #ifdef HAVE_CONFIG_H
156 # include <config.h>
157 #endif
158 
159 /*----------------------------------------------------------------------------*/
166 /*----------------------------------------------------------------------------*/
167 
170 #include <uves_utils_cpl.h>
171 
172 #include <uves_utils.h>
173 #include <uves_utils_wrappers.h>
174 #include <uves_dump.h>
175 #include <uves_error.h>
176 
177 #include <cpl.h>
178 #include <stdbool.h>
179 #include <string.h>
180 
181 static cpl_image *filter_median(const cpl_image *image, int radx, int rady,
182  bool extrapolate_border);
183 
184 
185 /*----------------------------------------------------------------------------*/
197 /*----------------------------------------------------------------------------*/
198 const cpl_property *
199 uves_find_property_const(const uves_propertylist *plist, const char *name,
200  int number)
201 {
202  int i = 0;
203  int size = uves_propertylist_get_size(plist);
204 
205  assure( number >= 0, CPL_ERROR_ILLEGAL_INPUT, "Number (%d) must be non-negative",
206  number);
207 
208  for (i = 0; i < size; i++)
209  {
210  const cpl_property *p = uves_propertylist_get_const(plist, i);
211 
212  if (strcmp(cpl_property_get_name(p), name) == 0)
213  {
214  if (number == 0)
215  {
216  return p;
217  }
218  else
219  /* Continue search */
220  {
221  number--;
222  }
223  }
224  }
225 
226  cleanup:
227  return NULL;
228 }
229 cpl_property *
230 uves_find_property(uves_propertylist *plist, const char *name,
231  int number)
232 {
233  return (cpl_property *) uves_find_property_const(plist, name, number);
234 }
235 
236 /*----------------------------------------------------------------------------*/
248 /*----------------------------------------------------------------------------*/
249 cpl_error_code
250 uves_filter_image_average(cpl_image *image, int radius_x, int radius_y)
251 {
252  cpl_image *aux = NULL;
253  double *image_data = NULL;
254  double *aux_data = NULL;
255  int nx, ny;
256  int i;
257 
258  /* For bad pixel handling, create a similar auxillary image that counts the bad pixels */
259 
260  assure( image != NULL, CPL_ERROR_NULL_INPUT, "Null image");
261  assure( radius_x >= 0, CPL_ERROR_ILLEGAL_INPUT, "Negative x-radius (%d)", radius_x);
262  assure( radius_y >= 0, CPL_ERROR_ILLEGAL_INPUT, "Negative y-radius (%d)", radius_y);
263  assure( cpl_image_get_type(image) == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
264  "Type is %s. double expected", uves_tostring_cpl_type(cpl_image_get_type(image)));
265 
266  nx = cpl_image_get_size_x(image);
267  ny = cpl_image_get_size_y(image);
268  image_data = cpl_image_get_data_double(image);
269 
270  /* (Disabled:) To avoid problems with overflow (the total flux in the image might
271  be larger than INT_MAX) subtract a constant (the average flux), apply the filter,
272  then add the constant */
273 
274  /* First build auxillary image:
275  *
276  * aux(x,y) = sum_{i=0,x-1} sum_{j=0,y-1} image(i,j)
277  * = sum of rectangle (0,0)-(x-1,y-1)
278  *
279  */
280 
281  aux = cpl_image_new(nx+1, ny+1, CPL_TYPE_DOUBLE); /* Initialized to zero */
282  aux_data = cpl_image_get_data(aux);
283 
284  /* Column x=0 and row y=0 are already zero and need not be calculated,
285  * start from 1. */
286 
287 /* Slow: for (x = 1; x < nx+1; x++)
288  {
289  for (y = 1; y < ny+1; y++)
290  {
291 */
292  for (i = 0; i < (nx+1)*(ny+1); i++)
293  {
294  int x = i % (nx+1);
295  int y = i / (nx+1);
296 
297  if ( x >= 1 && y >= 1)
298  {
299  aux_data[x + y*(nx+1)] = image_data[x-1 + (y-1) * nx]
300  + aux_data [x-1 + y * (nx+1)]
301  + aux_data [x + (y-1)* (nx+1)]
302  - aux_data [x-1 + (y-1)* (nx+1)];
303  }
304 
305  /* Proof of induction step
306  * (assume that formula holds up to (x-1,y) and (x,y-1) and prove formula for (x,y))
307  *
308  * aux(x,y) = image(x-1, y-1) + aux(x-1, y) + aux(x, y-1) - aux(x-1, y-1) (see code)
309  *
310  * = image(x-1, y-1)
311  * + sum_{i=0,x-2}_{j=0,y-1} image(i,j) _
312  * + sum_{i=0,x-1}_{j=0,y-2} image(i,j) \_ sum_{j=0,y-2} image(x-1, j)
313  * - sum_{i=0,x-2}_{j=0,y-2} image(i,j) _/
314  *
315  * = sum_{i=0,x-2}_{j=0,y-1} image(i,j)
316  * + sum_ {j=0,y-1} image(x-1, j)
317  *
318  * = sum_{j=0,y-1} [ ( sum_{i=0,x-2} image(i,j) ) + image(x-1,j) ]
319  * = sum_{j=0,y-1} sum_{i=0,x-1} image(i,j) q.e.d.
320  *
321  * It's simpler when you draw it...
322  */
323  }
324 
325  uves_msg_debug("Finished setting up auxillary image. Get average");
326 
327  /* Then calculate average = (flux in window) / (image size) */
328  for (i = 0; i < nx*ny; i++)
329  {
330  int x = (i % nx);
331  int y = (i / nx);
332 
333  int lower, upper;
334  int left, right;
335 
336  lower = y - radius_y; if (lower < 0) lower = 0;
337  upper = y + radius_y; if (upper >= ny) upper = ny - 1;
338 
339  left = x - radius_x; if (left < 0) left = 0;
340  right = x + radius_x; if (right >= nx) right = nx - 1;
341 
342  image_data[x + y*nx] =
343  (
344  aux_data[(right+1) + (upper+1)*(nx+1)] +
345  aux_data[ left + lower *(nx+1)] -
346  aux_data[ left + (upper+1)*(nx+1)] -
347  aux_data[(right+1) + lower *(nx+1)]
348  )
349  /
350  ( (double) (upper-lower+1) * (right-left+1) );
351  }
352 
353  cleanup:
354  uves_free_image(&aux);
355  return cpl_error_get_code();
356 }
357 
358 
359 /*----------------------------------------------------------------------------*/
373 /*----------------------------------------------------------------------------*/
374 cpl_error_code
375 uves_filter_image_median(cpl_image **image, int xwindow, int ywindow, bool extrapolate_border)
376 {
377  cpl_matrix *id = NULL;
378  cpl_image *temp = NULL;
379 
380  assure( xwindow >= 0 && ywindow >= 0, CPL_ERROR_ILLEGAL_INPUT,
381  "Illegal window radius: %d x %d",
382  (2*xwindow + 1),
383  (2*ywindow + 1));
384 
385  UVES_TIME_START("median filter");
386 
387  if (xwindow <= 1 && ywindow <= 1)
388 /* CPL 3 supports if (xwindow <= 4 && ywindow <= 4) */
389  {
390  check(( id = cpl_matrix_new(2*xwindow+1, 2*ywindow+1),
391  cpl_matrix_fill(id, 1)), "Could not create kernel matrix");
392 
393  /* Image to cpl_image_filter_median must be float or double */
394  if (cpl_image_get_type(*image) == CPL_TYPE_INT)
395  {
396  temp = cpl_image_cast(*image, CPL_TYPE_DOUBLE);
397  uves_free_image(image);
398  }
399  else
400  {
401  temp = cpl_image_duplicate(*image);
402  uves_free_image(image);
403  }
404  check( *image = uves_image_filter_median(temp, id), "Error applying median filter");
405  uves_free_image(&temp);
406 
407  /* fixme: the CPL function marks border pixels as bad. Do something
408  depending on the extrapolate_border flag */
409  }
410  else
411  {
412  temp = *image;
413  check( *image = filter_median(temp, xwindow, ywindow, extrapolate_border),
414  "Error applying median filter");
415  uves_free_image(&temp);
416  }
417 
418  UVES_TIME_END;
419 
420  cleanup:
421  uves_free_matrix(&id);
422  uves_free_image(&temp);
423  return cpl_error_get_code();
424 }
425 
427 #define DOUBLE_SWAP(a,b) { register double t=(a);(a)=(b);(b)=t; }
428 
440  double * a,
441  int n,
442  int k)
443 {
444  register double x ;
445  register int i, j, l, m ;
446 
447  l=0 ; m=n-1 ;
448  while (l<m) {
449  x=a[k] ;
450  i=l ;
451  j=m ;
452  do {
453  while (a[i]<x) i++ ;
454  while (x<a[j]) j-- ;
455  if (i<=j) {
456  DOUBLE_SWAP(a[i],a[j]) ;
457  i++ ; j-- ;
458  }
459  } while (i<=j) ;
460  if (j<k) l=i ;
461  if (k<i) m=j ;
462  }
463  return a[k] ;
464 }
465 
474 double
475 uves_tools_get_median(double *a, int n)
476 {
477  if (n % 2 == 0)
478  {
479  return
480  (uves_utils_get_kth_double(a, n, n/2) +
481  uves_utils_get_kth_double(a, n, n/2-1))/2.0;
482 
483  }
484  else
485  {
486  return uves_utils_get_kth_double(a, n, (n-1)/2);
487  }
488 }
489 
490 
491 
492 /*----------------------------------------------------------------------------*/
514 /*----------------------------------------------------------------------------*/
515 static cpl_image *
516 filter_median(const cpl_image *image, int radx, int rady, bool extrapolate_border)
517 {
518  int x, y;
519  int nx = cpl_image_get_size_x(image);
520  int ny = cpl_image_get_size_y(image);
521  cpl_image *result = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
522  double *result_data;
523  const double *image_data;
524  double *window = NULL;
525 
526  window = cpl_malloc(sizeof(double) * (2*radx+1)*(2*rady+1));
527  assure_mem( result );
528  assure( cpl_image_get_type(image) == CPL_TYPE_DOUBLE,
529  CPL_ERROR_UNSUPPORTED_MODE, "Type is %s",
530  uves_tostring_cpl_type(cpl_image_get_type(image)));
531 
532  result_data = cpl_image_get_data_double(result);
533  image_data = cpl_image_get_data_double_const(image);
534 
535  for (y = 1; y <= ny; y++)
536  {
537  for (x = 1; x <= nx; x++)
538  {
539  int x1, y_1, x2, y2;
540 
541  x1 = x - radx; y_1 = y - rady;
542  x2 = x + radx; y2 = y + rady;
543 
544  if (extrapolate_border)
545  {
546  /* At edge of image, move median box, so
547  that entire box is inside of image */
548  if (x1 < 1)
549  {
550  x2 += (1 - x1);
551  x1 += (1 - x1);
552  }
553  if (nx < x2)
554  {
555  x1 -= (x2 - nx);
556  x2 -= (x2 - nx);
557  }
558 
559  if (y_1 < 1)
560  {
561  y2 += (1 - y_1);
562  y_1 += (1 - y_1);
563  }
564  if (ny < y2)
565  {
566  y_1 -= (y2 - ny);
567  y2 -= (y2 - ny);
568  }
569  }
570  else { /* Rely on the use of min/max below */ }
571 
572 #if 0
573  result_data[(x-1) + (y-1)*nx] =
574  cpl_image_get_median_window(image,
575  uves_max_int(1, x1),
576  uves_max_int(1, y_1),
577  uves_min_int(nx, x2),
578  uves_min_int(ny, y2));
579 
580 #else
581  /* This saves a few (~10-20) percent execution time */
582  {
583  int i, j, k;
584 
585  k = 0;
586  for (j = uves_max_int(1 , y_1)-1;
587  j <= uves_min_int(ny, y2 )-1;
588  j++)
589  for (i = uves_max_int(1, x1)-1;
590  i <= uves_min_int(nx, x2)-1;
591  i++)
592  {
593  window[k++] = image_data[i + j*nx];
594  }
595 
596  result_data[(x-1) + (y-1)*nx] =
597  uves_utils_get_kth_double(window,k,(((k)&1)?((k)/2):(((k)/2)-1))) ;
598  }
599 #endif
600  }
601  }
602 
603 
604  assure( cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
605  "Error calculating %dx%d median filter", radx, rady);
606 
607  cleanup:
608  cpl_free(window);
609  return result;
610 }
611 
612 
613 /*----------------------------------------------------------------------------*/
641 /*----------------------------------------------------------------------------*/
642 
643 cpl_error_code
644 uves_fit_gaussian_2d_image(const cpl_image *image, const cpl_image *noise,
645  int x1, int y_1,
646  int x2, int y2,
647  double *x0, double *y_0, double *sigmax, double *sigmay,
648  double *amplitude,
649  double *dx0, double *dy0
650  )
651 {
652  cpl_image *marginal_x = NULL;
653  cpl_image *marginal_y = NULL;
654  cpl_image *marginal_x_noise = NULL;
655  cpl_image *marginal_y_noise = NULL;
656  cpl_image *variance = NULL;
657  cpl_matrix *covariance = NULL;
658 
659  int nx, ny;
660  double norm_x, norm_y;
661  double background_x, background_y;
662 
663  /* Check input */
664  assure( image != NULL, CPL_ERROR_NULL_INPUT, "Null image");
665  nx = cpl_image_get_size_x(image);
666  ny = cpl_image_get_size_y(image);
667  assure( noise != NULL || (dx0 == NULL && dy0 == NULL), CPL_ERROR_INCOMPATIBLE_INPUT,
668  "Cannot compute uncertainty of fit with no noise image specified");
669  assure( noise == NULL ||
670  (cpl_image_get_size_x(noise) == nx &&
671  cpl_image_get_size_y(noise) == ny),
672  CPL_ERROR_INCOMPATIBLE_INPUT,
673  "Size of input image (%dx%d) and noise image (%" CPL_SIZE_FORMAT "x%" CPL_SIZE_FORMAT ") differ",
674  nx, ny,
675  cpl_image_get_size_x(noise),
676  cpl_image_get_size_y(noise));
677  assure( 1 <= x1 && x1 <= x2 && x2 <= nx &&
678  1 <= y_1 && y_1 <= y2 && y2 <= ny, CPL_ERROR_ILLEGAL_INPUT,
679  "Illegal window: (%d, %d)-(%d, %d)", x1, y_1, x2, y2);
680  assure( x0 != NULL, CPL_ERROR_NULL_INPUT, "Null x-center");
681  assure( y_0 != NULL, CPL_ERROR_NULL_INPUT, "Null y-center");
682  assure( sigmax != NULL, CPL_ERROR_NULL_INPUT, "Null sigma_x");
683  assure( sigmay != NULL, CPL_ERROR_NULL_INPUT, "Null sigma_y");
684  /* amplitude, dx0, dy0 may be NULL */
685 
686  if (noise != NULL)
687  {
688  /* Variance = noise^2 */
689  check(( variance = cpl_image_extract(noise, x1, y_1, x2, y2),
690  cpl_image_power(variance, 2.0)),
691  "Error creating variance image");
692  }
693 
694  /* Collapse along columns (result is horizontal) */
695  check( marginal_x = cpl_image_collapse_window_create(image,
696  x1, y_1, x2, y2,
697  0), /* Sum of columns */
698  "Error collapsing window (%d, %d) - (%d, %d)", x1, y_1, x2, y2);
699 
700  if (noise != NULL)
701  {
702  /* Sigma of sum = sqrt [ sum sigma_i^2 ] */
703 
704  check( marginal_x_noise = cpl_image_collapse_window_create(variance,
705  1, 1,
706  x2-x1+1, y2-y_1+1,
707  0), /* Sum of columns */
708  "Error collapsing window (1, 1) - (%d, %d)", x2-x1+1, y2-y_1+1);
709 
710  /* Sqrt */
711  cpl_image_power(marginal_x_noise, 0.5);
712  }
713 
714  /* Collapse along rows (result is vertical) */
715  check( marginal_y = cpl_image_collapse_window_create(image,
716  x1, y_1, x2, y2,
717  1), /* Sum of rows */
718  "Error collapsing window (%d, %d) - (%d, %d)", x1, y_1, x2, y2);
719 
720  if (noise != NULL)
721  {
722  check( marginal_y_noise = cpl_image_collapse_window_create(variance,
723  1, 1,
724  x2-x1+1, y2-y_1+1,
725  1), /* Sum of rows */
726  "Error collapsing window (1, 1) - (%d, %d)", x2-x1+1, y2-y_1+1);
727 
728  /* Sqrt */
729  cpl_image_power(marginal_y_noise, 0.5);
730  }
731 
732  /* Fit x-distribution */
733  uves_fit_1d_image(marginal_x, marginal_x_noise, NULL,
734  true, /* Horizontal ? */
735  false, false, /* Fix/fit background ? */
736  1, x2 - x1 + 1, 1, /* xlo, xhi, y */
737  x0, sigmax, &norm_x, &background_x, NULL,
738  NULL, NULL, /* mse, red. chi^2 */
739  (dx0 != NULL) ? &covariance : NULL,
741 
742  /* Set code 'CPL_ERROR_CONTINUE' if fitting failed, check for unexpected errors */
743  assure( cpl_error_get_code() != CPL_ERROR_CONTINUE ||
744  cpl_error_get_code() != CPL_ERROR_SINGULAR_MATRIX,
745  CPL_ERROR_CONTINUE, "Fitting along x failed");
746  assure( cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
747  "Fitting along x failed");
748 
749  /* Map to world-coordinates */
750  *x0 += (x1 - 1);
751 
752  if (dx0 != NULL)
753  {
754  *dx0 = cpl_matrix_get(covariance, 0, 0);
755  }
756 
757 
758  /* Fit y-distribution */
759  uves_free_matrix(&covariance);
760  uves_fit_1d_image(marginal_y, marginal_y_noise, NULL,
761  false, /* Horizontal ? */
762  false, false, /* Fix/fit background ? */
763  1, y2 - y_1 + 1, 1, /* ylo, yhi, x */
764  y_0, sigmay, &norm_y, &background_y, NULL,
765  NULL, NULL, /* mse, red. chi^2 */
766  (dy0 != NULL) ? &covariance : NULL,
768 
769  /* Set code 'CPL_ERROR_CONTINUE' if fitting failed, check for unexpected errors */
770  assure( cpl_error_get_code() != CPL_ERROR_CONTINUE ||
771  cpl_error_get_code() != CPL_ERROR_SINGULAR_MATRIX,
772  CPL_ERROR_CONTINUE, "Fitting along y failed");
773  assure( cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
774  "Fitting along y failed");
775 
776  /* Map to world-coordinates */
777  *y_0 += (y_1 - 1);
778 
779  if (dy0 != NULL)
780  {
781  *dy0 = cpl_matrix_get(covariance, 0, 0);
782  }
783 
784  /* Set amplitude = N / [ sqrt(2pi sigmax^2) sqrt(2pi sigmay^2) ].
785  *
786  * The fitted norm (area), N, is the same (up to numerical errors) in both directions,
787  * so use geometric average as an estimate of N.
788  */
789  if (amplitude != NULL)
790  {
791  *amplitude = sqrt(norm_x * norm_y) / (2*M_PI * (*sigmax) * (*sigmay));
792  }
793 
794  cleanup:
795  uves_free_matrix(&covariance);
796  uves_free_image(&variance);
797  uves_free_image(&marginal_x);
798  uves_free_image(&marginal_x_noise);
799  uves_free_image(&marginal_y);
800  uves_free_image(&marginal_y_noise);
801 
802  return cpl_error_get_code();
803 }
804 
805 
const cpl_property * uves_propertylist_get_const(const uves_propertylist *self, long position)
Access property list elements by index.
cpl_error_code uves_filter_image_median(cpl_image **image, int xwindow, int ywindow, bool extrapolate_border)
Median filter.
cpl_error_code uves_fit_gaussian_2d_image(const cpl_image *image, const cpl_image *noise, int x1, int y_1, int x2, int y2, double *x0, double *y_0, double *sigmax, double *sigmay, double *amplitude, double *dx0, double *dy0)
Fit a 2d gaussian to an image sub-window.
cpl_error_code uves_filter_image_average(cpl_image *image, int radius_x, int radius_y)
Average filter.
int uves_gauss_derivative(const double x[], const double a[], double result[])
Evaluate the derivatives of a gaussian.
Definition: uves_utils.c:4346
static cpl_image * filter_median(const cpl_image *image, int radx, int rady, bool extrapolate_border)
Median filter.
long uves_propertylist_get_size(const uves_propertylist *self)
Get the current size of a property list.
int uves_gauss(const double x[], const double a[], double *result)
Evaluate a gaussian.
Definition: uves_utils.c:4291
#define assure_mem(PTR)
Definition: uves_error.h:181
double uves_tools_get_median(double *a, int n)
returns median (not CPL median) of an array
const char * uves_tostring_cpl_type(cpl_type t)
Convert a CPL type to a string.
Definition: uves_dump.c:378
#define uves_msg_debug(...)
Print a debug message.
Definition: uves_msg.h:97
const cpl_property * uves_find_property_const(const uves_propertylist *plist, const char *name, int number)
Find named property.
#define check(CMD,...)
Definition: uves_error.h:198
double uves_utils_get_kth_double(double *a, int n, int k)
returns the kth value of an array