FORS Pipeline Reference Manual  5.0.9
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 } while (0)
283 
290 fors_image *
291 fors_image_load(const cpl_frame *frame)
292 {
293  fors_image *image = NULL;
294  cpl_image *data = NULL;
295  cpl_image *variance = NULL;
296  const char *filename;
297  int extension= 0;
298  const int plane = 0;
299 
300  assure( frame != NULL, return image, NULL );
301  /* bias may be NULL */
302  filename = cpl_frame_get_filename(frame);
303  assure( filename != NULL, return image,
304  "NULL filename received");
305 
306  cpl_msg_info(cpl_func, "Loading %s: %s",
307  /* fors_frame_get_group_string(frame), */
308  (cpl_frame_get_tag(frame) != NULL) ?
309  cpl_frame_get_tag(frame) : "NULL",
310  filename);
311 
312  /* Get data */
313  data = cpl_image_load(filename,
314  FORS_IMAGE_TYPE, plane, extension);
315 
316  assure( data != NULL, return image,
317  "Could not load image from %s extension %d",
318  filename, extension);
319 
320 
321  /* Read variance if it exists */
322  if (cpl_frame_get_nextensions(frame) == 0) {
323 
324  /* Create an empty variance */
325  variance = cpl_image_new(
326  cpl_image_get_size_x(data),
327  cpl_image_get_size_y(data),
328  FORS_IMAGE_TYPE);
329 
330  }
331  else {
332 
333  extension = 1;
334 
335  /* Get error bars */
336  variance = cpl_image_load(filename,
337  FORS_IMAGE_TYPE, plane, extension);
338 
339  assure( variance != NULL, return image,
340  "Could not load image from %s extension %d",
341  filename, extension);
342 
343  cpl_image_power(variance, 2);
344 
345  assure( cpl_image_get_min(variance) >= 0,
346  cpl_image_delete(variance); return image,
347  "Illegal minimum variance: %g",
348  cpl_image_get_min(variance));
349 
350  }
351 
352  image = fors_image_new(data, variance);
353 
354  cleanup;
355  return image;
356 }
357 
358 
359 #undef cleanup
360 #define cleanup \
361 do { \
362  cpl_image_delete(sigma); \
363  cpl_propertylist_delete(extension_header); \
364 } while(0)
365 
374 void
375 fors_image_save(const fors_image *image, const cpl_propertylist *header,
376  const cpl_propertylist *err_header,
377  const char *filename)
378 {
379  cpl_propertylist *extension_header = NULL;
380  cpl_image *sigma = NULL;
381 
382  assure( image != NULL, return, NULL );
383  /* header may be NULL */
384  assure( filename != NULL, return, NULL );
385 
386  cpl_image_save(image->data, filename, CPL_BPP_IEEE_FLOAT, header,
387  CPL_IO_DEFAULT);
388  assure( !cpl_error_get_code(), return,
389  "Cannot save product %s", filename);
390 
391  sigma = cpl_image_power_create(image->variance, 0.5);
392  /* This would probably be faster if sqrt() is used rather than pow */
393  if(err_header != NULL)
394  extension_header = cpl_propertylist_duplicate(err_header);
395  else
396  extension_header = cpl_propertylist_new();
397  cpl_propertylist_append_string(extension_header,
398  "EXTNAME", "IMAGE.ERR");
399 
400  cpl_image_save(sigma, filename, CPL_BPP_IEEE_FLOAT, extension_header,
401  CPL_IO_EXTEND);
402  assure( !cpl_error_get_code(), return,
403  "Cannot save product %s", filename);
404 
405  cleanup;
406  return;
407 }
408 
409 
410 #undef cleanup
411 #define cleanup \
412 do { \
413  cpl_image_delete(var_bkg); \
414  cpl_image_delete(sigma_bkg); \
415 } while(0)
416 
427 void
428 fors_image_save_sex(const fors_image *image, const cpl_propertylist *header,
429  const char *filename_dat,
430  const char *filename_var,
431  int radius)
432 {
433  cpl_propertylist *extension_header = NULL;
434  cpl_image *sigma_bkg = NULL;
435  cpl_image *var_bkg = NULL;
436 
437  assure( image != NULL, return, NULL );
438  /* header may be NULL */
439  assure( filename_dat != NULL, return, NULL );
440  assure( filename_var != NULL, return, NULL );
441 
442  cpl_image_save(image->data, filename_dat, CPL_BPP_IEEE_FLOAT, header,
443  CPL_IO_DEFAULT);
444  assure( !cpl_error_get_code(), return,
445  "Cannot save product %s", filename_dat);
446 
447  /* Sextractor wants as input the background error bars,
448  i.e. excluding sources.
449  Therefore filter away sources but keep the sharp edges
450  between the illuminated / non-illuminated areas.
451 
452  I.e. use a median filter, average filter would not work.
453  */
454 
455  cpl_msg_info(cpl_func, "Creating background error map");
456 
457  bool filter_data = false; /* filter the variance image */
458  int xstep = radius/2; /* 25 points sampling grid
459  . . . . .
460  . . . . .
461  . . . . .
462  . . . . .
463  . . . . .
464  */
465  int ystep = radius/2;
466  int xstart = 1;
467  int ystart = 1;
468  int xend = fors_image_get_size_x(image);
469  int yend = fors_image_get_size_y(image);
470 
471 
472  var_bkg = fors_image_filter_median_create(image,
473  radius,
474  radius,
475  xstart, ystart,
476  xend, yend,
477  xstep, ystep,
478  filter_data);
479  assure( !cpl_error_get_code(), return,
480  "Median filtering failed");
481 
482  sigma_bkg = cpl_image_power_create(var_bkg, 0.5);
483 
484  cpl_image_save(sigma_bkg, filename_var,
485  CPL_BPP_IEEE_FLOAT, extension_header,
486  CPL_IO_DEFAULT);
487  assure( !cpl_error_get_code(), return,
488  "Cannot save product %s", filename_var);
489 
490  cleanup;
491  return;
492 }
493 
494 #undef cleanup
495 #define cleanup
496 
501 cpl_size fors_image_get_size_x(const fors_image *image)
502 {
503  assure( image != NULL, return -1, NULL );
504  return cpl_image_get_size_x(image->data);
505 }
506 
507 #undef cleanup
508 #define cleanup
509 
514 cpl_size fors_image_get_size_y(const fors_image *image)
515 {
516  assure( image != NULL, return -1, NULL );
517  return cpl_image_get_size_y(image->data);
518 }
519 
520 #undef cleanup
521 #define cleanup
522 
526 const float *fors_image_get_data_const(const fors_image *image)
527 {
528  assure( image != NULL, return NULL, NULL );
529 
530  assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return NULL, NULL );
531  /* This function (including API) would need to change
532  if the pixel type changes */
533 
534  return cpl_image_get_data_float(image->data);
535 }
536 
537 #undef cleanup
538 #define cleanup
539 
546 void
548 {
549  assure( image != NULL, return, NULL );
550 
551  cpl_image_abs(image->data);
552 
553  return;
554 }
555 
556 #undef cleanup
557 #define cleanup
558 
565 void
567 {
568  assure( image != NULL, return, NULL );
569 
570  cpl_image_multiply(image->data, image->data);
571  /* It is an undocumented feature of CPL that you
572  can pass the same image to cpl_image_multiply and get
573  the right answer. Let us hope it does not change...
574  */
575  cpl_image_multiply_scalar(image->variance, 2);
576 
577  return;
578 }
579 
580 
581 #undef cleanup
582 #define cleanup \
583 do { \
584  cpl_image_delete(temp); \
585 } while(0)
586 
594 void
596 {
597  cpl_image *temp = NULL;
598  assure( left != NULL, return, NULL );
599  assure( right != NULL, return, NULL );
600 
601  cpl_image_subtract(left->data, right->data);
602 
603  /* variance_left := variance_left + variance_right */
604  cpl_image_add(left->variance, right->variance);
605 
606  cleanup;
607  return;
608 }
609 
610 #undef cleanup
611 #define cleanup
612 
622 void
623 fors_image_multiply_noerr(fors_image *left, const cpl_image *right)
624 {
625  assure( left != NULL, return, NULL );
626  assure( right != NULL, return, NULL );
627  assure( cpl_image_get_size_x(left->data) == cpl_image_get_size_x(right) &&
628  cpl_image_get_size_y(left->data) == cpl_image_get_size_y(right),
629  return,
630  "Incompatible data and weight image sizes: "
631  "%"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT
632  " and %"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT,
633  cpl_image_get_size_x(left->data),
634  cpl_image_get_size_y(left->data),
635  cpl_image_get_size_x(right),
636  cpl_image_get_size_y(right));
637 
638  cpl_image_multiply(left->data, right);
639  cpl_image_multiply(left->variance, right);
640  cpl_image_multiply(left->variance, right);
641 
642  return;
643 }
644 
645 #undef cleanup
646 #define cleanup
647 
663 void
664 fors_image_divide_noerr(fors_image *left, cpl_image *right)
665 {
666  assure( left != NULL, return, NULL );
667  assure( right != NULL, return, NULL );
668  assure( cpl_image_get_size_x(left->data) == cpl_image_get_size_x(right) &&
669  cpl_image_get_size_y(left->data) == cpl_image_get_size_y(right),
670  return,
671  "Incompatible data and weight image sizes: "
672  "%"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT
673  " and %"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT,
674  cpl_image_get_size_x(left->data),
675  cpl_image_get_size_y(left->data),
676  cpl_image_get_size_x(right),
677  cpl_image_get_size_y(right));
678 
679  int x, y;
680  int nx = cpl_image_get_size_x(right);
681  int ny = cpl_image_get_size_y(right);
682  float *datal = cpl_image_get_data_float(left->data);
683  float *datav = cpl_image_get_data_float(left->variance);
684  float *datar = cpl_image_get_data_float(right);
685  for (y = 0; y < ny; y++) {
686  for (x = 0; x < nx; x++) {
687  if (datar[x + nx*y] == 0) {
688  datar[x + nx*y] = 1;
689  datal[x + nx*y] = 1;
690 
691  datav[x + nx*y] = FORS_IMAGE_TYPE_MAX;
692  }
693  }
694  }
695 
696  cpl_image_divide(left->data, right);
697  cpl_image_divide(left->variance, right);
698  cpl_image_divide(left->variance, right);
699 
700  return;
701 }
702 
703 #undef cleanup
704 #define cleanup \
705 do { \
706  fors_image_delete(&dupl); \
707 } while(0)
708 
728 void
730 {
731  fors_image *dupl = NULL;
732 
733  assure( left != NULL, return, NULL );
734  assure( right != NULL, return, NULL );
735 
736  dupl = fors_image_duplicate(right);
737 
738  cpl_image_divide(left->data, dupl->data);
739  /* This CPL function divides by zero by setting x/0 = 1 for all x */
740 
741  cpl_image_multiply(dupl->variance, left->data);
742  cpl_image_multiply(dupl->variance, left->data);
743 
744  /* Now dupl->variance = sigma2^2 * data1^2 / data2^2 */
745 
746  cpl_image_add(left->variance, dupl->variance);
747 
748  /* Now left->variance = sigma1^2 + sigma2^2 * data1^2 / data2^2 */
749 
750  cpl_image_divide(left->variance, dupl->data);
751  cpl_image_divide(left->variance, dupl->data);
752  /* QED */
753 
754  /* Handle division by zero */
755  int x, y;
756  int nx = cpl_image_get_size_x(left->data);
757  int ny = cpl_image_get_size_y(left->data);
758  float *datal = cpl_image_get_data_float(left->data);
759  float *datav = cpl_image_get_data_float(left->variance);
760  float *datar = cpl_image_get_data_float(right->data);
761  for (y = 0; y < ny; y++) {
762  for (x = 0; x < nx; x++) {
763  if (datar[x + nx*y] == 0) {
764  datal[x + nx*y] = 1;
765  datav[x + nx*y] = FORS_IMAGE_TYPE_MAX;
766  }
767  }
768  }
769 
770  cleanup;
771  return;
772 }
773 
774 #undef cleanup
775 #define cleanup \
776 do { \
777  cpl_image_delete(s22d12); \
778 } while(0)
779 
790 void
792 {
793  cpl_image *s22d12 = NULL;
794 
795  assure( left != NULL, return, NULL );
796  assure( right != NULL, return, NULL );
797 
798  s22d12 = cpl_image_duplicate(right->variance);
799  cpl_image_multiply(s22d12, left->data);
800  cpl_image_multiply(s22d12, left->data);
801 
802  cpl_image_multiply(left->variance, right->data);
803  cpl_image_multiply(left->variance, right->data);
804  cpl_image_add(left->variance, s22d12);
805 
806  cpl_image_multiply(left->data, right->data);
807 
808  cleanup;
809  return;
810 }
811 
812 
813 #undef cleanup
814 #define cleanup
815 
827 void fors_image_subtract_scalar(fors_image *image, double s, double ds)
828 {
829  assure( image != NULL, return, NULL );
830  assure( ds <= 0, return, "Unsupported");
831 
832  cpl_image_subtract_scalar(image->data, s);
833 
834  return;
835 }
836 
837 
838 #undef cleanup
839 #define cleanup
840 
852 void fors_image_divide_scalar(fors_image *image, double s, double ds)
853 {
854  assure( image != NULL, return, NULL );
855  assure( s != 0, return, "Division by zero");
856  assure( ds <= 0, return, "Unsupported");
857 
858  cpl_image_divide_scalar(image->data, s);
859  cpl_image_divide_scalar(image->variance, s*s);
860 
861  return;
862 }
863 
864 #undef cleanup
865 #define cleanup
866 
878 void fors_image_multiply_scalar(fors_image *image, double s, double ds)
879 {
880  assure( image != NULL, return, NULL );
881  assure( ds <= 0, return, "Unsupported");
882 
883  cpl_image_multiply_scalar(image->data, s);
884  cpl_image_multiply_scalar(image->variance, s*s);
885 
886  return;
887 }
888 
889 #undef cleanup
890 #define cleanup \
891 do { \
892  cpl_image_delete(temp); \
893 } while(0)
894 
907 void fors_image_exponential(fors_image *image, double b, double db)
908 {
909  cpl_image *temp = NULL;
910 
911  assure( image != NULL, return, NULL );
912  assure( b >= 0, return, "Negative base: %f", b);
913  assure( db <= 0, return, "Unsupported");
914 
915  cpl_image_exponential(image->data, b);
916 
917  double lnb = log(b);
918 
919  cpl_image_multiply_scalar(image->variance, lnb*lnb);
920  cpl_image_multiply(image->variance, image->data);
921  cpl_image_multiply(image->variance, image->data);
922 
923  return;
924 }
925 
926 
927 #undef cleanup
928 #define cleanup
929 
934 double
936 {
937  assure( image != NULL, return 0, NULL );
938 
939  return cpl_image_get_min(image->data);
940 }
941 
942 #undef cleanup
943 #define cleanup
944 
949 double
951 {
952  assure( image != NULL, return 0, NULL );
953 
954  return cpl_image_get_max(image->data);
955 }
956 
957 #undef cleanup
958 #define cleanup
959 
965 double
966 fors_image_get_mean(const fors_image *image, double *dmean)
967 {
968  assure( image != NULL, return 0, NULL );
969  assure( dmean == NULL, return 0, "Unsupported");
970 
971  return cpl_image_get_mean(image->data);
972 }
973 
974 #undef cleanup
975 #define cleanup
976 
982 double
983 fors_image_get_median(const fors_image *image, double *dmedian)
984 {
985  assure( image != NULL, return 0, NULL );
986  assure( dmedian == NULL, return 0, "Unsupported");
987 
988  return cpl_image_get_median(image->data);
989 }
990 
991 
992 #undef cleanup
993 #define cleanup
994 
1009  int xlo, int ylo,
1010  int xhi, int yhi)
1011 {
1012  /* CPL is missing the function to locally extract an image,
1013  so this this inefficient CPL function */
1014  assure( image != NULL, return, NULL );
1015  assure( 1 <= xlo && xlo <= xhi && xhi <= fors_image_get_size_x(image) &&
1016  1 <= ylo && ylo <= yhi && yhi <= fors_image_get_size_y(image),
1017  return, "Cannot extraction region (%d, %d) - (%d, %d) of "
1018  "%"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT" image",
1019  xlo, ylo, xhi, yhi,
1020  fors_image_get_size_x(image),
1021  fors_image_get_size_y(image));
1022 
1023  cpl_image *new_data = cpl_image_extract(image->data,
1024  xlo, ylo,
1025  xhi, yhi);
1026  cpl_image_delete(image->data);
1027 
1028  cpl_image* new_variance = cpl_image_extract(image->variance,
1029  xlo, ylo,
1030  xhi, yhi);
1031  cpl_image_delete(image->variance);
1032 
1033  image->data = new_data;
1034  image->variance = new_variance;
1035 
1036  return;
1037 }
1038 
1064 cpl_image *
1066  int xradius,
1067  int yradius,
1068  int xstart,
1069  int ystart,
1070  int xend,
1071  int yend,
1072  int xstep,
1073  int ystep,
1074  bool use_data)
1075 {
1076  const cpl_image *input = NULL;
1077  cpl_image *smooth = NULL;
1078  int nx, ny;
1079 
1080  assure( image != NULL, return smooth, NULL );
1081  passure( image->data != NULL, return smooth );
1082  passure( image->variance != NULL, return smooth );
1083 
1084  input = (use_data) ? image->data : image->variance;
1085 
1086  nx = cpl_image_get_size_x(input);
1087  ny = cpl_image_get_size_y(input);
1088 
1089  if (xstep < 1) xstep = 1;
1090  if (ystep < 1) ystep = 1;
1091 
1092  assure( 1 <= xstart && xstart <= xend && xend <= nx &&
1093  1 <= ystart && ystart <= yend && yend <= ny, return smooth,
1094  "Illegal region (%d, %d) - (%d, %d) of %dx%d image",
1095  xstart, ystart,
1096  xend, yend,
1097  nx, ny);
1098 
1099  smooth = cpl_image_duplicate(input);
1100 
1101  /* For efficiency reasons, assume that the image type is float */
1102  assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return smooth, NULL );
1103 
1104  const float *input_data = cpl_image_get_data_float_const(input);
1105  float *smooth_data = cpl_image_get_data_float(smooth);
1106  float *data = cpl_malloc((2*yradius + 1)*(2*xradius + 1)*sizeof(*data));
1107 
1108  int y;
1109  for (y = ystart; y < yend; y++) {
1110  /*
1111  Sample kernel on grid which always contains the central pixel
1112 
1113  Trim window (note: this will cause fewer values to
1114  be used for the median near the region borders
1115  */
1116  int ylo = y - (yradius/ystep) * ystep;
1117  int yhi = y + (yradius/ystep) * ystep;
1118 
1119  while (ylo < ystart) ylo += ystep;
1120  while (yhi > yend ) yhi -= ystep;
1121 
1122  int x;
1123  for (x = xstart; x < xend; x++) {
1124  int xlo = x - (xradius/xstep) * xstep;
1125  int xhi = x + (xradius/xstep) * xstep;
1126 
1127  while (xlo < xstart) xlo += xstep;
1128  while (xhi > xend ) xhi -= xstep;
1129 
1130  /* Collect data */
1131  int k = 0;
1132  int j, i;
1133  for (j = ylo; j <= yhi; j += ystep) {
1134  for (i = xlo; i <= xhi; i += xstep) {
1135  data[k++] = input_data[ (i-1) + (j-1)*nx ];
1136  }
1137  }
1138 
1139  /* Get median */
1140  smooth_data[ (x-1) + (y-1)*nx ] =
1141  fors_tools_get_median_float(data, k);
1142  }
1143  }
1144 
1145  cpl_free(data);
1146  return smooth;
1147 }
1148 
1149 #undef cleanup
1150 #define cleanup \
1151 do { \
1152  cpl_image_delete(input); \
1153 } while(0)
1154 cpl_image *
1155 fors_image_flat_fit_create(fors_image *image,
1156  int step,
1157  int degree,
1158  float level)
1159 {
1160  cpl_image *temp = NULL;
1161  cpl_image *input = NULL;
1162  cpl_image *smooth = NULL;
1163  int nx, ny;
1164 
1165  assure( image != NULL, return smooth, NULL );
1166  passure( image->data != NULL, return smooth );
1167  assure( step > 0, return smooth, NULL );
1168  assure( degree >= 0, return smooth, NULL );
1169 
1170 
1171  temp = image->data;
1172 
1173  nx = cpl_image_get_size_x(temp);
1174  ny = cpl_image_get_size_y(temp);
1175 
1176  /*
1177  * For efficiency reasons, assume that the image type is float
1178  */
1179 
1180  assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return smooth, NULL );
1181 
1182  /*
1183  * Apply light median filter, to eliminate big outliers from fit
1184  */
1185 
1186  input = mos_image_filter_median(image->data, 3, 3);
1187 
1188  const float *input_data = cpl_image_get_data_float_const(input);
1189 
1190  /*
1191  * First of all, count how many points will have to be fitted
1192  */
1193 
1194  int x, y, pos;
1195  int count = 0;
1196  for (y = 0; y < ny; y += step) {
1197  pos = y*nx;
1198  for (x = 0; x < nx; x += step, pos += step) {
1199  if (input_data[pos] > level) {
1200  count++;
1201  }
1202  }
1203  }
1204 
1205  if (count < (degree+1)*(degree+2)) {
1206  step = sqrt((nx*nx)/((degree+1)*(degree+2))) / 2;
1207  if (step == 0)
1208  step = 1;
1209  cpl_msg_error(cpl_func, "Flat field image too small (%dx%d). "
1210  "Please provide a smaller resampling step (a good "
1211  "value would be %d)", nx, ny, step);
1212  cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
1213  cleanup;
1214  return NULL;
1215  }
1216 
1217 
1218  /*
1219  * Fill position and flux vectors with appropriate values
1220  */
1221 
1222  cpl_bivector *positions = cpl_bivector_new(count);
1223  double *xpos = cpl_bivector_get_x_data(positions);
1224  double *ypos = cpl_bivector_get_y_data(positions);
1225  cpl_vector *fluxes = cpl_vector_new(count);
1226  double *flux = cpl_vector_get_data(fluxes);
1227 
1228  count = 0;
1229  for (y = 0; y < ny; y += step) {
1230  pos = y*nx;
1231  for (x = 0; x < nx; x += step, pos += step) {
1232  if (input_data[pos] > level) {
1233  xpos[count] = x;
1234  ypos[count] = y;
1235  flux[count] = input_data[pos];
1236  count++;
1237  }
1238  }
1239  }
1240 
1241  cpl_image_delete(input); input = NULL;
1242 
1243  /*
1244  * Do the fit, and fill the output image with the model
1245  * values in all pixels.
1246  */
1247 
1248  cpl_polynomial *model = cpl_polynomial_fit_2d_create(positions,
1249  fluxes,
1250  degree,
1251  NULL);
1252 
1253  cpl_bivector_delete(positions);
1254  cpl_vector_delete(fluxes);
1255 
1256  smooth = cpl_image_new(nx, ny, FORS_IMAGE_TYPE);
1257  float *smooth_data = cpl_image_get_data_float(smooth);
1258 
1259  cpl_vector *point = cpl_vector_new(2);
1260  double *dpoint = cpl_vector_get_data(point);
1261 
1262  for (y = 0; y < ny; y++) {
1263  pos = y*nx;
1264  dpoint[1] = y;
1265  for (x = 0; x < nx; x++, pos++) {
1266  dpoint[0] = x;
1267  smooth_data[pos] = cpl_polynomial_eval(model, point);
1268  }
1269  }
1270 
1271  cpl_polynomial_delete(model);
1272  cpl_vector_delete(point);
1273 
1274  cleanup;
1275  return smooth;
1276 
1277 }
1278 
1279 #undef cleanup
1280 #define cleanup
1281 
1297 cpl_image *
1299  int xradius,
1300  int yradius,
1301  bool use_data)
1302 {
1303  const cpl_image *input = NULL;
1304  cpl_image *hmaxima = NULL;
1305  cpl_image *maxima = NULL;
1306  int nx, ny;
1307 
1308  assure( image != NULL, return maxima, NULL );
1309  passure( image->data != NULL, return maxima );
1310  passure( image->variance != NULL, return maxima );
1311 
1312  input = (use_data) ? image->data : image->variance;
1313 
1314  nx = cpl_image_get_size_x(input);
1315  ny = cpl_image_get_size_y(input);
1316 
1317  /*
1318  * Allocate space for horizontal max filter result.
1319  */
1320 
1321  hmaxima = cpl_image_duplicate(input);
1322 
1323  /* For efficiency reasons, assume that the image type is float */
1324  assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return maxima, NULL );
1325 
1326  float *input_data = (float *)cpl_image_get_data_float_const(input);
1327  float *maxima_data = cpl_image_get_data_float(hmaxima);
1328 
1329  int y;
1330  for (y = 0; y < ny; y++) {
1331  const float *irow = input_data + y * nx;
1332  float *orow = maxima_data + y * nx;
1333  max_filter(irow, orow, nx, 2*xradius+1);
1334  }
1335 
1336  cpl_image_turn(hmaxima, 1);
1337 
1338  /*
1339  * Allocate space for vertical max filter result.
1340  */
1341 
1342  maxima = cpl_image_duplicate(hmaxima);
1343  input_data = cpl_image_get_data_float(hmaxima);
1344  maxima_data = cpl_image_get_data_float(maxima);
1345 
1346  /*
1347  * Now nx is the y size of the rotated image...
1348  */
1349 
1350  int x;
1351  for (x = 0; x < nx; x++) {
1352  const float *irow = input_data + x * ny;
1353  float *orow = maxima_data + x * ny;
1354  max_filter(irow, orow, ny, 2*yradius+1);
1355  }
1356 
1357  cpl_image_delete(hmaxima);
1358 
1359  cpl_image_turn(maxima, -1);
1360 
1361  return maxima;
1362 }
1363 
1364 #undef cleanup
1365 #define cleanup
1366 
1372 double
1373 fors_image_get_stdev(const fors_image *image, double *dstdev)
1374 {
1375  assure( image != NULL, return 0, NULL );
1376  assure( dstdev == NULL, return 0, "Unsupported");
1377 
1378  return cpl_image_get_stdev(image->data);
1379 }
1380 #undef cleanup
1381 #define cleanup \
1382 do { \
1383  cpl_mask_delete(rejected); \
1384  cpl_image_delete(im); \
1385 } while (0)
1386 
1395  double cut,
1396  double *dstdev)
1397 {
1398  cpl_mask *rejected = NULL;
1399  cpl_image *im = NULL;
1400 
1401  assure( image != NULL, return 0, NULL );
1402  assure( cut > 0, return 0, "Illegal cut: %f", cut );
1403  assure( dstdev == NULL, return 0, "Unsupported");
1404 
1405  double median = fors_image_get_median(image, NULL);
1406 
1407  im = cpl_image_duplicate(image->data);
1408  cpl_image_subtract_scalar(im, median);
1409  cpl_image_power(im, 2);
1410  /* Now squared residuals wrt median */
1411 
1412  rejected = cpl_mask_threshold_image_create(image->data,
1413  median - cut,
1414  median + cut);
1415  cpl_mask_not(rejected);
1416  cpl_image_reject_from_mask(im, rejected);
1417 
1418  double robust_stdev = sqrt(cpl_image_get_mean(im));
1419 
1420  cleanup;
1421  return robust_stdev;
1422 }
1423 
1424 #undef cleanup
1425 #define cleanup
1426 
1436 double
1437 fors_image_get_error_mean(const fors_image *image, double *dmean)
1438 {
1439  double avg;
1440 
1441  assure( image != NULL, return 0, NULL );
1442  assure( dmean == NULL, return 0, "Unsupported");
1443 
1444  avg = cpl_image_get_mean(image->variance);
1445 
1446  /* This should never happen, but avoid sqrt of negative value in any case */
1447  assure( avg >= 0, return -1, "Average variance is %f", avg);
1448 
1449  return sqrt(avg);
1450 }
1451 
1452 
1453 #undef cleanup
1454 #define cleanup \
1455 do { \
1456  cpl_imagelist_delete(datlist); \
1457  cpl_imagelist_delete(varlist); \
1458 } while (0)
1459 
1468 fors_image *
1469 fors_image_collapse_create(const fors_image_list *images)
1470 {
1471  cpl_imagelist *datlist = NULL;
1472  cpl_imagelist *varlist = NULL;
1473  cpl_image *data = NULL;
1474  cpl_image *variance = NULL;
1475  const fors_image *i;
1476  int N = 0;
1477 
1478  assure( images != NULL, return NULL, NULL );
1479  assure( fors_image_list_size(images) > 0, return NULL,
1480  "Cannot stack zero images");
1481 
1482  i = fors_image_list_first_const(images);
1483 
1484  datlist = cpl_imagelist_new();
1485  varlist = cpl_imagelist_new();
1486 
1487  while(i != NULL) {
1488 
1489  /* Append current image to image lists */
1490  cpl_imagelist_set(datlist,
1491  cpl_image_duplicate(i->data),
1492  cpl_imagelist_get_size(datlist));
1493  cpl_imagelist_set(varlist,
1494  cpl_image_duplicate(i->variance),
1495  cpl_imagelist_get_size(varlist));
1496  i = fors_image_list_next_const(images);
1497  N++;
1498  }
1499 
1500 #ifdef CPL_IS_NOT_CRAP
1501  data = cpl_imagelist_collapse_create(datlist);
1502 
1503  variance = cpl_imagelist_collapse_create(varlist);
1504 #else
1505  data = fors_imagelist_collapse_create(datlist);
1506 
1507  variance = fors_imagelist_collapse_create(varlist);
1508 #endif
1509 
1510  cpl_image_divide_scalar(variance, N);
1511 
1512  cleanup;
1513  return fors_image_new(data, variance);
1514 }
1515 
1516 
1517 #undef cleanup
1518 #define cleanup \
1519 do { \
1520  cpl_imagelist_delete(datlist); \
1521  cpl_imagelist_delete(varlist); \
1522 } while (0)
1523 
1534 fors_image *
1535 fors_image_collapse_minmax_create(const fors_image_list *images,
1536  int low, int high)
1537 {
1538  cpl_imagelist *datlist = NULL;
1539  cpl_imagelist *varlist = NULL;
1540  cpl_image *data = NULL;
1541  cpl_image *variance = NULL;
1542  const fors_image *i;
1543  int N = 0;
1544 
1545  assure( images != NULL, return NULL, NULL );
1546  assure( fors_image_list_size(images) > low + high, return NULL,
1547  "Cannot reject more images than there are");
1548  assure( low*high >= 0 && low+high > 0, return NULL,
1549  "Invalid minmax rejection criteria");
1550 
1551  i = fors_image_list_first_const(images);
1552 
1553  datlist = cpl_imagelist_new();
1554  varlist = cpl_imagelist_new();
1555 
1556  while(i != NULL) {
1557 
1558  /* Append current image to image lists */
1559  cpl_imagelist_set(datlist,
1560  cpl_image_duplicate(i->data),
1561  cpl_imagelist_get_size(datlist));
1562  cpl_imagelist_set(varlist,
1563  cpl_image_duplicate(i->variance),
1564  cpl_imagelist_get_size(varlist));
1565  i = fors_image_list_next_const(images);
1566  N++;
1567  }
1568 
1569  data = cpl_imagelist_collapse_minmax_create(datlist, low, high);
1570  variance = cpl_imagelist_collapse_minmax_create(varlist, low, high);
1571 
1572  cpl_image_divide_scalar(variance, N);
1573 
1574  cleanup;
1575  return fors_image_new(data, variance);
1576 }
1577 
1590 fors_image *
1591 fors_image_collapse_ksigma_create(const fors_image_list *images,
1592  int low, int high, int iter)
1593 {
1594  cpl_imagelist *datlist = NULL;
1595  cpl_imagelist *varlist = NULL;
1596  cpl_image *data = NULL;
1597  cpl_image *variance = NULL;
1598  cpl_image *ngood = NULL;
1599  const fors_image *i;
1600 
1601  assure( images != NULL, return NULL, NULL );
1602 
1603  i = fors_image_list_first_const(images);
1604 
1605  datlist = cpl_imagelist_new();
1606  varlist = cpl_imagelist_new();
1607 
1608  while(i != NULL) {
1609 
1610  /* Append current image to image lists */
1611  cpl_imagelist_set(datlist,
1612  cpl_image_duplicate(i->data),
1613  cpl_imagelist_get_size(datlist));
1614  cpl_imagelist_set(varlist,
1615  cpl_image_duplicate(i->variance),
1616  cpl_imagelist_get_size(varlist));
1617  i = fors_image_list_next_const(images);
1618  }
1619 
1620  data = mos_ksigma_stack(datlist, low, high, iter, &ngood);
1621  variance = cpl_imagelist_collapse_create(varlist);
1622 
1623  cpl_image_divide(variance, ngood);
1624 
1625  cpl_image_delete(ngood);
1626  cleanup;
1627 
1628  return fors_image_new(data, variance);
1629 }
1630 
1642 fors_image *
1643 fors_image_collapse_median_create(const fors_image_list *images)
1644 {
1645  cpl_imagelist *datlist = NULL;
1646  cpl_imagelist *varlist = NULL;
1647  cpl_image *data = NULL;
1648  cpl_image *variance = NULL;
1649  const fors_image *i;
1650  int N = 0;
1651 
1652  assure( images != NULL, return NULL, NULL );
1653  assure( fors_image_list_size(images) > 0, return NULL,
1654  "Cannot stack zero images");
1655 
1656  i = fors_image_list_first_const(images);
1657 
1658  datlist = cpl_imagelist_new();
1659  varlist = cpl_imagelist_new();
1660  while(i != NULL) {
1661  /* Append to image lists */
1662  cpl_imagelist_set(datlist,
1663  cpl_image_duplicate(i->data),
1664  cpl_imagelist_get_size(datlist));
1665  cpl_imagelist_set(varlist,
1666  cpl_image_duplicate(i->variance),
1667  cpl_imagelist_get_size(varlist));
1668 
1669  i = fors_image_list_next_const(images);
1670  N++;
1671  }
1672 
1673 #ifdef CPL_IS_NOT_CRAP
1674  data = cpl_imagelist_collapse_median_create(datlist);
1675 
1676  variance = cpl_imagelist_collapse_create(varlist);
1677 #else
1678  data = fors_imagelist_collapse_median_create(datlist);
1679 
1680  variance = fors_imagelist_collapse_create(varlist);
1681 #endif
1682 
1683  cpl_image_divide_scalar(variance, N);
1684 
1685  cpl_image_multiply_scalar(variance,
1688 
1689  cleanup;
1690  return fors_image_new(data, variance);
1691 }
1692 
1693 #undef cleanup
1694 #define cleanup
1695 
1712 void fors_image_draw(fors_image *image, int type,
1713  double x, double y,
1714  int radius, double color)
1715 {
1716  assure( image != NULL, return, NULL );
1717 
1718  assure( type == 0 || type == 1 || type == 2,
1719  return , "Unsupported type %d", type);
1720 
1721  assure( radius > 0, return, NULL );
1722 
1723  if (type == 2) {
1724  int i;
1725  for (i = 0; i < 360; i++) {
1726  /* Step size of 1 degree is arbitrary */
1727 
1728  int px = x + radius*cos(i/(2*M_PI));
1729  int py = y + radius*sin(i/(2*M_PI));
1730 
1731  if (1 <= px && px <= cpl_image_get_size_x(image->data) &&
1732  1 <= py && py <= cpl_image_get_size_y(image->data)) {
1733  cpl_image_set(image->data, px, py, color);
1734  cpl_image_set(image->variance, px, py, color > 0 ? color : 0);
1735  }
1736  }
1737  }
1738  else {
1739  int i;
1740 
1741  for (i = -radius; i <= radius; i++) {
1742 
1743  int px, py;
1744 
1745  if (type == 0) {
1746  px = x + i;
1747  py = y;
1748  }
1749  else {
1750  px = x;
1751  py = y + i;
1752  }
1753 
1754  if (1 <= px && px <= cpl_image_get_size_x(image->data) &&
1755  1 <= py && py <= cpl_image_get_size_y(image->data)) {
1756  cpl_image_set(image->data , px, py, color);
1757  cpl_image_set(image->variance, px, py, color > 0 ? color : 0);
1758  }
1759  }
1760  }
1761 
1762  return;
1763 }
1764 
1765 hdrl_imagelist * fors_image_list_to_hdrl(const fors_image_list * imalist)
1766 {
1767  int i;
1768  hdrl_imagelist * images_hdrl = hdrl_imagelist_new();
1769  const fors_image * target = fors_image_list_first_const(imalist);
1770  for(i = 0 ; i < fors_image_list_size(imalist); ++i)
1771  {
1772  const cpl_image * ima_data = target->data;
1773  cpl_image * ima_error = cpl_image_power_create(target->variance, 0.5);
1774  cpl_mask * old_bpm = cpl_image_set_bpm(ima_error,
1775  cpl_mask_duplicate(cpl_image_get_bpm_const(ima_data)));
1776  cpl_mask_delete(old_bpm);
1777  hdrl_image * ima_hdrl = hdrl_image_create(ima_data, ima_error);
1778  hdrl_imagelist_set(images_hdrl, ima_hdrl,
1779  hdrl_imagelist_get_size(images_hdrl));
1780  target = fors_image_list_next_const(imalist);
1781  cpl_image_delete(ima_error);
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_error_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:1065
void fors_image_multiply_scalar(fors_image *image, double s, double ds)
Multiply by scalar.
Definition: fors_image.c:878
void fors_image_abs(fors_image *image)
Absolute value.
Definition: fors_image.c:547
double fors_image_get_stdev_robust(const fors_image *image, double cut, double *dstdev)
Get robust empirical stdev of data.
Definition: fors_image.c:1394
void fors_image_square(fors_image *image)
Squared.
Definition: fors_image.c:566
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:950
const float * fors_image_get_data_const(const fors_image *image)
Get pointer to data buffer.
Definition: fors_image.c:526
void fors_image_subtract(fors_image *left, const fors_image *right)
Subtract images.
Definition: fors_image.c:595
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:428
fors_image * fors_image_collapse_create(const fors_image_list *images)
Average collapse.
Definition: fors_image.c:1469
void fors_image_divide_noerr(fors_image *left, cpl_image *right)
Divide images.
Definition: fors_image.c:664
void fors_image_crop(fors_image *image, int xlo, int ylo, int xhi, int yhi)
Crop image.
Definition: fors_image.c:1008
double fors_image_get_stdev(const fors_image *image, double *dstdev)
Get empirical stdev of data.
Definition: fors_image.c:1373
void fors_image_multiply_noerr(fors_image *left, const cpl_image *right)
Multiply images.
Definition: fors_image.c:623
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:514
void fors_image_divide_scalar(fors_image *image, double s, double ds)
Divide by scalar.
Definition: fors_image.c:852
fors_image * fors_image_collapse_ksigma_create(const fors_image_list *images, int low, int high, int iter)
Ksigma collapse.
Definition: fors_image.c:1591
#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:935
fors_image * fors_image_load(const cpl_frame *frame)
Load image.
Definition: fors_image.c:291
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:1298
void fors_image_multiply(fors_image *left, const fors_image *right)
Multiply images.
Definition: fors_image.c:791
double fors_image_get_mean(const fors_image *image, double *dmean)
Get mean data value.
Definition: fors_image.c:966
void fors_image_draw(fors_image *image, int type, double x, double y, int radius, double color)
Draw on image.
Definition: fors_image.c:1712
fors_image * fors_image_collapse_median_create(const fors_image_list *images)
Median collapse.
Definition: fors_image.c:1643
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:501
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:729
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
double fors_image_get_median(const fors_image *image, double *dmedian)
Get median data value.
Definition: fors_image.c:983
void fors_image_exponential(fors_image *image, double b, double db)
Exponential.
Definition: fors_image.c:907
double fors_image_get_error_mean(const fors_image *image, double *dmean)
Get mean of error bars.
Definition: fors_image.c:1437
cpl_image * mos_image_filter_median(cpl_image *image, int nx, int ny)
Convenience function for standard median filtering.
Definition: moses.c:19262
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:1535
void fors_image_subtract_scalar(fors_image *image, double s, double ds)
Subtract scalar.
Definition: fors_image.c:827
cpl_image * fors_imagelist_collapse_median_create(const cpl_imagelist *ilist)
Workaround for cpl_imagelist_collapse_median_create.
Definition: fors_utils.c:616
void fors_image_save(const fors_image *image, const cpl_propertylist *header, const cpl_propertylist *err_header, const char *filename)
Save image.
Definition: fors_image.c:375