FORS Pipeline Reference Manual  4.12.5
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 %f",
131  cpl_image_get_min(variance));
132 
133  image = cpl_malloc(sizeof(*image));
134 
135  image->data = data;
136  image->variance = variance;
137 
138  return image;
139 }
140 
141 #undef cleanup
142 #define cleanup
143 
148 fors_image *
150 {
151  assure( image != NULL, return NULL, NULL );
152 
153  return fors_image_new(cpl_image_duplicate(image->data),
154  cpl_image_duplicate(image->variance));
155 }
156 
161 void
163 {
164  if (image && *image) {
165  cpl_image_delete((*image)->data);
166  cpl_image_delete((*image)->variance);
167  cpl_free(*image); *image = NULL;
168  }
169  return;
170 }
171 
176 void
178 {
179  fors_image_delete((fors_image **)image);
180 
181  return;
182 }
183 
184 /* not used */
185 #if 0
186 
190 static void
191 fors_image_dump(const fors_image *image, FILE *file)
192 {
193  if (image == NULL) {
194  fprintf(file, "Null image\n");
195  }
196  else {
197  cpl_stats *stats;
198 
199  fprintf(file, "Data:\n");
200  stats = cpl_stats_new_from_image(image->data, CPL_STATS_ALL);
201  cpl_stats_dump(stats, CPL_STATS_ALL, file);
202  cpl_stats_delete(stats);
203 
204  fprintf(file, "Variance:\n");
205  stats = cpl_stats_new_from_image(image->variance, CPL_STATS_ALL);
206  cpl_stats_dump(stats, CPL_STATS_ALL, file);
207  cpl_stats_delete(stats);
208  }
209 
210  return;
211 }
212 #endif
213 
214 #undef cleanup
215 #define cleanup \
216 do { \
217  double_list_delete(&sat_percent, double_delete); \
218 } while (0)
219 
233 fors_image_list *
234 fors_image_load_list(const cpl_frameset *frames)
235 {
236  fors_image_list *ilist = fors_image_list_new();
237  double_list *sat_percent = double_list_new();
238 
239  assure( frames != NULL, return ilist, NULL );
240  assure( !cpl_frameset_is_empty(frames), return ilist, "Empty frameset");
241 
242  {
243  const cpl_frame *f;
244 
245  for (int i =0; i< cpl_frameset_get_size(frames); i ++)
246  {
247  f = cpl_frameset_get_position_const(frames, i);
248 
249  fors_image *ima = fors_image_load(f);
250 
251  fors_image_list_insert(ilist, ima);
252  }
253  }
254 
255  cleanup;
256  return ilist;
257 }
258 
270 const fors_image_list *
271 fors_image_load_list_const(const cpl_frameset *frames)
272 {
273  return (const fors_image_list *)
274  fors_image_load_list(frames);
275 }
276 
277 #undef cleanup
278 #define cleanup \
279 do { \
280  cpl_image_delete(temp); \
281 } while (0)
282 
297 fors_image *
298 fors_image_load(const cpl_frame *frame)
299 {
300  fors_image *image = NULL;
301  cpl_image *data = NULL;
302  cpl_image *variance = NULL;
303  cpl_image *temp = NULL;
304  const char *filename;
305  int extension= 0;
306  const int plane = 0;
307 
308  assure( frame != NULL, return image, NULL );
309  /* bias may be NULL */
310  filename = cpl_frame_get_filename(frame);
311  assure( filename != NULL, return image,
312  "NULL filename received");
313 
314  cpl_msg_info(cpl_func, "Loading %s: %s",
315  /* fors_frame_get_group_string(frame), */
316  (cpl_frame_get_tag(frame) != NULL) ?
317  cpl_frame_get_tag(frame) : "NULL",
318  filename);
319 
320  /* Get data */
321  data = cpl_image_load(filename,
322  FORS_IMAGE_TYPE, plane, extension);
323 
324  assure( !cpl_error_get_code(), return image,
325  "Could not load image from %s extension %d",
326  filename, extension);
327 
328 
329  /* Read variance if it exists */
330  if (cpl_frame_get_nextensions(frame) == 0) {
331 
332  /* Create an empty variance */
333  variance = cpl_image_new(
334  cpl_image_get_size_x(data),
335  cpl_image_get_size_y(data),
336  FORS_IMAGE_TYPE);
337 
338  }
339  else {
340 
341  extension = 1;
342 
343  /* Get error bars */
344  variance = cpl_image_load(filename,
345  FORS_IMAGE_TYPE, plane, extension);
346 
347  assure( !cpl_error_get_code(), return image,
348  "Could not load image from %s extension %d",
349  filename, extension);
350 
351  cpl_image_power(variance, 2);
352 
353  assure( cpl_image_get_min(variance) >= 0, return image,
354  "Illegal minimum variance: %g",
355  cpl_image_get_min(variance));
356 
357  cpl_image_delete(temp); temp = NULL;
358  }
359 
360  image = fors_image_new(data, variance);
361 
362  cleanup;
363  return image;
364 }
365 
366 
367 #undef cleanup
368 #define cleanup \
369 do { \
370  cpl_image_delete(sigma); \
371  cpl_propertylist_delete(extension_header); \
372 } while(0)
373 
382 void
383 fors_image_save(const fors_image *image, const cpl_propertylist *header,
384  const char *filename)
385 {
386  cpl_propertylist *extension_header = NULL;
387  cpl_image *sigma = NULL;
388 
389  assure( image != NULL, return, NULL );
390  /* header may be NULL */
391  assure( filename != NULL, return, NULL );
392 
393  cpl_image_save(image->data, filename, CPL_BPP_IEEE_FLOAT, header,
394  CPL_IO_DEFAULT);
395  assure( !cpl_error_get_code(), return,
396  "Cannot save product %s", filename);
397 
398  sigma = cpl_image_power_create(image->variance, 0.5);
399  /* This would probably be faster if sqrt() is used rather than pow */
400  extension_header = cpl_propertylist_new();
401  cpl_propertylist_append_string(extension_header,
402  "EXTNAME", "IMAGE.ERR");
403 
404  cpl_image_save(sigma, filename, CPL_BPP_IEEE_FLOAT, extension_header,
405  CPL_IO_EXTEND);
406  assure( !cpl_error_get_code(), return,
407  "Cannot save product %s", filename);
408 
409  cleanup;
410  return;
411 }
412 
413 
414 #undef cleanup
415 #define cleanup \
416 do { \
417  cpl_image_delete(var_bkg); \
418  cpl_image_delete(sigma_bkg); \
419 } while(0)
420 
431 void
432 fors_image_save_sex(const fors_image *image, const cpl_propertylist *header,
433  const char *filename_dat,
434  const char *filename_var,
435  int radius)
436 {
437  cpl_propertylist *extension_header = NULL;
438  cpl_image *sigma_bkg = NULL;
439  cpl_image *var_bkg = NULL;
440 
441  assure( image != NULL, return, NULL );
442  /* header may be NULL */
443  assure( filename_dat != NULL, return, NULL );
444  assure( filename_var != NULL, return, NULL );
445 
446  cpl_image_save(image->data, filename_dat, CPL_BPP_IEEE_FLOAT, header,
447  CPL_IO_DEFAULT);
448  assure( !cpl_error_get_code(), return,
449  "Cannot save product %s", filename_dat);
450 
451  /* Sextractor wants as input the background error bars,
452  i.e. excluding sources.
453  Therefore filter away sources but keep the sharp edges
454  between the illuminated / non-illuminated areas.
455 
456  I.e. use a median filter, average filter would not work.
457  */
458 
459  cpl_msg_info(cpl_func, "Creating background error map");
460 
461  bool filter_data = false; /* filter the variance image */
462  int xstep = radius/2; /* 25 points sampling grid
463  . . . . .
464  . . . . .
465  . . . . .
466  . . . . .
467  . . . . .
468  */
469  int ystep = radius/2;
470  int xstart = 1;
471  int ystart = 1;
472  int xend = fors_image_get_size_x(image);
473  int yend = fors_image_get_size_y(image);
474 
475 
476  var_bkg = fors_image_filter_median_create(image,
477  radius,
478  radius,
479  xstart, ystart,
480  xend, yend,
481  xstep, ystep,
482  filter_data);
483  assure( !cpl_error_get_code(), return,
484  "Median filtering failed");
485 
486  sigma_bkg = cpl_image_power_create(var_bkg, 0.5);
487 
488  cpl_image_save(sigma_bkg, filename_var,
489  CPL_BPP_IEEE_FLOAT, extension_header,
490  CPL_IO_DEFAULT);
491  assure( !cpl_error_get_code(), return,
492  "Cannot save product %s", filename_var);
493 
494  cleanup;
495  return;
496 }
497 
498 #undef cleanup
499 #define cleanup
500 
505 cpl_size fors_image_get_size_x(const fors_image *image)
506 {
507  assure( image != NULL, return -1, NULL );
508  return cpl_image_get_size_x(image->data);
509 }
510 
511 #undef cleanup
512 #define cleanup
513 
518 cpl_size fors_image_get_size_y(const fors_image *image)
519 {
520  assure( image != NULL, return -1, NULL );
521  return cpl_image_get_size_y(image->data);
522 }
523 
524 #undef cleanup
525 #define cleanup
526 
530 const float *fors_image_get_data_const(const fors_image *image)
531 {
532  assure( image != NULL, return NULL, NULL );
533 
534  assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return NULL, NULL );
535  /* This function (including API) would need to change
536  if the pixel type changes */
537 
538  return cpl_image_get_data_float(image->data);
539 }
540 
541 #undef cleanup
542 #define cleanup
543 
550 void
552 {
553  assure( image != NULL, return, NULL );
554 
555  cpl_image_abs(image->data);
556 
557  return;
558 }
559 
560 #undef cleanup
561 #define cleanup
562 
569 void
571 {
572  assure( image != NULL, return, NULL );
573 
574  cpl_image_multiply(image->data, image->data);
575  /* It is an undocumented feature of CPL that you
576  can pass the same image to cpl_image_multiply and get
577  the right answer. Let us hope it does not change...
578  */
579  cpl_image_multiply_scalar(image->variance, 2);
580 
581  return;
582 }
583 
584 
585 #undef cleanup
586 #define cleanup \
587 do { \
588  cpl_image_delete(temp); \
589 } while(0)
590 
598 void
600 {
601  cpl_image *temp = NULL;
602  assure( left != NULL, return, NULL );
603  assure( right != NULL, return, NULL );
604 
605  cpl_image_subtract(left->data, right->data);
606 
607  /* variance_left := variance_left + variance_right */
608  cpl_image_add(left->variance, right->variance);
609 
610  cleanup;
611  return;
612 }
613 
614 #undef cleanup
615 #define cleanup
616 
626 void
627 fors_image_multiply_noerr(fors_image *left, const cpl_image *right)
628 {
629  assure( left != NULL, return, NULL );
630  assure( right != NULL, return, NULL );
631  assure( cpl_image_get_size_x(left->data) == cpl_image_get_size_x(right) &&
632  cpl_image_get_size_y(left->data) == cpl_image_get_size_y(right),
633  return,
634  "Incompatible data and weight image sizes: "
635  "%"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT
636  " and %"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT,
637  cpl_image_get_size_x(left->data),
638  cpl_image_get_size_y(left->data),
639  cpl_image_get_size_x(right),
640  cpl_image_get_size_y(right));
641 
642  cpl_image_multiply(left->data, right);
643  cpl_image_multiply(left->variance, right);
644  cpl_image_multiply(left->variance, right);
645 
646  return;
647 }
648 
649 #undef cleanup
650 #define cleanup
651 
667 void
668 fors_image_divide_noerr(fors_image *left, cpl_image *right)
669 {
670  assure( left != NULL, return, NULL );
671  assure( right != NULL, return, NULL );
672  assure( cpl_image_get_size_x(left->data) == cpl_image_get_size_x(right) &&
673  cpl_image_get_size_y(left->data) == cpl_image_get_size_y(right),
674  return,
675  "Incompatible data and weight image sizes: "
676  "%"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT
677  " and %"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT,
678  cpl_image_get_size_x(left->data),
679  cpl_image_get_size_y(left->data),
680  cpl_image_get_size_x(right),
681  cpl_image_get_size_y(right));
682 
683  int x, y;
684  int nx = cpl_image_get_size_x(right);
685  int ny = cpl_image_get_size_y(right);
686  float *datal = cpl_image_get_data_float(left->data);
687  float *datav = cpl_image_get_data_float(left->variance);
688  float *datar = cpl_image_get_data_float(right);
689  for (y = 0; y < ny; y++) {
690  for (x = 0; x < nx; x++) {
691  if (datar[x + nx*y] == 0) {
692  datar[x + nx*y] = 1;
693  datal[x + nx*y] = 1;
694 
695  datav[x + nx*y] = FORS_IMAGE_TYPE_MAX;
696  }
697  }
698  }
699 
700  cpl_image_divide(left->data, right);
701  cpl_image_divide(left->variance, right);
702  cpl_image_divide(left->variance, right);
703 
704  return;
705 }
706 
707 #undef cleanup
708 #define cleanup \
709 do { \
710  fors_image_delete(&dupl); \
711 } while(0)
712 
732 void
734 {
735  fors_image *dupl = NULL;
736 
737  assure( left != NULL, return, NULL );
738  assure( right != NULL, return, NULL );
739 
740  dupl = fors_image_duplicate(right);
741 
742  cpl_image_divide(left->data, dupl->data);
743  /* This CPL function divides by zero by setting x/0 = 1 for all x */
744 
745  cpl_image_multiply(dupl->variance, left->data);
746  cpl_image_multiply(dupl->variance, left->data);
747 
748  /* Now dupl->variance = sigma2^2 * data1^2 / data2^2 */
749 
750  cpl_image_add(left->variance, dupl->variance);
751 
752  /* Now left->variance = sigma1^2 + sigma2^2 * data1^2 / data2^2 */
753 
754  cpl_image_divide(left->variance, dupl->data);
755  cpl_image_divide(left->variance, dupl->data);
756  /* QED */
757 
758  /* Handle division by zero */
759  int x, y;
760  int nx = cpl_image_get_size_x(left->data);
761  int ny = cpl_image_get_size_y(left->data);
762  float *datal = cpl_image_get_data_float(left->data);
763  float *datav = cpl_image_get_data_float(left->variance);
764  float *datar = cpl_image_get_data_float(right->data);
765  for (y = 0; y < ny; y++) {
766  for (x = 0; x < nx; x++) {
767  if (datar[x + nx*y] == 0) {
768  datal[x + nx*y] = 1;
769  datav[x + nx*y] = FORS_IMAGE_TYPE_MAX;
770  }
771  }
772  }
773 
774  cleanup;
775  return;
776 }
777 
778 #undef cleanup
779 #define cleanup \
780 do { \
781  cpl_image_delete(s22d12); \
782 } while(0)
783 
794 void
796 {
797  cpl_image *s22d12 = NULL;
798 
799  assure( left != NULL, return, NULL );
800  assure( right != NULL, return, NULL );
801 
802  s22d12 = cpl_image_duplicate(right->variance);
803  cpl_image_multiply(s22d12, left->data);
804  cpl_image_multiply(s22d12, left->data);
805 
806  cpl_image_multiply(left->variance, right->data);
807  cpl_image_multiply(left->variance, right->data);
808  cpl_image_add(left->variance, s22d12);
809 
810  cpl_image_multiply(left->data, right->data);
811 
812  cleanup;
813  return;
814 }
815 
816 
817 #undef cleanup
818 #define cleanup
819 
831 void fors_image_subtract_scalar(fors_image *image, double s, double ds)
832 {
833  assure( image != NULL, return, NULL );
834  assure( ds <= 0, return, "Unsupported");
835 
836  cpl_image_subtract_scalar(image->data, s);
837 
838  return;
839 }
840 
841 
842 #undef cleanup
843 #define cleanup
844 
856 void fors_image_divide_scalar(fors_image *image, double s, double ds)
857 {
858  assure( image != NULL, return, NULL );
859  assure( s != 0, return, "Division by zero");
860  assure( ds <= 0, return, "Unsupported");
861 
862  cpl_image_divide_scalar(image->data, s);
863  cpl_image_divide_scalar(image->variance, s*s);
864 
865  return;
866 }
867 
868 #undef cleanup
869 #define cleanup
870 
882 void fors_image_multiply_scalar(fors_image *image, double s, double ds)
883 {
884  assure( image != NULL, return, NULL );
885  assure( ds <= 0, return, "Unsupported");
886 
887  cpl_image_multiply_scalar(image->data, s);
888  cpl_image_multiply_scalar(image->variance, s*s);
889 
890  return;
891 }
892 
893 #undef cleanup
894 #define cleanup \
895 do { \
896  cpl_image_delete(temp); \
897 } while(0)
898 
911 void fors_image_exponential(fors_image *image, double b, double db)
912 {
913  cpl_image *temp = NULL;
914 
915  assure( image != NULL, return, NULL );
916  assure( b >= 0, return, "Negative base: %f", b);
917  assure( db <= 0, return, "Unsupported");
918 
919  cpl_image_exponential(image->data, b);
920 
921  double lnb = log(b);
922 
923  cpl_image_multiply_scalar(image->variance, lnb*lnb);
924  cpl_image_multiply(image->variance, image->data);
925  cpl_image_multiply(image->variance, image->data);
926 
927  return;
928 }
929 
930 
931 #undef cleanup
932 #define cleanup
933 
938 double
940 {
941  assure( image != NULL, return 0, NULL );
942 
943  return cpl_image_get_min(image->data);
944 }
945 
946 #undef cleanup
947 #define cleanup
948 
953 double
955 {
956  assure( image != NULL, return 0, NULL );
957 
958  return cpl_image_get_max(image->data);
959 }
960 
961 #undef cleanup
962 #define cleanup
963 
969 double
970 fors_image_get_mean(const fors_image *image, double *dmean)
971 {
972  assure( image != NULL, return 0, NULL );
973  assure( dmean == NULL, return 0, "Unsupported");
974 
975  return cpl_image_get_mean(image->data);
976 }
977 
978 #undef cleanup
979 #define cleanup
980 
986 double
987 fors_image_get_median(const fors_image *image, double *dmedian)
988 {
989  assure( image != NULL, return 0, NULL );
990  assure( dmedian == NULL, return 0, "Unsupported");
991 
992  return cpl_image_get_median(image->data);
993 }
994 
995 
996 #undef cleanup
997 #define cleanup
998 
1013  int xlo, int ylo,
1014  int xhi, int yhi)
1015 {
1016  /* CPL is missing the function to locally extract an image,
1017  so this this inefficient CPL function */
1018  assure( image != NULL, return, NULL );
1019  assure( 1 <= xlo && xlo <= xhi && xhi <= fors_image_get_size_x(image) &&
1020  1 <= ylo && ylo <= yhi && yhi <= fors_image_get_size_y(image),
1021  return, "Cannot extraction region (%d, %d) - (%d, %d) of "
1022  "%"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT" image",
1023  xlo, ylo, xhi, yhi,
1024  fors_image_get_size_x(image),
1025  fors_image_get_size_y(image));
1026 
1027  cpl_image *new_data = cpl_image_extract(image->data,
1028  xlo, ylo,
1029  xhi, yhi);
1030  cpl_image_delete(image->data);
1031 
1032  cpl_image* new_variance = cpl_image_extract(image->variance,
1033  xlo, ylo,
1034  xhi, yhi);
1035  cpl_image_delete(image->variance);
1036 
1037  image->data = new_data;
1038  image->variance = new_variance;
1039 
1040  return;
1041 }
1042 
1068 cpl_image *
1070  int xradius,
1071  int yradius,
1072  int xstart,
1073  int ystart,
1074  int xend,
1075  int yend,
1076  int xstep,
1077  int ystep,
1078  bool use_data)
1079 {
1080  const cpl_image *input = NULL;
1081  cpl_image *smooth = NULL;
1082  int nx, ny;
1083 
1084  assure( image != NULL, return smooth, NULL );
1085  passure( image->data != NULL, return smooth );
1086  passure( image->variance != NULL, return smooth );
1087 
1088  input = (use_data) ? image->data : image->variance;
1089 
1090  nx = cpl_image_get_size_x(input);
1091  ny = cpl_image_get_size_y(input);
1092 
1093  if (xstep < 1) xstep = 1;
1094  if (ystep < 1) ystep = 1;
1095 
1096  assure( 1 <= xstart && xstart <= xend && xend <= nx &&
1097  1 <= ystart && ystart <= yend && yend <= ny, return smooth,
1098  "Illegal region (%d, %d) - (%d, %d) of %dx%d image",
1099  xstart, ystart,
1100  xend, yend,
1101  nx, ny);
1102 
1103  smooth = cpl_image_duplicate(input);
1104 
1105  /* For efficiency reasons, assume that the image type is float */
1106  assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return smooth, NULL );
1107 
1108  const float *input_data = cpl_image_get_data_float_const(input);
1109  float *smooth_data = cpl_image_get_data_float(smooth);
1110  float *data = cpl_malloc((2*yradius + 1)*(2*xradius + 1)*sizeof(*data));
1111 
1112  int y;
1113  for (y = ystart; y < yend; y++) {
1114  /*
1115  Sample kernel on grid which always contains the central pixel
1116 
1117  Trim window (note: this will cause fewer values to
1118  be used for the median near the region borders
1119  */
1120  int ylo = y - (yradius/ystep) * ystep;
1121  int yhi = y + (yradius/ystep) * ystep;
1122 
1123  while (ylo < ystart) ylo += ystep;
1124  while (yhi > yend ) yhi -= ystep;
1125 
1126  int x;
1127  for (x = xstart; x < xend; x++) {
1128  int xlo = x - (xradius/xstep) * xstep;
1129  int xhi = x + (xradius/xstep) * xstep;
1130 
1131  while (xlo < xstart) xlo += xstep;
1132  while (xhi > xend ) xhi -= xstep;
1133 
1134  /* Collect data */
1135  int k = 0;
1136  int j, i;
1137  for (j = ylo; j <= yhi; j += ystep) {
1138  for (i = xlo; i <= xhi; i += xstep) {
1139  data[k++] = input_data[ (i-1) + (j-1)*nx ];
1140  }
1141  }
1142 
1143  /* Get median */
1144  smooth_data[ (x-1) + (y-1)*nx ] =
1145  fors_tools_get_median_float(data, k);
1146  }
1147  }
1148 
1149  cpl_free(data);
1150  return smooth;
1151 }
1152 
1153 #undef cleanup
1154 #define cleanup \
1155 do { \
1156  cpl_image_delete(input); \
1157 } while(0)
1158 cpl_image *
1159 fors_image_flat_fit_create(fors_image *image,
1160  int step,
1161  int degree,
1162  float level)
1163 {
1164  cpl_image *temp = NULL;
1165  cpl_image *input = NULL;
1166  cpl_image *smooth = NULL;
1167  int nx, ny;
1168 
1169  assure( image != NULL, return smooth, NULL );
1170  passure( image->data != NULL, return smooth );
1171  assure( step > 0, return smooth, NULL );
1172  assure( degree >= 0, return smooth, NULL );
1173 
1174 
1175  temp = image->data;
1176 
1177  nx = cpl_image_get_size_x(temp);
1178  ny = cpl_image_get_size_y(temp);
1179 
1180  /*
1181  * For efficiency reasons, assume that the image type is float
1182  */
1183 
1184  assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return smooth, NULL );
1185 
1186  /*
1187  * Apply light median filter, to eliminate big outliers from fit
1188  */
1189 
1190  input = mos_image_filter_median(image->data, 3, 3);
1191 
1192  const float *input_data = cpl_image_get_data_float_const(input);
1193 
1194  /*
1195  * First of all, count how many points will have to be fitted
1196  */
1197 
1198  int x, y, pos;
1199  int count = 0;
1200  for (y = 0; y < ny; y += step) {
1201  pos = y*nx;
1202  for (x = 0; x < nx; x += step, pos += step) {
1203  if (input_data[pos] > level) {
1204  count++;
1205  }
1206  }
1207  }
1208 
1209  if (count < (degree+1)*(degree+2)) {
1210  step = sqrt((nx*nx)/((degree+1)*(degree+2))) / 2;
1211  if (step == 0)
1212  step = 1;
1213  cpl_msg_error(cpl_func, "Flat field image too small (%dx%d). "
1214  "Please provide a smaller resampling step (a good "
1215  "value would be %d)", nx, ny, step);
1216  cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
1217  cleanup;
1218  return NULL;
1219  }
1220 
1221 
1222  /*
1223  * Fill position and flux vectors with appropriate values
1224  */
1225 
1226  cpl_bivector *positions = cpl_bivector_new(count);
1227  double *xpos = cpl_bivector_get_x_data(positions);
1228  double *ypos = cpl_bivector_get_y_data(positions);
1229  cpl_vector *fluxes = cpl_vector_new(count);
1230  double *flux = cpl_vector_get_data(fluxes);
1231 
1232  count = 0;
1233  for (y = 0; y < ny; y += step) {
1234  pos = y*nx;
1235  for (x = 0; x < nx; x += step, pos += step) {
1236  if (input_data[pos] > level) {
1237  xpos[count] = x;
1238  ypos[count] = y;
1239  flux[count] = input_data[pos];
1240  count++;
1241  }
1242  }
1243  }
1244 
1245  cpl_image_delete(input); input = NULL;
1246 
1247  /*
1248  * Do the fit, and fill the output image with the model
1249  * values in all pixels.
1250  */
1251 
1252  cpl_polynomial *model = cpl_polynomial_fit_2d_create(positions,
1253  fluxes,
1254  degree,
1255  NULL);
1256 
1257  cpl_bivector_delete(positions);
1258  cpl_vector_delete(fluxes);
1259 
1260  smooth = cpl_image_new(nx, ny, FORS_IMAGE_TYPE);
1261  float *smooth_data = cpl_image_get_data_float(smooth);
1262 
1263  cpl_vector *point = cpl_vector_new(2);
1264  double *dpoint = cpl_vector_get_data(point);
1265 
1266  for (y = 0; y < ny; y++) {
1267  pos = y*nx;
1268  dpoint[1] = y;
1269  for (x = 0; x < nx; x++, pos++) {
1270  dpoint[0] = x;
1271  smooth_data[pos] = cpl_polynomial_eval(model, point);
1272  }
1273  }
1274 
1275  cpl_polynomial_delete(model);
1276  cpl_vector_delete(point);
1277 
1278  cleanup;
1279  return smooth;
1280 
1281 }
1282 
1283 #undef cleanup
1284 #define cleanup
1285 
1301 cpl_image *
1303  int xradius,
1304  int yradius,
1305  bool use_data)
1306 {
1307  const cpl_image *input = NULL;
1308  cpl_image *hmaxima = NULL;
1309  cpl_image *maxima = NULL;
1310  int nx, ny;
1311 
1312  assure( image != NULL, return maxima, NULL );
1313  passure( image->data != NULL, return maxima );
1314  passure( image->variance != NULL, return maxima );
1315 
1316  input = (use_data) ? image->data : image->variance;
1317 
1318  nx = cpl_image_get_size_x(input);
1319  ny = cpl_image_get_size_y(input);
1320 
1321  /*
1322  * Allocate space for horizontal max filter result.
1323  */
1324 
1325  hmaxima = cpl_image_duplicate(input);
1326 
1327  /* For efficiency reasons, assume that the image type is float */
1328  assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return maxima, NULL );
1329 
1330  float *input_data = (float *)cpl_image_get_data_float_const(input);
1331  float *maxima_data = cpl_image_get_data_float(hmaxima);
1332 
1333  int y;
1334  for (y = 0; y < ny; y++) {
1335  const float *irow = input_data + y * nx;
1336  float *orow = maxima_data + y * nx;
1337  max_filter(irow, orow, nx, 2*xradius+1);
1338  }
1339 
1340  cpl_image_turn(hmaxima, 1);
1341 
1342  /*
1343  * Allocate space for vertical max filter result.
1344  */
1345 
1346  maxima = cpl_image_duplicate(hmaxima);
1347  input_data = cpl_image_get_data_float(hmaxima);
1348  maxima_data = cpl_image_get_data_float(maxima);
1349 
1350  /*
1351  * Now nx is the y size of the rotated image...
1352  */
1353 
1354  int x;
1355  for (x = 0; x < nx; x++) {
1356  const float *irow = input_data + x * ny;
1357  float *orow = maxima_data + x * ny;
1358  max_filter(irow, orow, ny, 2*yradius+1);
1359  }
1360 
1361  cpl_image_delete(hmaxima);
1362 
1363  cpl_image_turn(maxima, -1);
1364 
1365  return maxima;
1366 }
1367 
1368 #undef cleanup
1369 #define cleanup
1370 
1376 double
1377 fors_image_get_stdev(const fors_image *image, double *dstdev)
1378 {
1379  assure( image != NULL, return 0, NULL );
1380  assure( dstdev == NULL, return 0, "Unsupported");
1381 
1382  return cpl_image_get_stdev(image->data);
1383 }
1384 #undef cleanup
1385 #define cleanup \
1386 do { \
1387  cpl_mask_delete(rejected); \
1388  cpl_image_delete(im); \
1389 } while (0)
1390 
1399  double cut,
1400  double *dstdev)
1401 {
1402  cpl_mask *rejected = NULL;
1403  cpl_image *im = NULL;
1404 
1405  assure( image != NULL, return 0, NULL );
1406  assure( cut > 0, return 0, "Illegal cut: %f", cut );
1407  assure( dstdev == NULL, return 0, "Unsupported");
1408 
1409  double median = fors_image_get_median(image, NULL);
1410 
1411  im = cpl_image_duplicate(image->data);
1412  cpl_image_subtract_scalar(im, median);
1413  cpl_image_power(im, 2);
1414  /* Now squared residuals wrt median */
1415 
1416  rejected = cpl_mask_threshold_image_create(image->data,
1417  median - cut,
1418  median + cut);
1419  cpl_mask_not(rejected);
1420  cpl_image_reject_from_mask(im, rejected);
1421 
1422  double robust_stdev = sqrt(cpl_image_get_mean(im));
1423 
1424  cleanup;
1425  return robust_stdev;
1426 }
1427 
1428 #undef cleanup
1429 #define cleanup
1430 
1440 double
1441 fors_image_get_error_mean(const fors_image *image, double *dmean)
1442 {
1443  double avg;
1444 
1445  assure( image != NULL, return 0, NULL );
1446  assure( dmean == NULL, return 0, "Unsupported");
1447 
1448  avg = cpl_image_get_mean(image->variance);
1449 
1450  /* This should never happen, but avoid sqrt of negative value in any case */
1451  assure( avg >= 0, return -1, "Average variance is %f", avg);
1452 
1453  return sqrt(avg);
1454 }
1455 
1456 
1457 #undef cleanup
1458 #define cleanup \
1459 do { \
1460  cpl_imagelist_delete(datlist); \
1461  cpl_imagelist_delete(varlist); \
1462 } while (0)
1463 
1472 fors_image *
1473 fors_image_collapse_create(const fors_image_list *images)
1474 {
1475  cpl_imagelist *datlist = NULL;
1476  cpl_imagelist *varlist = NULL;
1477  cpl_image *data = NULL;
1478  cpl_image *variance = NULL;
1479  const fors_image *i;
1480  int N = 0;
1481 
1482  assure( images != NULL, return NULL, NULL );
1483  assure( fors_image_list_size(images) > 0, return NULL,
1484  "Cannot stack zero images");
1485 
1486  i = fors_image_list_first_const(images);
1487 
1488  datlist = cpl_imagelist_new();
1489  varlist = cpl_imagelist_new();
1490 
1491  while(i != NULL) {
1492 
1493  /* Append current image to image lists */
1494  cpl_imagelist_set(datlist,
1495  cpl_image_duplicate(i->data),
1496  cpl_imagelist_get_size(datlist));
1497  cpl_imagelist_set(varlist,
1498  cpl_image_duplicate(i->variance),
1499  cpl_imagelist_get_size(varlist));
1500  i = fors_image_list_next_const(images);
1501  N++;
1502  }
1503 
1504 #ifdef CPL_IS_NOT_CRAP
1505  data = cpl_imagelist_collapse_create(datlist);
1506 
1507  variance = cpl_imagelist_collapse_create(varlist);
1508 #else
1509  data = fors_imagelist_collapse_create(datlist);
1510 
1511  variance = fors_imagelist_collapse_create(varlist);
1512 #endif
1513 
1514  cpl_image_divide_scalar(variance, N);
1515 
1516  cleanup;
1517  return fors_image_new(data, variance);
1518 }
1519 
1520 
1521 #undef cleanup
1522 #define cleanup \
1523 do { \
1524  cpl_imagelist_delete(datlist); \
1525  cpl_imagelist_delete(varlist); \
1526 } while (0)
1527 
1538 fors_image *
1539 fors_image_collapse_minmax_create(const fors_image_list *images,
1540  int low, int high)
1541 {
1542  cpl_imagelist *datlist = NULL;
1543  cpl_imagelist *varlist = NULL;
1544  cpl_image *data = NULL;
1545  cpl_image *variance = NULL;
1546  const fors_image *i;
1547  int N = 0;
1548 
1549  assure( images != NULL, return NULL, NULL );
1550  assure( fors_image_list_size(images) > low + high, return NULL,
1551  "Cannot reject more images than there are");
1552  assure( low*high >= 0 && low+high > 0, return NULL,
1553  "Invalid minmax rejection criteria");
1554 
1555  i = fors_image_list_first_const(images);
1556 
1557  datlist = cpl_imagelist_new();
1558  varlist = cpl_imagelist_new();
1559 
1560  while(i != NULL) {
1561 
1562  /* Append current image to image lists */
1563  cpl_imagelist_set(datlist,
1564  cpl_image_duplicate(i->data),
1565  cpl_imagelist_get_size(datlist));
1566  cpl_imagelist_set(varlist,
1567  cpl_image_duplicate(i->variance),
1568  cpl_imagelist_get_size(varlist));
1569  i = fors_image_list_next_const(images);
1570  N++;
1571  }
1572 
1573  data = cpl_imagelist_collapse_minmax_create(datlist, low, high);
1574  variance = cpl_imagelist_collapse_minmax_create(varlist, low, high);
1575 
1576  cpl_image_divide_scalar(variance, N);
1577 
1578  cleanup;
1579  return fors_image_new(data, variance);
1580 }
1581 
1594 fors_image *
1595 fors_image_collapse_ksigma_create(const fors_image_list *images,
1596  int low, int high, int iter)
1597 {
1598  cpl_imagelist *datlist = NULL;
1599  cpl_imagelist *varlist = NULL;
1600  cpl_image *data = NULL;
1601  cpl_image *variance = NULL;
1602  cpl_image *ngood = NULL;
1603  const fors_image *i;
1604 
1605  assure( images != NULL, return NULL, NULL );
1606 
1607  i = fors_image_list_first_const(images);
1608 
1609  datlist = cpl_imagelist_new();
1610  varlist = cpl_imagelist_new();
1611 
1612  while(i != NULL) {
1613 
1614  /* Append current image to image lists */
1615  cpl_imagelist_set(datlist,
1616  cpl_image_duplicate(i->data),
1617  cpl_imagelist_get_size(datlist));
1618  cpl_imagelist_set(varlist,
1619  cpl_image_duplicate(i->variance),
1620  cpl_imagelist_get_size(varlist));
1621  i = fors_image_list_next_const(images);
1622  }
1623 
1624  data = mos_ksigma_stack(datlist, low, high, iter, &ngood);
1625  variance = cpl_imagelist_collapse_create(varlist);
1626 
1627  cpl_image_divide(variance, ngood);
1628 
1629  cpl_image_delete(ngood);
1630  cleanup;
1631 
1632  return fors_image_new(data, variance);
1633 }
1634 
1646 fors_image *
1647 fors_image_collapse_median_create(const fors_image_list *images)
1648 {
1649  cpl_imagelist *datlist = NULL;
1650  cpl_imagelist *varlist = NULL;
1651  cpl_image *data = NULL;
1652  cpl_image *variance = NULL;
1653  const fors_image *i;
1654  int N = 0;
1655 
1656  assure( images != NULL, return NULL, NULL );
1657  assure( fors_image_list_size(images) > 0, return NULL,
1658  "Cannot stack zero images");
1659 
1660  i = fors_image_list_first_const(images);
1661 
1662  datlist = cpl_imagelist_new();
1663  varlist = cpl_imagelist_new();
1664  while(i != NULL) {
1665  /* Append to image lists */
1666  cpl_imagelist_set(datlist,
1667  cpl_image_duplicate(i->data),
1668  cpl_imagelist_get_size(datlist));
1669  cpl_imagelist_set(varlist,
1670  cpl_image_duplicate(i->variance),
1671  cpl_imagelist_get_size(varlist));
1672 
1673  i = fors_image_list_next_const(images);
1674  N++;
1675  }
1676 
1677 #ifdef CPL_IS_NOT_CRAP
1678  data = cpl_imagelist_collapse_median_create(datlist);
1679 
1680  variance = cpl_imagelist_collapse_create(varlist);
1681 #else
1682  data = fors_imagelist_collapse_median_create(datlist);
1683 
1684  variance = fors_imagelist_collapse_create(varlist);
1685 #endif
1686 
1687  cpl_image_divide_scalar(variance, N);
1688 
1689  cpl_image_multiply_scalar(variance,
1692 
1693  cleanup;
1694  return fors_image_new(data, variance);
1695 }
1696 
1697 #undef cleanup
1698 #define cleanup
1699 
1716 void fors_image_draw(fors_image *image, int type,
1717  double x, double y,
1718  int radius, double color)
1719 {
1720  assure( image != NULL, return, NULL );
1721 
1722  assure( type == 0 || type == 1 || type == 2,
1723  return , "Unsupported type %d", type);
1724 
1725  assure( radius > 0, return, NULL );
1726 
1727  if (type == 2) {
1728  int i;
1729  for (i = 0; i < 360; i++) {
1730  /* Step size of 1 degree is arbitrary */
1731 
1732  int px = x + radius*cos(i/(2*M_PI));
1733  int py = y + radius*sin(i/(2*M_PI));
1734 
1735  if (1 <= px && px <= cpl_image_get_size_x(image->data) &&
1736  1 <= py && py <= cpl_image_get_size_y(image->data)) {
1737  cpl_image_set(image->data, px, py, color);
1738  cpl_image_set(image->variance, px, py, color > 0 ? color : 0);
1739  }
1740  }
1741  }
1742  else {
1743  int i;
1744 
1745  for (i = -radius; i <= radius; i++) {
1746 
1747  int px, py;
1748 
1749  if (type == 0) {
1750  px = x + i;
1751  py = y;
1752  }
1753  else {
1754  px = x;
1755  py = y + i;
1756  }
1757 
1758  if (1 <= px && px <= cpl_image_get_size_x(image->data) &&
1759  1 <= py && py <= cpl_image_get_size_y(image->data)) {
1760  cpl_image_set(image->data , px, py, color);
1761  cpl_image_set(image->variance, px, py, color > 0 ? color : 0);
1762  }
1763  }
1764  }
1765 
1766  return;
1767 }
1768 
1769 hdrl_imagelist * fors_image_list_to_hdrl(const fors_image_list * imalist)
1770 {
1771  int i;
1772  hdrl_imagelist * images_hdrl = hdrl_imagelist_new();
1773  const fors_image * target = fors_image_list_first_const(imalist);
1774  for(i = 0 ; i < fors_image_list_size(imalist); ++i)
1775  {
1776  const cpl_image * ima_data = target->data;
1777  cpl_image * ima_error = cpl_image_power_create(target->variance, 0.5);
1778  hdrl_image * ima_hdrl = hdrl_image_create(ima_data, ima_error);
1779  hdrl_imagelist_set(images_hdrl, ima_hdrl,
1780  hdrl_imagelist_get_size(images_hdrl));
1781  target = fors_image_list_next_const(imalist);
1782  }
1783 
1784  return images_hdrl;
1785 }
1786 
1787 fors_image * fors_image_from_hdrl(const hdrl_image * image)
1788 {
1789  const cpl_image * data = hdrl_image_get_image_const(image);
1790  cpl_image * variance = cpl_image_power_create
1791  (hdrl_image_get_image_const(image), 2);
1792  fors_image * ima = fors_image_new(cpl_image_duplicate(data), variance);
1793  return ima;
1794 }
1795 
1796 
1797 #define LIST_DEFINE
1798 #undef LIST_ELEM
1799 #define LIST_ELEM fors_image
1800 #include <list.h>
1801 
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:1069
void fors_image_multiply_scalar(fors_image *image, double s, double ds)
Multiply by scalar.
Definition: fors_image.c:882
void fors_image_abs(fors_image *image)
Absolute value.
Definition: fors_image.c:551
double fors_image_get_stdev_robust(const fors_image *image, double cut, double *dstdev)
Get robust empirical stdev of data.
Definition: fors_image.c:1398
void fors_image_square(fors_image *image)
Squared.
Definition: fors_image.c:570
const fors_image_list * fors_image_load_list_const(const cpl_frameset *frames)
Load imagelist.
Definition: fors_image.c:271
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:954
const float * fors_image_get_data_const(const fors_image *image)
Get pointer to data buffer.
Definition: fors_image.c:530
void fors_image_subtract(fors_image *left, const fors_image *right)
Subtract images.
Definition: fors_image.c:599
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:432
fors_image * fors_image_collapse_create(const fors_image_list *images)
Average collapse.
Definition: fors_image.c:1473
void fors_image_divide_noerr(fors_image *left, cpl_image *right)
Divide images.
Definition: fors_image.c:668
void fors_image_crop(fors_image *image, int xlo, int ylo, int xhi, int yhi)
Crop image.
Definition: fors_image.c:1012
double fors_image_get_stdev(const fors_image *image, double *dstdev)
Get empirical stdev of data.
Definition: fors_image.c:1377
void fors_image_multiply_noerr(fors_image *left, const cpl_image *right)
Multiply images.
Definition: fors_image.c:627
void fors_image_delete(fors_image **image)
Deallocate image and set pointer to NULL.
Definition: fors_image.c:162
cpl_size fors_image_get_size_y(const fors_image *image)
Get image height.
Definition: fors_image.c:518
void fors_image_divide_scalar(fors_image *image, double s, double ds)
Divide by scalar.
Definition: fors_image.c:856
fors_image * fors_image_collapse_ksigma_create(const fors_image_list *images, int low, int high, int iter)
Ksigma collapse.
Definition: fors_image.c:1595
#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:939
fors_image * fors_image_load(const cpl_frame *frame)
Load image.
Definition: fors_image.c:298
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:1302
void fors_image_multiply(fors_image *left, const fors_image *right)
Multiply images.
Definition: fors_image.c:795
double fors_image_get_mean(const fors_image *image, double *dmean)
Get mean data value.
Definition: fors_image.c:970
void fors_image_draw(fors_image *image, int type, double x, double y, int radius, double color)
Draw on image.
Definition: fors_image.c:1716
fors_image * fors_image_collapse_median_create(const fors_image_list *images)
Median collapse.
Definition: fors_image.c:1647
fors_image_list * fors_image_load_list(const cpl_frameset *frames)
Load imagelist.
Definition: fors_image.c:234
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:505
void fors_image_delete_const(const fors_image **image)
Deallocate image and set pointer to NULL.
Definition: fors_image.c:177
void fors_image_divide(fors_image *left, const fors_image *right)
Divide images.
Definition: fors_image.c:733
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:17681
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:383
double fors_image_get_median(const fors_image *image, double *dmedian)
Get median data value.
Definition: fors_image.c:987
void fors_image_exponential(fors_image *image, double b, double db)
Exponential.
Definition: fors_image.c:911
double fors_image_get_error_mean(const fors_image *image, double *dmean)
Get mean of error bars.
Definition: fors_image.c:1441
cpl_image * mos_image_filter_median(cpl_image *image, int nx, int ny)
Convenience function for standard median filtering.
Definition: moses.c:18949
fors_image * fors_image_duplicate(const fors_image *image)
Copy constructor.
Definition: fors_image.c:149
fors_image * fors_image_collapse_minmax_create(const fors_image_list *images, int low, int high)
Minmax collapse.
Definition: fors_image.c:1539
void fors_image_subtract_scalar(fors_image *image, double s, double ds)
Subtract scalar.
Definition: fors_image.c:831
cpl_image * fors_imagelist_collapse_median_create(const cpl_imagelist *ilist)
Workaround for cpl_imagelist_collapse_median_create.
Definition: fors_utils.c:616