FORS Pipeline Reference Manual  5.0.2
fors_image.c
1 /* $Id: fors_image.c,v 1.63 2013-08-07 13:24:40 cgarcia Exp $
2  *
3  * This file is part of the FORS Library
4  * Copyright (C) 2002-2010 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /*
22  * $Author: cgarcia $
23  * $Date: 2013-08-07 13:24:40 $
24  * $Revision: 1.63 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 #include <fors_image.h>
33 
34 #include <fors_dfs.h>
35 #include <fors_utils.h>
36 #include <fors_pfits.h>
37 #include <fors_double.h>
38 #include <fors_saturation.h>
39 #include <fors_subtract_bias.h>
40 #include <moses.h>
41 
42 #include <cpl.h>
43 
44 #include <math.h>
45 #include <stdbool.h>
46 #include <stdio.h>
47 
48 
52 const cpl_type FORS_IMAGE_TYPE = CPL_TYPE_FLOAT;
53 #define FORS_IMAGE_TYPE_MAX FLT_MAX /* Use a #define rather than a variable here
54  to avoid type casting */
55 
56 #undef cleanup
57 
58 /*
59  * The following static function passes a max filter of given box
60  * size on the input data buffer. The output data buffer must be
61  * pre-allocated. The box size must be a positive odd integer.
62  * Returns 0 on success.
63  */
64 
65 static int
66 max_filter(const float *ibuffer, float *obuffer, int length, int size)
67 {
68  float max;
69  int start = size / 2;
70  int end = length - size / 2;
71  int i, j;
72 
73 
74  for (i = start; i < end; i++) {
75  max = ibuffer[i-start];
76  for (j = i - start + 1; j <= i + start; j++)
77  if (max < ibuffer[j])
78  max = ibuffer[j];
79  obuffer[i] = max;
80  }
81 
82  for (i = 0; i < start; i++)
83  obuffer[i] = obuffer[start];
84 
85  for (i = end; i < length; i++)
86  obuffer[i] = obuffer[end-1];
87 
88  return 0;
89 }
90 
91 #define cleanup
92 
101 fors_image *
102 fors_image_new(cpl_image *data, cpl_image *variance)
103 {
104  fors_image *image = NULL;
105 
106  assure( data != NULL, return NULL, NULL );
107  assure( variance != NULL, return NULL, NULL );
108 
109 //TODO: Changed to allow saving as double. Check the consequences.
110 // assure( cpl_image_get_type(data) == FORS_IMAGE_TYPE, return NULL,
111 // "Provided data image type is %s, must be %s",
112 // fors_type_get_string(cpl_image_get_type(data)),
113 // fors_type_get_string(FORS_IMAGE_TYPE) );
114 
115 // assure( cpl_image_get_type(variance) == FORS_IMAGE_TYPE, return NULL,
116 // "Provided weight image type is %s, must be %s",
117 // fors_type_get_string(cpl_image_get_type(variance)),
118 // fors_type_get_string(FORS_IMAGE_TYPE) );
119 
120  assure( cpl_image_get_size_x(data) == cpl_image_get_size_x(variance) &&
121  cpl_image_get_size_y(data) == cpl_image_get_size_y(variance),
122  return NULL,
123  "Incompatible data and weight image sizes: "
124  "%"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT
125  " and %"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT,
126  cpl_image_get_size_x(data), cpl_image_get_size_y(data),
127  cpl_image_get_size_x(variance), cpl_image_get_size_y(variance));
128 
129  assure( cpl_image_get_min(variance) >= 0, return NULL,
130  "Variances must be non-negative, minimum is %g. \n"
131  "This is most likely a software bug. "
132  "You may contact usd-help@eso.org which can provide a workaround.",
133  cpl_image_get_min(variance));
134 
135  image = cpl_malloc(sizeof(*image));
136 
137  image->data = data;
138  image->variance = variance;
139 
140  return image;
141 }
142 
143 #undef cleanup
144 #define cleanup
145 
150 fors_image *
152 {
153  assure( image != NULL, return NULL, NULL );
154 
155  return fors_image_new(cpl_image_duplicate(image->data),
156  cpl_image_duplicate(image->variance));
157 }
158 
163 void
165 {
166  if (image && *image) {
167  cpl_image_delete((*image)->data);
168  cpl_image_delete((*image)->variance);
169  cpl_free(*image); *image = NULL;
170  }
171  return;
172 }
173 
178 void
180 {
181  fors_image_delete((fors_image **)image);
182 
183  return;
184 }
185 
186 /* not used */
187 #if 0
188 
192 static void
193 fors_image_dump(const fors_image *image, FILE *file)
194 {
195  if (image == NULL) {
196  fprintf(file, "Null image\n");
197  }
198  else {
199  cpl_stats *stats;
200 
201  fprintf(file, "Data:\n");
202  stats = cpl_stats_new_from_image(image->data, CPL_STATS_ALL);
203  cpl_stats_dump(stats, CPL_STATS_ALL, file);
204  cpl_stats_delete(stats);
205 
206  fprintf(file, "Variance:\n");
207  stats = cpl_stats_new_from_image(image->variance, CPL_STATS_ALL);
208  cpl_stats_dump(stats, CPL_STATS_ALL, file);
209  cpl_stats_delete(stats);
210  }
211 
212  return;
213 }
214 #endif
215 
216 #undef cleanup
217 #define cleanup \
218 do { \
219  double_list_delete(&sat_percent, double_delete); \
220 } while (0)
221 
235 fors_image_list *
236 fors_image_load_list(const cpl_frameset *frames)
237 {
238  fors_image_list *ilist = fors_image_list_new();
239  double_list *sat_percent = double_list_new();
240 
241  assure( frames != NULL, return ilist, NULL );
242  assure( !cpl_frameset_is_empty(frames), return ilist, "Empty frameset");
243 
244  {
245  const cpl_frame *f;
246 
247  for (int i =0; i< cpl_frameset_get_size(frames); i ++)
248  {
249  f = cpl_frameset_get_position_const(frames, i);
250 
251  fors_image *ima = fors_image_load(f);
252 
253  fors_image_list_insert(ilist, ima);
254  }
255  }
256 
257  cleanup;
258  return ilist;
259 }
260 
272 const fors_image_list *
273 fors_image_load_list_const(const cpl_frameset *frames)
274 {
275  return (const fors_image_list *)
276  fors_image_load_list(frames);
277 }
278 
279 #undef cleanup
280 #define cleanup \
281 do { \
282  cpl_image_delete(temp); \
283 } while (0)
284 
291 fors_image *
292 fors_image_load(const cpl_frame *frame)
293 {
294  fors_image *image = NULL;
295  cpl_image *data = NULL;
296  cpl_image *variance = NULL;
297  cpl_image *temp = NULL;
298  const char *filename;
299  int extension= 0;
300  const int plane = 0;
301 
302  assure( frame != NULL, return image, NULL );
303  /* bias may be NULL */
304  filename = cpl_frame_get_filename(frame);
305  assure( filename != NULL, return image,
306  "NULL filename received");
307 
308  cpl_msg_info(cpl_func, "Loading %s: %s",
309  /* fors_frame_get_group_string(frame), */
310  (cpl_frame_get_tag(frame) != NULL) ?
311  cpl_frame_get_tag(frame) : "NULL",
312  filename);
313 
314  /* Get data */
315  data = cpl_image_load(filename,
316  FORS_IMAGE_TYPE, plane, extension);
317 
318  assure( !cpl_error_get_code(), return image,
319  "Could not load image from %s extension %d",
320  filename, extension);
321 
322 
323  /* Read variance if it exists */
324  if (cpl_frame_get_nextensions(frame) == 0) {
325 
326  /* Create an empty variance */
327  variance = cpl_image_new(
328  cpl_image_get_size_x(data),
329  cpl_image_get_size_y(data),
330  FORS_IMAGE_TYPE);
331 
332  }
333  else {
334 
335  extension = 1;
336 
337  /* Get error bars */
338  variance = cpl_image_load(filename,
339  FORS_IMAGE_TYPE, plane, extension);
340 
341  assure( !cpl_error_get_code(), return image,
342  "Could not load image from %s extension %d",
343  filename, extension);
344 
345  cpl_image_power(variance, 2);
346 
347  assure( cpl_image_get_min(variance) >= 0, return image,
348  "Illegal minimum variance: %g",
349  cpl_image_get_min(variance));
350 
351  cpl_image_delete(temp); temp = NULL;
352  }
353 
354  image = fors_image_new(data, variance);
355 
356  cleanup;
357  return image;
358 }
359 
360 
361 #undef cleanup
362 #define cleanup \
363 do { \
364  cpl_image_delete(sigma); \
365  cpl_propertylist_delete(extension_header); \
366 } while(0)
367 
376 void
377 fors_image_save(const fors_image *image, const cpl_propertylist *header,
378  const char *filename)
379 {
380  cpl_propertylist *extension_header = NULL;
381  cpl_image *sigma = NULL;
382 
383  assure( image != NULL, return, NULL );
384  /* header may be NULL */
385  assure( filename != NULL, return, NULL );
386 
387  cpl_image_save(image->data, filename, CPL_BPP_IEEE_FLOAT, header,
388  CPL_IO_DEFAULT);
389  assure( !cpl_error_get_code(), return,
390  "Cannot save product %s", filename);
391 
392  sigma = cpl_image_power_create(image->variance, 0.5);
393  /* This would probably be faster if sqrt() is used rather than pow */
394  extension_header = cpl_propertylist_new();
395  cpl_propertylist_append_string(extension_header,
396  "EXTNAME", "IMAGE.ERR");
397 
398  cpl_image_save(sigma, filename, CPL_BPP_IEEE_FLOAT, extension_header,
399  CPL_IO_EXTEND);
400  assure( !cpl_error_get_code(), return,
401  "Cannot save product %s", filename);
402 
403  cleanup;
404  return;
405 }
406 
407 
408 #undef cleanup
409 #define cleanup \
410 do { \
411  cpl_image_delete(var_bkg); \
412  cpl_image_delete(sigma_bkg); \
413 } while(0)
414 
425 void
426 fors_image_save_sex(const fors_image *image, const cpl_propertylist *header,
427  const char *filename_dat,
428  const char *filename_var,
429  int radius)
430 {
431  cpl_propertylist *extension_header = NULL;
432  cpl_image *sigma_bkg = NULL;
433  cpl_image *var_bkg = NULL;
434 
435  assure( image != NULL, return, NULL );
436  /* header may be NULL */
437  assure( filename_dat != NULL, return, NULL );
438  assure( filename_var != NULL, return, NULL );
439 
440  cpl_image_save(image->data, filename_dat, CPL_BPP_IEEE_FLOAT, header,
441  CPL_IO_DEFAULT);
442  assure( !cpl_error_get_code(), return,
443  "Cannot save product %s", filename_dat);
444 
445  /* Sextractor wants as input the background error bars,
446  i.e. excluding sources.
447  Therefore filter away sources but keep the sharp edges
448  between the illuminated / non-illuminated areas.
449 
450  I.e. use a median filter, average filter would not work.
451  */
452 
453  cpl_msg_info(cpl_func, "Creating background error map");
454 
455  bool filter_data = false; /* filter the variance image */
456  int xstep = radius/2; /* 25 points sampling grid
457  . . . . .
458  . . . . .
459  . . . . .
460  . . . . .
461  . . . . .
462  */
463  int ystep = radius/2;
464  int xstart = 1;
465  int ystart = 1;
466  int xend = fors_image_get_size_x(image);
467  int yend = fors_image_get_size_y(image);
468 
469 
470  var_bkg = fors_image_filter_median_create(image,
471  radius,
472  radius,
473  xstart, ystart,
474  xend, yend,
475  xstep, ystep,
476  filter_data);
477  assure( !cpl_error_get_code(), return,
478  "Median filtering failed");
479 
480  sigma_bkg = cpl_image_power_create(var_bkg, 0.5);
481 
482  cpl_image_save(sigma_bkg, filename_var,
483  CPL_BPP_IEEE_FLOAT, extension_header,
484  CPL_IO_DEFAULT);
485  assure( !cpl_error_get_code(), return,
486  "Cannot save product %s", filename_var);
487 
488  cleanup;
489  return;
490 }
491 
492 #undef cleanup
493 #define cleanup
494 
499 cpl_size fors_image_get_size_x(const fors_image *image)
500 {
501  assure( image != NULL, return -1, NULL );
502  return cpl_image_get_size_x(image->data);
503 }
504 
505 #undef cleanup
506 #define cleanup
507 
512 cpl_size fors_image_get_size_y(const fors_image *image)
513 {
514  assure( image != NULL, return -1, NULL );
515  return cpl_image_get_size_y(image->data);
516 }
517 
518 #undef cleanup
519 #define cleanup
520 
524 const float *fors_image_get_data_const(const fors_image *image)
525 {
526  assure( image != NULL, return NULL, NULL );
527 
528  assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return NULL, NULL );
529  /* This function (including API) would need to change
530  if the pixel type changes */
531 
532  return cpl_image_get_data_float(image->data);
533 }
534 
535 #undef cleanup
536 #define cleanup
537 
544 void
546 {
547  assure( image != NULL, return, NULL );
548 
549  cpl_image_abs(image->data);
550 
551  return;
552 }
553 
554 #undef cleanup
555 #define cleanup
556 
563 void
565 {
566  assure( image != NULL, return, NULL );
567 
568  cpl_image_multiply(image->data, image->data);
569  /* It is an undocumented feature of CPL that you
570  can pass the same image to cpl_image_multiply and get
571  the right answer. Let us hope it does not change...
572  */
573  cpl_image_multiply_scalar(image->variance, 2);
574 
575  return;
576 }
577 
578 
579 #undef cleanup
580 #define cleanup \
581 do { \
582  cpl_image_delete(temp); \
583 } while(0)
584 
592 void
594 {
595  cpl_image *temp = NULL;
596  assure( left != NULL, return, NULL );
597  assure( right != NULL, return, NULL );
598 
599  cpl_image_subtract(left->data, right->data);
600 
601  /* variance_left := variance_left + variance_right */
602  cpl_image_add(left->variance, right->variance);
603 
604  cleanup;
605  return;
606 }
607 
608 #undef cleanup
609 #define cleanup
610 
620 void
621 fors_image_multiply_noerr(fors_image *left, const cpl_image *right)
622 {
623  assure( left != NULL, return, NULL );
624  assure( right != NULL, return, NULL );
625  assure( cpl_image_get_size_x(left->data) == cpl_image_get_size_x(right) &&
626  cpl_image_get_size_y(left->data) == cpl_image_get_size_y(right),
627  return,
628  "Incompatible data and weight image sizes: "
629  "%"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT
630  " and %"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT,
631  cpl_image_get_size_x(left->data),
632  cpl_image_get_size_y(left->data),
633  cpl_image_get_size_x(right),
634  cpl_image_get_size_y(right));
635 
636  cpl_image_multiply(left->data, right);
637  cpl_image_multiply(left->variance, right);
638  cpl_image_multiply(left->variance, right);
639 
640  return;
641 }
642 
643 #undef cleanup
644 #define cleanup
645 
661 void
662 fors_image_divide_noerr(fors_image *left, cpl_image *right)
663 {
664  assure( left != NULL, return, NULL );
665  assure( right != NULL, return, NULL );
666  assure( cpl_image_get_size_x(left->data) == cpl_image_get_size_x(right) &&
667  cpl_image_get_size_y(left->data) == cpl_image_get_size_y(right),
668  return,
669  "Incompatible data and weight image sizes: "
670  "%"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT
671  " and %"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT,
672  cpl_image_get_size_x(left->data),
673  cpl_image_get_size_y(left->data),
674  cpl_image_get_size_x(right),
675  cpl_image_get_size_y(right));
676 
677  int x, y;
678  int nx = cpl_image_get_size_x(right);
679  int ny = cpl_image_get_size_y(right);
680  float *datal = cpl_image_get_data_float(left->data);
681  float *datav = cpl_image_get_data_float(left->variance);
682  float *datar = cpl_image_get_data_float(right);
683  for (y = 0; y < ny; y++) {
684  for (x = 0; x < nx; x++) {
685  if (datar[x + nx*y] == 0) {
686  datar[x + nx*y] = 1;
687  datal[x + nx*y] = 1;
688 
689  datav[x + nx*y] = FORS_IMAGE_TYPE_MAX;
690  }
691  }
692  }
693 
694  cpl_image_divide(left->data, right);
695  cpl_image_divide(left->variance, right);
696  cpl_image_divide(left->variance, right);
697 
698  return;
699 }
700 
701 #undef cleanup
702 #define cleanup \
703 do { \
704  fors_image_delete(&dupl); \
705 } while(0)
706 
726 void
728 {
729  fors_image *dupl = NULL;
730 
731  assure( left != NULL, return, NULL );
732  assure( right != NULL, return, NULL );
733 
734  dupl = fors_image_duplicate(right);
735 
736  cpl_image_divide(left->data, dupl->data);
737  /* This CPL function divides by zero by setting x/0 = 1 for all x */
738 
739  cpl_image_multiply(dupl->variance, left->data);
740  cpl_image_multiply(dupl->variance, left->data);
741 
742  /* Now dupl->variance = sigma2^2 * data1^2 / data2^2 */
743 
744  cpl_image_add(left->variance, dupl->variance);
745 
746  /* Now left->variance = sigma1^2 + sigma2^2 * data1^2 / data2^2 */
747 
748  cpl_image_divide(left->variance, dupl->data);
749  cpl_image_divide(left->variance, dupl->data);
750  /* QED */
751 
752  /* Handle division by zero */
753  int x, y;
754  int nx = cpl_image_get_size_x(left->data);
755  int ny = cpl_image_get_size_y(left->data);
756  float *datal = cpl_image_get_data_float(left->data);
757  float *datav = cpl_image_get_data_float(left->variance);
758  float *datar = cpl_image_get_data_float(right->data);
759  for (y = 0; y < ny; y++) {
760  for (x = 0; x < nx; x++) {
761  if (datar[x + nx*y] == 0) {
762  datal[x + nx*y] = 1;
763  datav[x + nx*y] = FORS_IMAGE_TYPE_MAX;
764  }
765  }
766  }
767 
768  cleanup;
769  return;
770 }
771 
772 #undef cleanup
773 #define cleanup \
774 do { \
775  cpl_image_delete(s22d12); \
776 } while(0)
777 
788 void
790 {
791  cpl_image *s22d12 = NULL;
792 
793  assure( left != NULL, return, NULL );
794  assure( right != NULL, return, NULL );
795 
796  s22d12 = cpl_image_duplicate(right->variance);
797  cpl_image_multiply(s22d12, left->data);
798  cpl_image_multiply(s22d12, left->data);
799 
800  cpl_image_multiply(left->variance, right->data);
801  cpl_image_multiply(left->variance, right->data);
802  cpl_image_add(left->variance, s22d12);
803 
804  cpl_image_multiply(left->data, right->data);
805 
806  cleanup;
807  return;
808 }
809 
810 
811 #undef cleanup
812 #define cleanup
813 
825 void fors_image_subtract_scalar(fors_image *image, double s, double ds)
826 {
827  assure( image != NULL, return, NULL );
828  assure( ds <= 0, return, "Unsupported");
829 
830  cpl_image_subtract_scalar(image->data, s);
831 
832  return;
833 }
834 
835 
836 #undef cleanup
837 #define cleanup
838 
850 void fors_image_divide_scalar(fors_image *image, double s, double ds)
851 {
852  assure( image != NULL, return, NULL );
853  assure( s != 0, return, "Division by zero");
854  assure( ds <= 0, return, "Unsupported");
855 
856  cpl_image_divide_scalar(image->data, s);
857  cpl_image_divide_scalar(image->variance, s*s);
858 
859  return;
860 }
861 
862 #undef cleanup
863 #define cleanup
864 
876 void fors_image_multiply_scalar(fors_image *image, double s, double ds)
877 {
878  assure( image != NULL, return, NULL );
879  assure( ds <= 0, return, "Unsupported");
880 
881  cpl_image_multiply_scalar(image->data, s);
882  cpl_image_multiply_scalar(image->variance, s*s);
883 
884  return;
885 }
886 
887 #undef cleanup
888 #define cleanup \
889 do { \
890  cpl_image_delete(temp); \
891 } while(0)
892 
905 void fors_image_exponential(fors_image *image, double b, double db)
906 {
907  cpl_image *temp = NULL;
908 
909  assure( image != NULL, return, NULL );
910  assure( b >= 0, return, "Negative base: %f", b);
911  assure( db <= 0, return, "Unsupported");
912 
913  cpl_image_exponential(image->data, b);
914 
915  double lnb = log(b);
916 
917  cpl_image_multiply_scalar(image->variance, lnb*lnb);
918  cpl_image_multiply(image->variance, image->data);
919  cpl_image_multiply(image->variance, image->data);
920 
921  return;
922 }
923 
924 
925 #undef cleanup
926 #define cleanup
927 
932 double
934 {
935  assure( image != NULL, return 0, NULL );
936 
937  return cpl_image_get_min(image->data);
938 }
939 
940 #undef cleanup
941 #define cleanup
942 
947 double
949 {
950  assure( image != NULL, return 0, NULL );
951 
952  return cpl_image_get_max(image->data);
953 }
954 
955 #undef cleanup
956 #define cleanup
957 
963 double
964 fors_image_get_mean(const fors_image *image, double *dmean)
965 {
966  assure( image != NULL, return 0, NULL );
967  assure( dmean == NULL, return 0, "Unsupported");
968 
969  return cpl_image_get_mean(image->data);
970 }
971 
972 #undef cleanup
973 #define cleanup
974 
980 double
981 fors_image_get_median(const fors_image *image, double *dmedian)
982 {
983  assure( image != NULL, return 0, NULL );
984  assure( dmedian == NULL, return 0, "Unsupported");
985 
986  return cpl_image_get_median(image->data);
987 }
988 
989 
990 #undef cleanup
991 #define cleanup
992 
1007  int xlo, int ylo,
1008  int xhi, int yhi)
1009 {
1010  /* CPL is missing the function to locally extract an image,
1011  so this this inefficient CPL function */
1012  assure( image != NULL, return, NULL );
1013  assure( 1 <= xlo && xlo <= xhi && xhi <= fors_image_get_size_x(image) &&
1014  1 <= ylo && ylo <= yhi && yhi <= fors_image_get_size_y(image),
1015  return, "Cannot extraction region (%d, %d) - (%d, %d) of "
1016  "%"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT" image",
1017  xlo, ylo, xhi, yhi,
1018  fors_image_get_size_x(image),
1019  fors_image_get_size_y(image));
1020 
1021  cpl_image *new_data = cpl_image_extract(image->data,
1022  xlo, ylo,
1023  xhi, yhi);
1024  cpl_image_delete(image->data);
1025 
1026  cpl_image* new_variance = cpl_image_extract(image->variance,
1027  xlo, ylo,
1028  xhi, yhi);
1029  cpl_image_delete(image->variance);
1030 
1031  image->data = new_data;
1032  image->variance = new_variance;
1033 
1034  return;
1035 }
1036 
1062 cpl_image *
1064  int xradius,
1065  int yradius,
1066  int xstart,
1067  int ystart,
1068  int xend,
1069  int yend,
1070  int xstep,
1071  int ystep,
1072  bool use_data)
1073 {
1074  const cpl_image *input = NULL;
1075  cpl_image *smooth = NULL;
1076  int nx, ny;
1077 
1078  assure( image != NULL, return smooth, NULL );
1079  passure( image->data != NULL, return smooth );
1080  passure( image->variance != NULL, return smooth );
1081 
1082  input = (use_data) ? image->data : image->variance;
1083 
1084  nx = cpl_image_get_size_x(input);
1085  ny = cpl_image_get_size_y(input);
1086 
1087  if (xstep < 1) xstep = 1;
1088  if (ystep < 1) ystep = 1;
1089 
1090  assure( 1 <= xstart && xstart <= xend && xend <= nx &&
1091  1 <= ystart && ystart <= yend && yend <= ny, return smooth,
1092  "Illegal region (%d, %d) - (%d, %d) of %dx%d image",
1093  xstart, ystart,
1094  xend, yend,
1095  nx, ny);
1096 
1097  smooth = cpl_image_duplicate(input);
1098 
1099  /* For efficiency reasons, assume that the image type is float */
1100  assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return smooth, NULL );
1101 
1102  const float *input_data = cpl_image_get_data_float_const(input);
1103  float *smooth_data = cpl_image_get_data_float(smooth);
1104  float *data = cpl_malloc((2*yradius + 1)*(2*xradius + 1)*sizeof(*data));
1105 
1106  int y;
1107  for (y = ystart; y < yend; y++) {
1108  /*
1109  Sample kernel on grid which always contains the central pixel
1110 
1111  Trim window (note: this will cause fewer values to
1112  be used for the median near the region borders
1113  */
1114  int ylo = y - (yradius/ystep) * ystep;
1115  int yhi = y + (yradius/ystep) * ystep;
1116 
1117  while (ylo < ystart) ylo += ystep;
1118  while (yhi > yend ) yhi -= ystep;
1119 
1120  int x;
1121  for (x = xstart; x < xend; x++) {
1122  int xlo = x - (xradius/xstep) * xstep;
1123  int xhi = x + (xradius/xstep) * xstep;
1124 
1125  while (xlo < xstart) xlo += xstep;
1126  while (xhi > xend ) xhi -= xstep;
1127 
1128  /* Collect data */
1129  int k = 0;
1130  int j, i;
1131  for (j = ylo; j <= yhi; j += ystep) {
1132  for (i = xlo; i <= xhi; i += xstep) {
1133  data[k++] = input_data[ (i-1) + (j-1)*nx ];
1134  }
1135  }
1136 
1137  /* Get median */
1138  smooth_data[ (x-1) + (y-1)*nx ] =
1139  fors_tools_get_median_float(data, k);
1140  }
1141  }
1142 
1143  cpl_free(data);
1144  return smooth;
1145 }
1146 
1147 #undef cleanup
1148 #define cleanup \
1149 do { \
1150  cpl_image_delete(input); \
1151 } while(0)
1152 cpl_image *
1153 fors_image_flat_fit_create(fors_image *image,
1154  int step,
1155  int degree,
1156  float level)
1157 {
1158  cpl_image *temp = NULL;
1159  cpl_image *input = NULL;
1160  cpl_image *smooth = NULL;
1161  int nx, ny;
1162 
1163  assure( image != NULL, return smooth, NULL );
1164  passure( image->data != NULL, return smooth );
1165  assure( step > 0, return smooth, NULL );
1166  assure( degree >= 0, return smooth, NULL );
1167 
1168 
1169  temp = image->data;
1170 
1171  nx = cpl_image_get_size_x(temp);
1172  ny = cpl_image_get_size_y(temp);
1173 
1174  /*
1175  * For efficiency reasons, assume that the image type is float
1176  */
1177 
1178  assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return smooth, NULL );
1179 
1180  /*
1181  * Apply light median filter, to eliminate big outliers from fit
1182  */
1183 
1184  input = mos_image_filter_median(image->data, 3, 3);
1185 
1186  const float *input_data = cpl_image_get_data_float_const(input);
1187 
1188  /*
1189  * First of all, count how many points will have to be fitted
1190  */
1191 
1192  int x, y, pos;
1193  int count = 0;
1194  for (y = 0; y < ny; y += step) {
1195  pos = y*nx;
1196  for (x = 0; x < nx; x += step, pos += step) {
1197  if (input_data[pos] > level) {
1198  count++;
1199  }
1200  }
1201  }
1202 
1203  if (count < (degree+1)*(degree+2)) {
1204  step = sqrt((nx*nx)/((degree+1)*(degree+2))) / 2;
1205  if (step == 0)
1206  step = 1;
1207  cpl_msg_error(cpl_func, "Flat field image too small (%dx%d). "
1208  "Please provide a smaller resampling step (a good "
1209  "value would be %d)", nx, ny, step);
1210  cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
1211  cleanup;
1212  return NULL;
1213  }
1214 
1215 
1216  /*
1217  * Fill position and flux vectors with appropriate values
1218  */
1219 
1220  cpl_bivector *positions = cpl_bivector_new(count);
1221  double *xpos = cpl_bivector_get_x_data(positions);
1222  double *ypos = cpl_bivector_get_y_data(positions);
1223  cpl_vector *fluxes = cpl_vector_new(count);
1224  double *flux = cpl_vector_get_data(fluxes);
1225 
1226  count = 0;
1227  for (y = 0; y < ny; y += step) {
1228  pos = y*nx;
1229  for (x = 0; x < nx; x += step, pos += step) {
1230  if (input_data[pos] > level) {
1231  xpos[count] = x;
1232  ypos[count] = y;
1233  flux[count] = input_data[pos];
1234  count++;
1235  }
1236  }
1237  }
1238 
1239  cpl_image_delete(input); input = NULL;
1240 
1241  /*
1242  * Do the fit, and fill the output image with the model
1243  * values in all pixels.
1244  */
1245 
1246  cpl_polynomial *model = cpl_polynomial_fit_2d_create(positions,
1247  fluxes,
1248  degree,
1249  NULL);
1250 
1251  cpl_bivector_delete(positions);
1252  cpl_vector_delete(fluxes);
1253 
1254  smooth = cpl_image_new(nx, ny, FORS_IMAGE_TYPE);
1255  float *smooth_data = cpl_image_get_data_float(smooth);
1256 
1257  cpl_vector *point = cpl_vector_new(2);
1258  double *dpoint = cpl_vector_get_data(point);
1259 
1260  for (y = 0; y < ny; y++) {
1261  pos = y*nx;
1262  dpoint[1] = y;
1263  for (x = 0; x < nx; x++, pos++) {
1264  dpoint[0] = x;
1265  smooth_data[pos] = cpl_polynomial_eval(model, point);
1266  }
1267  }
1268 
1269  cpl_polynomial_delete(model);
1270  cpl_vector_delete(point);
1271 
1272  cleanup;
1273  return smooth;
1274 
1275 }
1276 
1277 #undef cleanup
1278 #define cleanup
1279 
1295 cpl_image *
1297  int xradius,
1298  int yradius,
1299  bool use_data)
1300 {
1301  const cpl_image *input = NULL;
1302  cpl_image *hmaxima = NULL;
1303  cpl_image *maxima = NULL;
1304  int nx, ny;
1305 
1306  assure( image != NULL, return maxima, NULL );
1307  passure( image->data != NULL, return maxima );
1308  passure( image->variance != NULL, return maxima );
1309 
1310  input = (use_data) ? image->data : image->variance;
1311 
1312  nx = cpl_image_get_size_x(input);
1313  ny = cpl_image_get_size_y(input);
1314 
1315  /*
1316  * Allocate space for horizontal max filter result.
1317  */
1318 
1319  hmaxima = cpl_image_duplicate(input);
1320 
1321  /* For efficiency reasons, assume that the image type is float */
1322  assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return maxima, NULL );
1323 
1324  float *input_data = (float *)cpl_image_get_data_float_const(input);
1325  float *maxima_data = cpl_image_get_data_float(hmaxima);
1326 
1327  int y;
1328  for (y = 0; y < ny; y++) {
1329  const float *irow = input_data + y * nx;
1330  float *orow = maxima_data + y * nx;
1331  max_filter(irow, orow, nx, 2*xradius+1);
1332  }
1333 
1334  cpl_image_turn(hmaxima, 1);
1335 
1336  /*
1337  * Allocate space for vertical max filter result.
1338  */
1339 
1340  maxima = cpl_image_duplicate(hmaxima);
1341  input_data = cpl_image_get_data_float(hmaxima);
1342  maxima_data = cpl_image_get_data_float(maxima);
1343 
1344  /*
1345  * Now nx is the y size of the rotated image...
1346  */
1347 
1348  int x;
1349  for (x = 0; x < nx; x++) {
1350  const float *irow = input_data + x * ny;
1351  float *orow = maxima_data + x * ny;
1352  max_filter(irow, orow, ny, 2*yradius+1);
1353  }
1354 
1355  cpl_image_delete(hmaxima);
1356 
1357  cpl_image_turn(maxima, -1);
1358 
1359  return maxima;
1360 }
1361 
1362 #undef cleanup
1363 #define cleanup
1364 
1370 double
1371 fors_image_get_stdev(const fors_image *image, double *dstdev)
1372 {
1373  assure( image != NULL, return 0, NULL );
1374  assure( dstdev == NULL, return 0, "Unsupported");
1375 
1376  return cpl_image_get_stdev(image->data);
1377 }
1378 #undef cleanup
1379 #define cleanup \
1380 do { \
1381  cpl_mask_delete(rejected); \
1382  cpl_image_delete(im); \
1383 } while (0)
1384 
1393  double cut,
1394  double *dstdev)
1395 {
1396  cpl_mask *rejected = NULL;
1397  cpl_image *im = NULL;
1398 
1399  assure( image != NULL, return 0, NULL );
1400  assure( cut > 0, return 0, "Illegal cut: %f", cut );
1401  assure( dstdev == NULL, return 0, "Unsupported");
1402 
1403  double median = fors_image_get_median(image, NULL);
1404 
1405  im = cpl_image_duplicate(image->data);
1406  cpl_image_subtract_scalar(im, median);
1407  cpl_image_power(im, 2);
1408  /* Now squared residuals wrt median */
1409 
1410  rejected = cpl_mask_threshold_image_create(image->data,
1411  median - cut,
1412  median + cut);
1413  cpl_mask_not(rejected);
1414  cpl_image_reject_from_mask(im, rejected);
1415 
1416  double robust_stdev = sqrt(cpl_image_get_mean(im));
1417 
1418  cleanup;
1419  return robust_stdev;
1420 }
1421 
1422 #undef cleanup
1423 #define cleanup
1424 
1434 double
1435 fors_image_get_error_mean(const fors_image *image, double *dmean)
1436 {
1437  double avg;
1438 
1439  assure( image != NULL, return 0, NULL );
1440  assure( dmean == NULL, return 0, "Unsupported");
1441 
1442  avg = cpl_image_get_mean(image->variance);
1443 
1444  /* This should never happen, but avoid sqrt of negative value in any case */
1445  assure( avg >= 0, return -1, "Average variance is %f", avg);
1446 
1447  return sqrt(avg);
1448 }
1449 
1450 
1451 #undef cleanup
1452 #define cleanup \
1453 do { \
1454  cpl_imagelist_delete(datlist); \
1455  cpl_imagelist_delete(varlist); \
1456 } while (0)
1457 
1466 fors_image *
1467 fors_image_collapse_create(const fors_image_list *images)
1468 {
1469  cpl_imagelist *datlist = NULL;
1470  cpl_imagelist *varlist = NULL;
1471  cpl_image *data = NULL;
1472  cpl_image *variance = NULL;
1473  const fors_image *i;
1474  int N = 0;
1475 
1476  assure( images != NULL, return NULL, NULL );
1477  assure( fors_image_list_size(images) > 0, return NULL,
1478  "Cannot stack zero images");
1479 
1480  i = fors_image_list_first_const(images);
1481 
1482  datlist = cpl_imagelist_new();
1483  varlist = cpl_imagelist_new();
1484 
1485  while(i != NULL) {
1486 
1487  /* Append current image to image lists */
1488  cpl_imagelist_set(datlist,
1489  cpl_image_duplicate(i->data),
1490  cpl_imagelist_get_size(datlist));
1491  cpl_imagelist_set(varlist,
1492  cpl_image_duplicate(i->variance),
1493  cpl_imagelist_get_size(varlist));
1494  i = fors_image_list_next_const(images);
1495  N++;
1496  }
1497 
1498 #ifdef CPL_IS_NOT_CRAP
1499  data = cpl_imagelist_collapse_create(datlist);
1500 
1501  variance = cpl_imagelist_collapse_create(varlist);
1502 #else
1503  data = fors_imagelist_collapse_create(datlist);
1504 
1505  variance = fors_imagelist_collapse_create(varlist);
1506 #endif
1507 
1508  cpl_image_divide_scalar(variance, N);
1509 
1510  cleanup;
1511  return fors_image_new(data, variance);
1512 }
1513 
1514 
1515 #undef cleanup
1516 #define cleanup \
1517 do { \
1518  cpl_imagelist_delete(datlist); \
1519  cpl_imagelist_delete(varlist); \
1520 } while (0)
1521 
1532 fors_image *
1533 fors_image_collapse_minmax_create(const fors_image_list *images,
1534  int low, int high)
1535 {
1536  cpl_imagelist *datlist = NULL;
1537  cpl_imagelist *varlist = NULL;
1538  cpl_image *data = NULL;
1539  cpl_image *variance = NULL;
1540  const fors_image *i;
1541  int N = 0;
1542 
1543  assure( images != NULL, return NULL, NULL );
1544  assure( fors_image_list_size(images) > low + high, return NULL,
1545  "Cannot reject more images than there are");
1546  assure( low*high >= 0 && low+high > 0, return NULL,
1547  "Invalid minmax rejection criteria");
1548 
1549  i = fors_image_list_first_const(images);
1550 
1551  datlist = cpl_imagelist_new();
1552  varlist = cpl_imagelist_new();
1553 
1554  while(i != NULL) {
1555 
1556  /* Append current image to image lists */
1557  cpl_imagelist_set(datlist,
1558  cpl_image_duplicate(i->data),
1559  cpl_imagelist_get_size(datlist));
1560  cpl_imagelist_set(varlist,
1561  cpl_image_duplicate(i->variance),
1562  cpl_imagelist_get_size(varlist));
1563  i = fors_image_list_next_const(images);
1564  N++;
1565  }
1566 
1567  data = cpl_imagelist_collapse_minmax_create(datlist, low, high);
1568  variance = cpl_imagelist_collapse_minmax_create(varlist, low, high);
1569 
1570  cpl_image_divide_scalar(variance, N);
1571 
1572  cleanup;
1573  return fors_image_new(data, variance);
1574 }
1575 
1588 fors_image *
1589 fors_image_collapse_ksigma_create(const fors_image_list *images,
1590  int low, int high, int iter)
1591 {
1592  cpl_imagelist *datlist = NULL;
1593  cpl_imagelist *varlist = NULL;
1594  cpl_image *data = NULL;
1595  cpl_image *variance = NULL;
1596  cpl_image *ngood = NULL;
1597  const fors_image *i;
1598 
1599  assure( images != NULL, return NULL, NULL );
1600 
1601  i = fors_image_list_first_const(images);
1602 
1603  datlist = cpl_imagelist_new();
1604  varlist = cpl_imagelist_new();
1605 
1606  while(i != NULL) {
1607 
1608  /* Append current image to image lists */
1609  cpl_imagelist_set(datlist,
1610  cpl_image_duplicate(i->data),
1611  cpl_imagelist_get_size(datlist));
1612  cpl_imagelist_set(varlist,
1613  cpl_image_duplicate(i->variance),
1614  cpl_imagelist_get_size(varlist));
1615  i = fors_image_list_next_const(images);
1616  }
1617 
1618  data = mos_ksigma_stack(datlist, low, high, iter, &ngood);
1619  variance = cpl_imagelist_collapse_create(varlist);
1620 
1621  cpl_image_divide(variance, ngood);
1622 
1623  cpl_image_delete(ngood);
1624  cleanup;
1625 
1626  return fors_image_new(data, variance);
1627 }
1628 
1640 fors_image *
1641 fors_image_collapse_median_create(const fors_image_list *images)
1642 {
1643  cpl_imagelist *datlist = NULL;
1644  cpl_imagelist *varlist = NULL;
1645  cpl_image *data = NULL;
1646  cpl_image *variance = NULL;
1647  const fors_image *i;
1648  int N = 0;
1649 
1650  assure( images != NULL, return NULL, NULL );
1651  assure( fors_image_list_size(images) > 0, return NULL,
1652  "Cannot stack zero images");
1653 
1654  i = fors_image_list_first_const(images);
1655 
1656  datlist = cpl_imagelist_new();
1657  varlist = cpl_imagelist_new();
1658  while(i != NULL) {
1659  /* Append to image lists */
1660  cpl_imagelist_set(datlist,
1661  cpl_image_duplicate(i->data),
1662  cpl_imagelist_get_size(datlist));
1663  cpl_imagelist_set(varlist,
1664  cpl_image_duplicate(i->variance),
1665  cpl_imagelist_get_size(varlist));
1666 
1667  i = fors_image_list_next_const(images);
1668  N++;
1669  }
1670 
1671 #ifdef CPL_IS_NOT_CRAP
1672  data = cpl_imagelist_collapse_median_create(datlist);
1673 
1674  variance = cpl_imagelist_collapse_create(varlist);
1675 #else
1676  data = fors_imagelist_collapse_median_create(datlist);
1677 
1678  variance = fors_imagelist_collapse_create(varlist);
1679 #endif
1680 
1681  cpl_image_divide_scalar(variance, N);
1682 
1683  cpl_image_multiply_scalar(variance,
1686 
1687  cleanup;
1688  return fors_image_new(data, variance);
1689 }
1690 
1691 #undef cleanup
1692 #define cleanup
1693 
1710 void fors_image_draw(fors_image *image, int type,
1711  double x, double y,
1712  int radius, double color)
1713 {
1714  assure( image != NULL, return, NULL );
1715 
1716  assure( type == 0 || type == 1 || type == 2,
1717  return , "Unsupported type %d", type);
1718 
1719  assure( radius > 0, return, NULL );
1720 
1721  if (type == 2) {
1722  int i;
1723  for (i = 0; i < 360; i++) {
1724  /* Step size of 1 degree is arbitrary */
1725 
1726  int px = x + radius*cos(i/(2*M_PI));
1727  int py = y + radius*sin(i/(2*M_PI));
1728 
1729  if (1 <= px && px <= cpl_image_get_size_x(image->data) &&
1730  1 <= py && py <= cpl_image_get_size_y(image->data)) {
1731  cpl_image_set(image->data, px, py, color);
1732  cpl_image_set(image->variance, px, py, color > 0 ? color : 0);
1733  }
1734  }
1735  }
1736  else {
1737  int i;
1738 
1739  for (i = -radius; i <= radius; i++) {
1740 
1741  int px, py;
1742 
1743  if (type == 0) {
1744  px = x + i;
1745  py = y;
1746  }
1747  else {
1748  px = x;
1749  py = y + i;
1750  }
1751 
1752  if (1 <= px && px <= cpl_image_get_size_x(image->data) &&
1753  1 <= py && py <= cpl_image_get_size_y(image->data)) {
1754  cpl_image_set(image->data , px, py, color);
1755  cpl_image_set(image->variance, px, py, color > 0 ? color : 0);
1756  }
1757  }
1758  }
1759 
1760  return;
1761 }
1762 
1763 hdrl_imagelist * fors_image_list_to_hdrl(const fors_image_list * imalist)
1764 {
1765  int i;
1766  hdrl_imagelist * images_hdrl = hdrl_imagelist_new();
1767  const fors_image * target = fors_image_list_first_const(imalist);
1768  for(i = 0 ; i < fors_image_list_size(imalist); ++i)
1769  {
1770  const cpl_image * ima_data = target->data;
1771  cpl_image * ima_error = cpl_image_power_create(target->variance, 0.5);
1772  cpl_mask * old_bpm = cpl_image_set_bpm(ima_error,
1773  cpl_mask_duplicate(cpl_image_get_bpm_const(ima_data)));
1774  cpl_mask_delete(old_bpm);
1775  hdrl_image * ima_hdrl = hdrl_image_create(ima_data, ima_error);
1776  hdrl_imagelist_set(images_hdrl, ima_hdrl,
1777  hdrl_imagelist_get_size(images_hdrl));
1778  target = fors_image_list_next_const(imalist);
1779  }
1780 
1781  return images_hdrl;
1782 }
1783 
1784 fors_image * fors_image_from_hdrl(const hdrl_image * image)
1785 {
1786  const cpl_image * data = hdrl_image_get_image_const(image);
1787  cpl_image * variance = cpl_image_power_create
1788  (hdrl_image_get_image_const(image), 2);
1789  fors_image * ima = fors_image_new(cpl_image_duplicate(data), variance);
1790  return ima;
1791 }
1792 
1793 
1794 #define LIST_DEFINE
1795 #undef LIST_ELEM
1796 #define LIST_ELEM fors_image
1797 #include <list.h>
1798 
cpl_image * fors_image_filter_median_create(const fors_image *image, int xradius, int yradius, int xstart, int ystart, int xend, int yend, int xstep, int ystep, bool use_data)
Smooth image.
Definition: fors_image.c:1063
void fors_image_multiply_scalar(fors_image *image, double s, double ds)
Multiply by scalar.
Definition: fors_image.c:876
void fors_image_abs(fors_image *image)
Absolute value.
Definition: fors_image.c:545
double fors_image_get_stdev_robust(const fors_image *image, double cut, double *dstdev)
Get robust empirical stdev of data.
Definition: fors_image.c:1392
void fors_image_square(fors_image *image)
Squared.
Definition: fors_image.c:564
const fors_image_list * fors_image_load_list_const(const cpl_frameset *frames)
Load imagelist.
Definition: fors_image.c:273
fors_image * fors_image_new(cpl_image *data, cpl_image *variance)
Create image.
Definition: fors_image.c:102
double fors_image_get_max(const fors_image *image)
Get max data value.
Definition: fors_image.c:948
const float * fors_image_get_data_const(const fors_image *image)
Get pointer to data buffer.
Definition: fors_image.c:524
void fors_image_subtract(fors_image *left, const fors_image *right)
Subtract images.
Definition: fors_image.c:593
void fors_image_save_sex(const fors_image *image, const cpl_propertylist *header, const char *filename_dat, const char *filename_var, int radius)
Save image in format useable by SExtractor.
Definition: fors_image.c:426
fors_image * fors_image_collapse_create(const fors_image_list *images)
Average collapse.
Definition: fors_image.c:1467
void fors_image_divide_noerr(fors_image *left, cpl_image *right)
Divide images.
Definition: fors_image.c:662
void fors_image_crop(fors_image *image, int xlo, int ylo, int xhi, int yhi)
Crop image.
Definition: fors_image.c:1006
double fors_image_get_stdev(const fors_image *image, double *dstdev)
Get empirical stdev of data.
Definition: fors_image.c:1371
void fors_image_multiply_noerr(fors_image *left, const cpl_image *right)
Multiply images.
Definition: fors_image.c:621
void fors_image_delete(fors_image **image)
Deallocate image and set pointer to NULL.
Definition: fors_image.c:164
cpl_size fors_image_get_size_y(const fors_image *image)
Get image height.
Definition: fors_image.c:512
void fors_image_divide_scalar(fors_image *image, double s, double ds)
Divide by scalar.
Definition: fors_image.c:850
fors_image * fors_image_collapse_ksigma_create(const fors_image_list *images, int low, int high, int iter)
Ksigma collapse.
Definition: fors_image.c:1589
#define assure(EXPR)
Definition: list.c:101
cpl_image * fors_imagelist_collapse_create(const cpl_imagelist *ilist)
Workaround for cpl_imagelist_collapse_create.
Definition: fors_utils.c:597
double fors_image_get_min(const fors_image *image)
Get min data value.
Definition: fors_image.c:933
fors_image * fors_image_load(const cpl_frame *frame)
Load image.
Definition: fors_image.c:292
cpl_image * fors_image_filter_max_create(const fors_image *image, int xradius, int yradius, bool use_data)
Max filter image.
Definition: fors_image.c:1296
void fors_image_multiply(fors_image *left, const fors_image *right)
Multiply images.
Definition: fors_image.c:789
double fors_image_get_mean(const fors_image *image, double *dmean)
Get mean data value.
Definition: fors_image.c:964
void fors_image_draw(fors_image *image, int type, double x, double y, int radius, double color)
Draw on image.
Definition: fors_image.c:1710
fors_image * fors_image_collapse_median_create(const fors_image_list *images)
Median collapse.
Definition: fors_image.c:1641
fors_image_list * fors_image_load_list(const cpl_frameset *frames)
Load imagelist.
Definition: fors_image.c:236
double fors_utils_median_corr(int n)
median stacking correction factor
Definition: fors_utils.c:696
cpl_size fors_image_get_size_x(const fors_image *image)
Get image width.
Definition: fors_image.c:499
void fors_image_delete_const(const fors_image **image)
Deallocate image and set pointer to NULL.
Definition: fors_image.c:179
void fors_image_divide(fors_image *left, const fors_image *right)
Divide images.
Definition: fors_image.c:727
cpl_image * mos_ksigma_stack(cpl_imagelist *imlist, double klow, double khigh, int kiter, cpl_image **good)
Stack images using k-sigma clipping.
Definition: moses.c:17980
float fors_tools_get_median_float(float *a, int n)
Unbiased median.
Definition: fors_utils.c:250
void fors_image_save(const fors_image *image, const cpl_propertylist *header, const char *filename)
Save image.
Definition: fors_image.c:377
double fors_image_get_median(const fors_image *image, double *dmedian)
Get median data value.
Definition: fors_image.c:981
void fors_image_exponential(fors_image *image, double b, double db)
Exponential.
Definition: fors_image.c:905
double fors_image_get_error_mean(const fors_image *image, double *dmean)
Get mean of error bars.
Definition: fors_image.c:1435
cpl_image * mos_image_filter_median(cpl_image *image, int nx, int ny)
Convenience function for standard median filtering.
Definition: moses.c:19259
fors_image * fors_image_duplicate(const fors_image *image)
Copy constructor.
Definition: fors_image.c:151
fors_image * fors_image_collapse_minmax_create(const fors_image_list *images, int low, int high)
Minmax collapse.
Definition: fors_image.c:1533
void fors_image_subtract_scalar(fors_image *image, double s, double ds)
Subtract scalar.
Definition: fors_image.c:825
cpl_image * fors_imagelist_collapse_median_create(const cpl_imagelist *ilist)
Workaround for cpl_imagelist_collapse_median_create.
Definition: fors_utils.c:616