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