fors_image.c

00001 /* $Id: fors_image.c,v 1.63 2013-08-07 13:24:40 cgarcia Exp $
00002  *
00003  * This file is part of the FORS Library
00004  * Copyright (C) 2002-2010 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00019  */
00020 
00021 /*
00022  * $Author: cgarcia $
00023  * $Date: 2013-08-07 13:24:40 $
00024  * $Revision: 1.63 $
00025  * $Name: not supported by cvs2svn $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <fors_image.h>
00033 
00034 #include <fors_dfs.h>
00035 #include <fors_utils.h>
00036 #include <fors_pfits.h>
00037 #include <fors_double.h>
00038 #include <fors_saturation.h>
00039 #include <fors_subtract_bias.h>
00040 #include <moses.h>
00041 
00042 #include <cpl.h>
00043 
00044 #include <math.h>
00045 #include <stdbool.h>
00046 #include <stdio.h>
00047 
00048 
00052 const cpl_type FORS_IMAGE_TYPE = CPL_TYPE_FLOAT;
00053 #define FORS_IMAGE_TYPE_MAX FLT_MAX  /* Use a #define rather than a variable here
00054                                         to avoid type casting */
00055 
00056 #undef cleanup
00057 
00058 /* 
00059  * The following static function passes a max filter of given box
00060  * size on the input data buffer. The output data buffer must be
00061  * pre-allocated. The box size must be a positive odd integer.
00062  * Returns 0 on success.
00063  */
00064  
00065 static int 
00066 max_filter(const float *ibuffer, float *obuffer, int length, int size)
00067 {
00068     float  max;
00069     int    start = size / 2;
00070     int    end   = length - size / 2;
00071     int    i, j;
00072 
00073 
00074     for (i = start; i < end; i++) {
00075         max = ibuffer[i-start];
00076         for (j = i - start + 1; j <= i + start; j++)
00077             if (max < ibuffer[j])
00078                 max = ibuffer[j];
00079         obuffer[i] = max;
00080     }
00081 
00082     for (i = 0; i < start; i++)
00083         obuffer[i] = obuffer[start];
00084  
00085     for (i = end; i < length; i++)
00086         obuffer[i] = obuffer[end-1];
00087 
00088     return 0;
00089 }
00090 
00091 #define cleanup
00092 
00101 fors_image *
00102 fors_image_new(cpl_image *data, cpl_image *variance)
00103 {
00104     fors_image *image = NULL;
00105 
00106     assure( data != NULL, return NULL, NULL );
00107     assure( variance != NULL, return NULL, NULL );
00108     
00109 //TODO: Changed to allow saving as double. Check the consequences.
00110 //    assure( cpl_image_get_type(data) == FORS_IMAGE_TYPE, return NULL,
00111 //            "Provided data image type is %s, must be %s",
00112 //            fors_type_get_string(cpl_image_get_type(data)),
00113 //            fors_type_get_string(FORS_IMAGE_TYPE) );
00114 
00115 //   assure( cpl_image_get_type(variance) == FORS_IMAGE_TYPE, return NULL,
00116 //            "Provided weight image type is %s, must be %s",
00117 //            fors_type_get_string(cpl_image_get_type(variance)),
00118 //            fors_type_get_string(FORS_IMAGE_TYPE) );
00119 
00120     assure( cpl_image_get_size_x(data) == cpl_image_get_size_x(variance) &&
00121             cpl_image_get_size_y(data) == cpl_image_get_size_y(variance),
00122             return NULL,
00123             "Incompatible data and weight image sizes: "
00124             "%"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT
00125             " and %"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT,
00126             cpl_image_get_size_x(data), cpl_image_get_size_y(data),
00127             cpl_image_get_size_x(variance), cpl_image_get_size_y(variance));
00128 
00129     assure( cpl_image_get_min(variance) >= 0, return NULL,
00130             "Variances must be non-negative, minimum is %g. \n" 
00131             "This is most likely a software bug. "
00132             "You may contact usd-help@eso.org which can provide a workaround.",
00133             cpl_image_get_min(variance));
00134 
00135     image = cpl_malloc(sizeof(*image));
00136 
00137     image->data = data;
00138     image->variance = variance;
00139 
00140     return image;    
00141 }
00142 
00143 #undef cleanup
00144 #define cleanup
00145 
00150 fors_image *
00151 fors_image_duplicate(const fors_image *image)
00152 {
00153     assure( image != NULL, return NULL, NULL );
00154 
00155     return fors_image_new(cpl_image_duplicate(image->data),
00156                           cpl_image_duplicate(image->variance));
00157 }
00158 
00163 void
00164 fors_image_delete(fors_image **image)
00165 {
00166     if (image && *image) {
00167         cpl_image_delete((*image)->data);
00168         cpl_image_delete((*image)->variance);
00169         cpl_free(*image); *image = NULL;
00170     }
00171     return;
00172 }
00173 
00178 void
00179 fors_image_delete_const(const fors_image **image)
00180 {
00181     fors_image_delete((fors_image **)image);
00182 
00183     return;
00184 }
00185 
00186 /* not used */
00187 #if 0
00188 
00192 static void
00193 fors_image_dump(const fors_image *image, FILE *file)
00194 {
00195     if (image == NULL) {
00196         fprintf(file, "Null image\n");
00197     }
00198     else {
00199         cpl_stats *stats;
00200 
00201         fprintf(file, "Data:\n");
00202         stats = cpl_stats_new_from_image(image->data, CPL_STATS_ALL);
00203         cpl_stats_dump(stats, CPL_STATS_ALL, file);
00204         cpl_stats_delete(stats);
00205             
00206         fprintf(file, "Variance:\n");
00207         stats = cpl_stats_new_from_image(image->variance, CPL_STATS_ALL);
00208         cpl_stats_dump(stats, CPL_STATS_ALL, file);
00209         cpl_stats_delete(stats);
00210     }
00211     
00212     return;
00213 }
00214 #endif
00215 
00216 #undef cleanup
00217 #define cleanup \
00218 do { \
00219     double_list_delete(&sat_percent, double_delete); \
00220 } while (0)
00221 
00235 fors_image_list *
00236 fors_image_load_list(const cpl_frameset *frames)
00237 {
00238     fors_image_list *ilist = fors_image_list_new();
00239     double_list *sat_percent = double_list_new();
00240     
00241     assure( frames != NULL, return ilist, NULL );
00242     assure( !cpl_frameset_is_empty(frames), return ilist, "Empty frameset");
00243 
00244     {
00245         const cpl_frame *f;
00246         
00247         for (int i =0; i< cpl_frameset_get_size(frames); i ++) 
00248         {
00249             f = cpl_frameset_get_position_const(frames, i);
00250             
00251             fors_image *ima = fors_image_load(f);
00252 
00253             fors_image_list_insert(ilist, ima);
00254         }
00255     }
00256 
00257     cleanup;
00258     return ilist;
00259 }
00260 
00272 const fors_image_list *
00273 fors_image_load_list_const(const cpl_frameset *frames)
00274 {
00275     return (const fors_image_list *)
00276         fors_image_load_list(frames);
00277 }
00278 
00279 #undef cleanup
00280 #define cleanup \
00281 do { \
00282 } while (0)
00283 
00290 fors_image *
00291 fors_image_load(const cpl_frame *frame)
00292 {
00293     fors_image *image           = NULL;
00294     cpl_image *data             = NULL;
00295     cpl_image *variance         = NULL;
00296     const char *filename;
00297     int extension= 0;
00298     const int plane = 0;
00299 
00300     assure( frame != NULL, return image, NULL );
00301     /* bias may be NULL */
00302     filename = cpl_frame_get_filename(frame);
00303     assure( filename != NULL, return image, 
00304             "NULL filename received");
00305     
00306     cpl_msg_info(cpl_func, "Loading %s: %s",
00307                  /* fors_frame_get_group_string(frame), */
00308          (cpl_frame_get_tag(frame) != NULL) ? 
00309          cpl_frame_get_tag(frame) : "NULL",
00310                  filename);
00311 
00312     /* Get data */
00313     data = cpl_image_load(filename, 
00314                           FORS_IMAGE_TYPE, plane, extension);
00315     
00316     assure( data != NULL, return image, 
00317             "Could not load image from %s extension %d", 
00318             filename, extension);
00319 
00320 
00321     /* Read variance if it exists */
00322     if (cpl_frame_get_nextensions(frame) == 0) {
00323 
00324         /* Create an empty variance */
00325         variance = cpl_image_new(
00326             cpl_image_get_size_x(data),
00327             cpl_image_get_size_y(data),
00328             FORS_IMAGE_TYPE);        
00329 
00330     }
00331     else {
00332 
00333         extension = 1;
00334         
00335         /* Get error bars */
00336         variance = cpl_image_load(filename, 
00337                                   FORS_IMAGE_TYPE, plane, extension);
00338         
00339         assure( variance != NULL, return image, 
00340                 "Could not load image from %s extension %d", 
00341                 filename, extension);
00342 
00343         cpl_image_power(variance, 2);
00344 
00345         assure( cpl_image_get_min(variance) >= 0, 
00346                 cpl_image_delete(variance); return image,
00347                 "Illegal minimum variance: %g",
00348                 cpl_image_get_min(variance));
00349 
00350     }
00351     
00352     image = fors_image_new(data, variance);
00353     
00354     cleanup;
00355     return image;
00356 }
00357 
00358 
00359 #undef cleanup
00360 #define cleanup \
00361 do { \
00362     cpl_image_delete(sigma); \
00363     cpl_propertylist_delete(extension_header); \
00364 } while(0)
00365 
00374 void
00375 fors_image_save(const fors_image *image, const cpl_propertylist *header,
00376                 const cpl_propertylist *err_header,
00377                 const char *filename)
00378 {
00379     cpl_propertylist *extension_header = NULL;
00380     cpl_image *sigma = NULL;
00381 
00382     assure( image != NULL, return, NULL );
00383     /* header may be NULL */
00384     assure( filename != NULL, return, NULL );
00385     
00386     cpl_image_save(image->data, filename, CPL_BPP_IEEE_FLOAT, header,
00387                    CPL_IO_DEFAULT);
00388     assure( !cpl_error_get_code(), return, 
00389             "Cannot save product %s", filename);
00390     
00391     sigma = cpl_image_power_create(image->variance, 0.5);
00392     /* This would probably be faster if sqrt() is used rather than pow */
00393     if(err_header != NULL)
00394         extension_header = cpl_propertylist_duplicate(err_header);
00395     else
00396         extension_header = cpl_propertylist_new();
00397     cpl_propertylist_append_string(extension_header, 
00398                                    "EXTNAME", "IMAGE.ERR");
00399 
00400     cpl_image_save(sigma, filename, CPL_BPP_IEEE_FLOAT, extension_header,
00401                    CPL_IO_EXTEND);
00402     assure( !cpl_error_get_code(), return, 
00403             "Cannot save product %s", filename);
00404     
00405     cleanup;
00406     return;
00407 }
00408 
00409 
00410 #undef cleanup
00411 #define cleanup \
00412 do { \
00413     cpl_image_delete(var_bkg); \
00414     cpl_image_delete(sigma_bkg); \
00415 } while(0)
00416 
00427 void
00428 fors_image_save_sex(const fors_image *image, const cpl_propertylist *header,
00429                     const char *filename_dat,
00430                     const char *filename_var,
00431                     int radius)
00432 {
00433     cpl_propertylist *extension_header = NULL;
00434     cpl_image *sigma_bkg = NULL;
00435     cpl_image *var_bkg = NULL;
00436 
00437     assure( image != NULL, return, NULL );
00438     /* header may be NULL */
00439     assure( filename_dat != NULL, return, NULL );
00440     assure( filename_var != NULL, return, NULL );
00441 
00442     cpl_image_save(image->data, filename_dat, CPL_BPP_IEEE_FLOAT, header,
00443                    CPL_IO_DEFAULT);
00444     assure( !cpl_error_get_code(), return, 
00445             "Cannot save product %s", filename_dat);
00446     
00447     /* Sextractor wants as input the background error bars,
00448        i.e. excluding sources.
00449        Therefore filter away sources but keep the sharp edges
00450        between the illuminated / non-illuminated areas.
00451 
00452        I.e. use a median filter, average filter would not work.
00453     */
00454 
00455     cpl_msg_info(cpl_func, "Creating background error map");
00456 
00457     bool filter_data = false;  /* filter the variance image */
00458     int xstep = radius/2; /* 25 points sampling grid 
00459                              . . . . .
00460                              . . . . .
00461                              . . . . .
00462                              . . . . .
00463                              . . . . .
00464                            */
00465     int ystep = radius/2;
00466     int xstart = 1;
00467     int ystart = 1;
00468     int xend = fors_image_get_size_x(image);
00469     int yend = fors_image_get_size_y(image);
00470 
00471 
00472     var_bkg = fors_image_filter_median_create(image, 
00473                                               radius,
00474                                               radius,
00475                                               xstart, ystart,
00476                                               xend, yend,
00477                                               xstep, ystep,
00478                                               filter_data);
00479     assure( !cpl_error_get_code(), return, 
00480             "Median filtering failed");
00481 
00482     sigma_bkg = cpl_image_power_create(var_bkg, 0.5);
00483 
00484     cpl_image_save(sigma_bkg, filename_var,
00485                    CPL_BPP_IEEE_FLOAT, extension_header,
00486                    CPL_IO_DEFAULT);
00487     assure( !cpl_error_get_code(), return, 
00488             "Cannot save product %s", filename_var);
00489 
00490     cleanup;
00491     return;
00492 }
00493 
00494 #undef cleanup
00495 #define cleanup
00496 
00501 cpl_size fors_image_get_size_x(const fors_image *image)
00502 {
00503     assure( image != NULL, return -1, NULL );
00504     return cpl_image_get_size_x(image->data);
00505 }
00506 
00507 #undef cleanup
00508 #define cleanup
00509 
00514 cpl_size fors_image_get_size_y(const fors_image *image)
00515 {
00516     assure( image != NULL, return -1, NULL );
00517     return cpl_image_get_size_y(image->data);
00518 }
00519 
00520 #undef cleanup
00521 #define cleanup
00522 
00526 const float *fors_image_get_data_const(const fors_image *image)
00527 {
00528     assure( image != NULL, return NULL, NULL );
00529 
00530     assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return NULL, NULL );
00531     /* This function (including API) would need to change
00532        if the pixel type changes */
00533 
00534     return cpl_image_get_data_float(image->data);
00535 }
00536 
00537 #undef cleanup
00538 #define cleanup
00539 
00546 void
00547 fors_image_abs(fors_image *image)
00548 {
00549     assure( image != NULL, return, NULL );
00550 
00551     cpl_image_abs(image->data);
00552 
00553     return;
00554 }
00555 
00556 #undef cleanup
00557 #define cleanup
00558 
00565 void
00566 fors_image_square(fors_image *image)
00567 {
00568     assure( image != NULL, return, NULL );
00569 
00570     cpl_image_multiply(image->data, image->data);
00571     /* It is an undocumented feature of CPL that you
00572        can pass the same image to cpl_image_multiply and get
00573        the right answer. Let us hope it does not change...
00574     */
00575     cpl_image_multiply_scalar(image->variance, 2);
00576 
00577     return;
00578 }
00579 
00580 
00581 #undef cleanup
00582 #define cleanup \
00583 do { \
00584     cpl_image_delete(temp); \
00585 } while(0)
00586 
00594 void
00595 fors_image_subtract(fors_image *left, const fors_image *right)
00596 {
00597     cpl_image *temp = NULL;
00598     assure( left != NULL, return, NULL );
00599     assure( right != NULL, return, NULL );
00600 
00601     cpl_image_subtract(left->data, right->data);
00602 
00603     /*  variance_left := variance_left + variance_right */
00604     cpl_image_add(left->variance, right->variance);
00605 
00606     cleanup;
00607     return;
00608 }
00609 
00610 #undef cleanup
00611 #define cleanup
00612 
00622 void
00623 fors_image_multiply_noerr(fors_image *left, const cpl_image *right)
00624 {
00625     assure( left != NULL, return, NULL );
00626     assure( right != NULL, return, NULL );
00627     assure( cpl_image_get_size_x(left->data) == cpl_image_get_size_x(right) &&
00628             cpl_image_get_size_y(left->data) == cpl_image_get_size_y(right),
00629             return,
00630             "Incompatible data and weight image sizes: "
00631             "%"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT
00632             " and %"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT,
00633             cpl_image_get_size_x(left->data),
00634             cpl_image_get_size_y(left->data),
00635             cpl_image_get_size_x(right),
00636             cpl_image_get_size_y(right));
00637 
00638     cpl_image_multiply(left->data, right);
00639     cpl_image_multiply(left->variance, right);
00640     cpl_image_multiply(left->variance, right);
00641 
00642     return;
00643 }
00644 
00645 #undef cleanup
00646 #define cleanup
00647 
00663 void
00664 fors_image_divide_noerr(fors_image *left, cpl_image *right)
00665 {
00666     assure( left != NULL, return, NULL );
00667     assure( right != NULL, return, NULL );
00668     assure( cpl_image_get_size_x(left->data) == cpl_image_get_size_x(right) &&
00669             cpl_image_get_size_y(left->data) == cpl_image_get_size_y(right),
00670             return,
00671             "Incompatible data and weight image sizes: "
00672             "%"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT
00673             " and %"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT,
00674             cpl_image_get_size_x(left->data),
00675             cpl_image_get_size_y(left->data),
00676             cpl_image_get_size_x(right),
00677             cpl_image_get_size_y(right));
00678 
00679     int x, y;
00680     int nx = cpl_image_get_size_x(right);
00681     int ny = cpl_image_get_size_y(right);
00682     float *datal = cpl_image_get_data_float(left->data);
00683     float *datav = cpl_image_get_data_float(left->variance);
00684     float *datar = cpl_image_get_data_float(right);
00685     for (y = 0; y < ny; y++) {
00686         for (x = 0; x < nx; x++) {
00687             if (datar[x + nx*y] == 0) {
00688                 datar[x + nx*y] = 1;
00689                 datal[x + nx*y] = 1;
00690 
00691                 datav[x + nx*y] = FORS_IMAGE_TYPE_MAX;
00692             }
00693         }
00694     }
00695 
00696     cpl_image_divide(left->data, right);
00697     cpl_image_divide(left->variance, right);
00698     cpl_image_divide(left->variance, right);
00699 
00700     return;
00701 }
00702 
00703 #undef cleanup
00704 #define cleanup \
00705 do { \
00706     fors_image_delete(&dupl); \
00707 } while(0)
00708 
00728 void
00729 fors_image_divide(fors_image *left, const fors_image *right)
00730 {
00731     fors_image *dupl = NULL;
00732 
00733     assure( left  != NULL, return, NULL );
00734     assure( right != NULL, return, NULL );
00735 
00736     dupl = fors_image_duplicate(right);
00737 
00738     cpl_image_divide(left->data, dupl->data); 
00739     /* This CPL function divides by zero by setting  x/0 = 1 for all x */
00740 
00741     cpl_image_multiply(dupl->variance, left->data);
00742     cpl_image_multiply(dupl->variance, left->data);
00743 
00744     /* Now  dupl->variance = sigma2^2 * data1^2 / data2^2 */
00745 
00746     cpl_image_add(left->variance, dupl->variance);
00747 
00748     /* Now  left->variance = sigma1^2 + sigma2^2 * data1^2 / data2^2 */
00749 
00750     cpl_image_divide(left->variance, dupl->data);
00751     cpl_image_divide(left->variance, dupl->data);
00752     /* QED */
00753 
00754     /* Handle division by zero */
00755     int x, y;
00756     int nx = cpl_image_get_size_x(left->data);
00757     int ny = cpl_image_get_size_y(left->data);
00758     float *datal = cpl_image_get_data_float(left->data);
00759     float *datav = cpl_image_get_data_float(left->variance);
00760     float *datar = cpl_image_get_data_float(right->data);
00761     for (y = 0; y < ny; y++) {
00762         for (x = 0; x < nx; x++) {
00763             if (datar[x + nx*y] == 0) {
00764                 datal[x + nx*y] = 1;
00765                 datav[x + nx*y] = FORS_IMAGE_TYPE_MAX;
00766             }
00767         }
00768     }
00769 
00770     cleanup;
00771     return;
00772 }
00773 
00774 #undef cleanup
00775 #define cleanup \
00776 do { \
00777     cpl_image_delete(s22d12); \
00778 } while(0)
00779 
00790 void
00791 fors_image_multiply(fors_image *left, const fors_image *right)
00792 {
00793     cpl_image *s22d12 = NULL;
00794 
00795     assure( left  != NULL, return, NULL );
00796     assure( right != NULL, return, NULL );
00797 
00798     s22d12 = cpl_image_duplicate(right->variance);
00799     cpl_image_multiply(s22d12, left->data);
00800     cpl_image_multiply(s22d12, left->data);
00801     
00802     cpl_image_multiply(left->variance, right->data);
00803     cpl_image_multiply(left->variance, right->data);
00804     cpl_image_add(left->variance, s22d12);
00805 
00806     cpl_image_multiply(left->data, right->data);
00807 
00808     cleanup;
00809     return;
00810 }
00811 
00812 
00813 #undef cleanup
00814 #define cleanup
00815 
00827 void fors_image_subtract_scalar(fors_image *image, double s, double ds)
00828 {
00829     assure( image != NULL, return, NULL );
00830     assure( ds <= 0, return, "Unsupported");
00831 
00832     cpl_image_subtract_scalar(image->data, s);
00833 
00834     return;
00835 }
00836 
00837 
00838 #undef cleanup
00839 #define cleanup
00840 
00852 void fors_image_divide_scalar(fors_image *image, double s, double ds)
00853 {
00854     assure( image != NULL, return, NULL );
00855     assure( s != 0, return, "Division by zero");
00856     assure( ds <= 0, return, "Unsupported");
00857 
00858     cpl_image_divide_scalar(image->data, s);
00859     cpl_image_divide_scalar(image->variance, s*s);
00860     
00861     return;
00862 }
00863 
00864 #undef cleanup
00865 #define cleanup
00866 
00878 void fors_image_multiply_scalar(fors_image *image, double s, double ds)
00879 {
00880     assure( image != NULL, return, NULL );
00881     assure( ds <= 0, return, "Unsupported");
00882 
00883     cpl_image_multiply_scalar(image->data, s);
00884     cpl_image_multiply_scalar(image->variance, s*s);
00885 
00886     return;
00887 }
00888 
00889 #undef cleanup
00890 #define cleanup \
00891 do { \
00892     cpl_image_delete(temp); \
00893 } while(0)
00894 
00907 void fors_image_exponential(fors_image *image, double b, double db)
00908 {
00909     cpl_image *temp = NULL;
00910 
00911     assure( image != NULL, return, NULL );
00912     assure( b >= 0, return, "Negative base: %f", b);
00913     assure( db <= 0, return, "Unsupported");
00914 
00915     cpl_image_exponential(image->data, b);
00916 
00917     double lnb = log(b);
00918     
00919     cpl_image_multiply_scalar(image->variance, lnb*lnb);
00920     cpl_image_multiply(image->variance, image->data);
00921     cpl_image_multiply(image->variance, image->data);
00922 
00923     return;
00924 }
00925 
00926 
00927 #undef cleanup
00928 #define cleanup
00929 
00934 double
00935 fors_image_get_min(const fors_image *image)
00936 {
00937     assure( image != NULL, return 0, NULL );
00938 
00939     return cpl_image_get_min(image->data);
00940 }
00941 
00942 #undef cleanup
00943 #define cleanup
00944 
00949 double
00950 fors_image_get_max(const fors_image *image)
00951 {
00952     assure( image != NULL, return 0, NULL );
00953 
00954     return cpl_image_get_max(image->data);
00955 }
00956 
00957 #undef cleanup
00958 #define cleanup
00959 
00965 double
00966 fors_image_get_mean(const fors_image *image, double *dmean)
00967 {
00968     assure( image != NULL, return 0, NULL );
00969     assure( dmean == NULL, return 0, "Unsupported");
00970 
00971     return cpl_image_get_mean(image->data);
00972 }
00973 
00974 #undef cleanup
00975 #define cleanup
00976 
00982 double
00983 fors_image_get_median(const fors_image *image, double *dmedian)
00984 {
00985     assure( image != NULL, return 0, NULL );
00986     assure( dmedian == NULL, return 0, "Unsupported");
00987 
00988     return cpl_image_get_median(image->data);
00989 }
00990 
00991 
00992 #undef cleanup
00993 #define cleanup
00994 
01008 void fors_image_crop(fors_image *image,
01009              int xlo, int ylo,
01010              int xhi, int yhi)
01011 {
01012     /* CPL is missing the function to locally extract an image,
01013        so this this inefficient CPL function */
01014     assure( image != NULL, return, NULL );
01015     assure( 1 <= xlo && xlo <= xhi && xhi <= fors_image_get_size_x(image) &&
01016             1 <= ylo && ylo <= yhi && yhi <= fors_image_get_size_y(image),
01017             return, "Cannot extraction region (%d, %d) - (%d, %d) of "
01018             "%"CPL_SIZE_FORMAT"x%"CPL_SIZE_FORMAT" image",
01019             xlo, ylo, xhi, yhi,
01020             fors_image_get_size_x(image),
01021             fors_image_get_size_y(image));
01022     
01023     cpl_image *new_data = cpl_image_extract(image->data,
01024                                             xlo, ylo,
01025                                             xhi, yhi);
01026     cpl_image_delete(image->data);
01027 
01028     cpl_image* new_variance = cpl_image_extract(image->variance,
01029                                                 xlo, ylo,
01030                                                 xhi, yhi);
01031     cpl_image_delete(image->variance);
01032 
01033     image->data = new_data;
01034     image->variance = new_variance;
01035 
01036     return;
01037 }
01038 
01064 cpl_image *
01065 fors_image_filter_median_create(const fors_image *image, 
01066                                 int xradius,
01067                                 int yradius,
01068                                 int xstart, 
01069                                 int ystart,
01070                                 int xend,
01071                                 int yend,
01072                                 int xstep,
01073                                 int ystep,
01074                                 bool use_data)
01075 {
01076     const cpl_image *input = NULL;
01077     cpl_image *smooth = NULL;
01078     int nx, ny;
01079     
01080     assure( image != NULL, return smooth, NULL );
01081     passure( image->data != NULL, return smooth );
01082     passure( image->variance != NULL, return smooth );
01083     
01084     input = (use_data) ? image->data : image->variance;
01085 
01086     nx = cpl_image_get_size_x(input);
01087     ny = cpl_image_get_size_y(input);
01088 
01089     if (xstep < 1) xstep = 1;
01090     if (ystep < 1) ystep = 1;
01091 
01092     assure( 1 <= xstart && xstart <= xend && xend <= nx &&
01093             1 <= ystart && ystart <= yend && yend <= ny, return smooth,
01094             "Illegal region (%d, %d) - (%d, %d) of %dx%d image",
01095             xstart, ystart,
01096             xend, yend,
01097             nx, ny);
01098     
01099     smooth = cpl_image_duplicate(input);
01100 
01101     /* For efficiency reasons, assume that the image type is float */
01102     assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return smooth, NULL );
01103 
01104     const float *input_data  = cpl_image_get_data_float_const(input);
01105     float *smooth_data = cpl_image_get_data_float(smooth);
01106     float *data = cpl_malloc((2*yradius + 1)*(2*xradius + 1)*sizeof(*data));
01107     
01108     int y;
01109     for (y = ystart; y < yend; y++) {
01110         /*
01111           Sample kernel on grid which always contains the central pixel
01112           
01113           Trim window (note: this will cause fewer values to
01114           be used for the median near the region borders 
01115         */
01116         int ylo = y - (yradius/ystep) * ystep;
01117         int yhi = y + (yradius/ystep) * ystep;
01118         
01119         while (ylo < ystart) ylo += ystep;
01120         while (yhi > yend  ) yhi -= ystep;
01121         
01122         int x;
01123         for (x = xstart; x < xend; x++) {
01124             int xlo = x - (xradius/xstep) * xstep;
01125             int xhi = x + (xradius/xstep) * xstep;
01126             
01127             while (xlo < xstart) xlo += xstep;
01128             while (xhi > xend  ) xhi -= xstep;
01129             
01130             /* Collect data */
01131             int k = 0;
01132             int j, i;
01133             for (j = ylo; j <= yhi; j += ystep) {
01134                 for (i = xlo; i <= xhi; i += xstep) {
01135                     data[k++] = input_data[ (i-1) + (j-1)*nx ];
01136                 }
01137             }
01138         
01139             /* Get median */
01140             smooth_data[ (x-1) + (y-1)*nx ] = 
01141                                fors_tools_get_median_float(data, k);
01142         }
01143     }
01144 
01145     cpl_free(data);
01146     return smooth;
01147 }
01148 
01149 #undef cleanup
01150 #define cleanup \
01151 do { \
01152     cpl_image_delete(input); \
01153 } while(0)
01154 cpl_image *
01155 fors_image_flat_fit_create(fors_image *image, 
01156                            int step, 
01157                            int degree, 
01158                            float level)
01159 {
01160     cpl_image *temp = NULL;
01161     cpl_image *input = NULL;
01162     cpl_image *smooth = NULL;
01163     int nx, ny;
01164 
01165     assure( image != NULL, return smooth, NULL );
01166     passure( image->data != NULL, return smooth );
01167     assure( step > 0, return smooth, NULL );
01168     assure( degree >= 0, return smooth, NULL );
01169 
01170 
01171     temp = image->data;
01172 
01173     nx = cpl_image_get_size_x(temp);
01174     ny = cpl_image_get_size_y(temp);
01175 
01176     /* 
01177      * For efficiency reasons, assume that the image type is float 
01178      */
01179 
01180     assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return smooth, NULL );
01181 
01182     /*
01183      * Apply light median filter, to eliminate big outliers from fit
01184      */
01185 
01186     input = mos_image_filter_median(image->data, 3, 3);
01187 
01188     const float *input_data = cpl_image_get_data_float_const(input);
01189 
01190     /*
01191      * First of all, count how many points will have to be fitted
01192      */
01193 
01194     int x, y, pos;
01195     int count = 0;
01196     for (y = 0; y < ny; y += step) {
01197         pos = y*nx;
01198         for (x = 0; x < nx; x += step, pos += step) {
01199             if (input_data[pos] > level) {
01200                 count++;
01201             }
01202         }
01203     }
01204 
01205     if (count < (degree+1)*(degree+2)) {
01206         step = sqrt((nx*nx)/((degree+1)*(degree+2))) / 2;
01207         if (step == 0)
01208             step = 1;
01209         cpl_msg_error(cpl_func, "Flat field image too small (%dx%d). "
01210                       "Please provide a smaller resampling step (a good "
01211                       "value would be %d)", nx, ny, step);
01212         cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
01213         cleanup;
01214         return NULL;
01215     }
01216 
01217 
01218     /*
01219      * Fill position and flux vectors with appropriate values
01220      */
01221 
01222     cpl_bivector *positions = cpl_bivector_new(count);
01223     double *xpos = cpl_bivector_get_x_data(positions);
01224     double *ypos = cpl_bivector_get_y_data(positions);
01225     cpl_vector *fluxes = cpl_vector_new(count);
01226     double *flux = cpl_vector_get_data(fluxes);
01227 
01228     count = 0;
01229     for (y = 0; y < ny; y += step) {
01230         pos = y*nx;
01231         for (x = 0; x < nx; x += step, pos += step) {
01232             if (input_data[pos] > level) {
01233                 xpos[count] = x;
01234                 ypos[count] = y;
01235                 flux[count] = input_data[pos];
01236                 count++;
01237             }
01238         }
01239     }
01240 
01241     cpl_image_delete(input); input = NULL;
01242 
01243     /*
01244      * Do the fit, and fill the output image with the model
01245      * values in all pixels.
01246      */
01247 
01248     cpl_polynomial *model = cpl_polynomial_fit_2d_create(positions,
01249                                                          fluxes,
01250                                                          degree,
01251                                                          NULL);
01252 
01253     cpl_bivector_delete(positions);
01254     cpl_vector_delete(fluxes);
01255 
01256     smooth = cpl_image_new(nx, ny, FORS_IMAGE_TYPE);
01257     float *smooth_data = cpl_image_get_data_float(smooth);
01258 
01259     cpl_vector *point = cpl_vector_new(2);
01260     double *dpoint = cpl_vector_get_data(point);
01261 
01262     for (y = 0; y < ny; y++) {
01263         pos = y*nx;
01264         dpoint[1] = y;
01265         for (x = 0; x < nx; x++, pos++) {
01266             dpoint[0] = x;
01267             smooth_data[pos] = cpl_polynomial_eval(model, point);
01268         }
01269     }
01270 
01271     cpl_polynomial_delete(model);
01272     cpl_vector_delete(point);
01273 
01274     cleanup;
01275     return smooth;
01276 
01277 }
01278 
01279 #undef cleanup
01280 #define cleanup
01281 
01297 cpl_image *
01298 fors_image_filter_max_create(const fors_image *image, 
01299                              int xradius,
01300                              int yradius,
01301                              bool use_data)
01302 {
01303     const cpl_image *input = NULL;
01304     cpl_image *hmaxima = NULL;
01305     cpl_image *maxima = NULL;
01306     int nx, ny;
01307     
01308     assure( image != NULL, return maxima, NULL );
01309     passure( image->data != NULL, return maxima );
01310     passure( image->variance != NULL, return maxima );
01311     
01312     input = (use_data) ? image->data : image->variance;
01313 
01314     nx = cpl_image_get_size_x(input);
01315     ny = cpl_image_get_size_y(input);
01316 
01317     /*
01318      * Allocate space for horizontal max filter result.
01319      */
01320 
01321     hmaxima = cpl_image_duplicate(input);
01322 
01323     /* For efficiency reasons, assume that the image type is float */
01324     assure( FORS_IMAGE_TYPE == CPL_TYPE_FLOAT, return maxima, NULL );
01325 
01326     float *input_data  = (float *)cpl_image_get_data_float_const(input);
01327     float *maxima_data = cpl_image_get_data_float(hmaxima);
01328 
01329     int y;
01330     for (y = 0; y < ny; y++) {
01331         const float *irow = input_data + y * nx;
01332         float       *orow = maxima_data + y * nx;
01333         max_filter(irow, orow, nx, 2*xradius+1);
01334     }
01335 
01336     cpl_image_turn(hmaxima, 1);
01337 
01338     /*
01339      * Allocate space for vertical max filter result.
01340      */
01341 
01342     maxima = cpl_image_duplicate(hmaxima);
01343     input_data  = cpl_image_get_data_float(hmaxima);
01344     maxima_data = cpl_image_get_data_float(maxima);
01345 
01346     /*
01347      * Now nx is the y size of the rotated image...
01348      */
01349 
01350     int x;
01351     for (x = 0; x < nx; x++) {
01352         const float *irow = input_data + x * ny;
01353         float       *orow = maxima_data + x * ny;
01354         max_filter(irow, orow, ny, 2*yradius+1);
01355     }
01356 
01357     cpl_image_delete(hmaxima);
01358 
01359     cpl_image_turn(maxima, -1);
01360     
01361     return maxima;
01362 }
01363 
01364 #undef cleanup
01365 #define cleanup
01366 
01372 double
01373 fors_image_get_stdev(const fors_image *image, double *dstdev)
01374 {
01375     assure( image != NULL, return 0, NULL );
01376     assure( dstdev == NULL, return 0, "Unsupported");
01377 
01378     return cpl_image_get_stdev(image->data);
01379 }
01380 #undef cleanup
01381 #define cleanup \
01382 do { \
01383     cpl_mask_delete(rejected); \
01384     cpl_image_delete(im); \
01385 } while (0)
01386 
01394 double fors_image_get_stdev_robust(const fors_image *image, 
01395                    double cut,
01396                    double *dstdev)
01397 {
01398     cpl_mask *rejected = NULL;
01399     cpl_image *im = NULL;
01400 
01401     assure( image != NULL, return 0, NULL );
01402     assure( cut > 0, return 0, "Illegal cut: %f", cut );
01403     assure( dstdev == NULL, return 0, "Unsupported");
01404 
01405     double median = fors_image_get_median(image, NULL);
01406 
01407     im = cpl_image_duplicate(image->data);
01408     cpl_image_subtract_scalar(im, median); 
01409     cpl_image_power(im, 2);
01410     /* Now squared residuals wrt median */
01411     
01412     rejected = cpl_mask_threshold_image_create(image->data,
01413                                                median - cut,
01414                                                median + cut);
01415     cpl_mask_not(rejected);
01416     cpl_image_reject_from_mask(im, rejected);
01417 
01418     double robust_stdev = sqrt(cpl_image_get_mean(im));
01419 
01420     cleanup;
01421     return robust_stdev;
01422 }
01423 
01424 #undef cleanup
01425 #define cleanup
01426 
01436 double
01437 fors_image_get_error_mean(const fors_image *image, double *dmean)
01438 {
01439     double avg;
01440 
01441     assure( image != NULL, return 0, NULL );
01442     assure( dmean == NULL, return 0, "Unsupported");
01443 
01444     avg = cpl_image_get_mean(image->variance);
01445 
01446     /* This should never happen, but avoid sqrt of negative value in any case */
01447     assure( avg >= 0, return -1, "Average variance is %f", avg);
01448     
01449     return sqrt(avg);
01450 }
01451 
01452 
01453 #undef cleanup
01454 #define cleanup \
01455 do { \
01456     cpl_imagelist_delete(datlist); \
01457     cpl_imagelist_delete(varlist); \
01458 } while (0)
01459 
01468 fors_image *
01469 fors_image_collapse_create(const fors_image_list *images)
01470 {
01471     cpl_imagelist *datlist = NULL;
01472     cpl_imagelist *varlist = NULL;
01473     cpl_image *data = NULL;
01474     cpl_image *variance = NULL;
01475     const fors_image *i;
01476     int N = 0;
01477     
01478     assure( images != NULL, return NULL, NULL );
01479     assure( fors_image_list_size(images) > 0, return NULL, 
01480             "Cannot stack zero images");
01481 
01482     i = fors_image_list_first_const(images);
01483 
01484     datlist = cpl_imagelist_new();
01485     varlist = cpl_imagelist_new();
01486 
01487     while(i != NULL) {
01488 
01489         /* Append current image to image lists */
01490         cpl_imagelist_set(datlist, 
01491                           cpl_image_duplicate(i->data), 
01492                           cpl_imagelist_get_size(datlist));
01493         cpl_imagelist_set(varlist,
01494                           cpl_image_duplicate(i->variance),
01495                           cpl_imagelist_get_size(varlist));
01496         i = fors_image_list_next_const(images);
01497         N++;
01498     }
01499 
01500 #ifdef CPL_IS_NOT_CRAP
01501     data    = cpl_imagelist_collapse_create(datlist);
01502 
01503     variance = cpl_imagelist_collapse_create(varlist);
01504 #else
01505     data    = fors_imagelist_collapse_create(datlist);
01506 
01507     variance = fors_imagelist_collapse_create(varlist);
01508 #endif
01509 
01510     cpl_image_divide_scalar(variance, N);
01511 
01512     cleanup;
01513     return fors_image_new(data, variance);
01514 }
01515 
01516 
01517 #undef cleanup
01518 #define cleanup \
01519 do { \
01520     cpl_imagelist_delete(datlist); \
01521     cpl_imagelist_delete(varlist); \
01522 } while (0)
01523 
01534 fors_image *
01535 fors_image_collapse_minmax_create(const fors_image_list *images, 
01536                                   int low, int high)
01537 {
01538     cpl_imagelist *datlist = NULL;
01539     cpl_imagelist *varlist = NULL;
01540     cpl_image *data = NULL;
01541     cpl_image *variance = NULL;
01542     const fors_image *i;
01543     int N = 0;
01544     
01545     assure( images != NULL, return NULL, NULL );
01546     assure( fors_image_list_size(images) >  low + high, return NULL, 
01547             "Cannot reject more images than there are");
01548     assure( low*high >= 0 && low+high > 0, return NULL, 
01549             "Invalid minmax rejection criteria");
01550 
01551     i = fors_image_list_first_const(images);
01552 
01553     datlist = cpl_imagelist_new();
01554     varlist = cpl_imagelist_new();
01555 
01556     while(i != NULL) {
01557 
01558         /* Append current image to image lists */
01559         cpl_imagelist_set(datlist, 
01560                           cpl_image_duplicate(i->data), 
01561                           cpl_imagelist_get_size(datlist));
01562         cpl_imagelist_set(varlist,
01563                           cpl_image_duplicate(i->variance),
01564                           cpl_imagelist_get_size(varlist));
01565         i = fors_image_list_next_const(images);
01566         N++;
01567     }
01568 
01569     data     = cpl_imagelist_collapse_minmax_create(datlist, low, high);
01570     variance = cpl_imagelist_collapse_minmax_create(varlist, low, high);
01571 
01572     cpl_image_divide_scalar(variance, N);
01573 
01574     cleanup;
01575     return fors_image_new(data, variance);
01576 }
01577 
01590 fors_image *
01591 fors_image_collapse_ksigma_create(const fors_image_list *images, 
01592                                   int low, int high, int iter)
01593 {
01594     cpl_imagelist *datlist = NULL;
01595     cpl_imagelist *varlist = NULL;
01596     cpl_image *data = NULL;
01597     cpl_image *variance = NULL;
01598     cpl_image *ngood = NULL;
01599     const fors_image *i;
01600     
01601     assure( images != NULL, return NULL, NULL );
01602 
01603     i = fors_image_list_first_const(images);
01604 
01605     datlist = cpl_imagelist_new();
01606     varlist = cpl_imagelist_new();
01607     
01608     while(i != NULL) {
01609 
01610         /* Append current image to image lists */
01611         cpl_imagelist_set(datlist,
01612                           cpl_image_duplicate(i->data),
01613                           cpl_imagelist_get_size(datlist));
01614         cpl_imagelist_set(varlist,
01615                           cpl_image_duplicate(i->variance),
01616                           cpl_imagelist_get_size(varlist));
01617         i = fors_image_list_next_const(images);
01618     }
01619 
01620     data     = mos_ksigma_stack(datlist, low, high, iter, &ngood);
01621     variance = cpl_imagelist_collapse_create(varlist);
01622 
01623     cpl_image_divide(variance, ngood);
01624 
01625     cpl_image_delete(ngood);
01626     cleanup;
01627 
01628     return fors_image_new(data, variance);
01629 }
01630 
01642 fors_image *
01643 fors_image_collapse_median_create(const fors_image_list *images)
01644 {
01645     cpl_imagelist *datlist = NULL;
01646     cpl_imagelist *varlist = NULL;
01647     cpl_image *data = NULL;
01648     cpl_image *variance = NULL;
01649     const fors_image *i;
01650     int N = 0;
01651 
01652     assure( images != NULL, return NULL, NULL );
01653     assure( fors_image_list_size(images) > 0, return NULL, 
01654             "Cannot stack zero images");
01655 
01656     i = fors_image_list_first_const(images);
01657     
01658     datlist = cpl_imagelist_new();
01659     varlist = cpl_imagelist_new();
01660     while(i != NULL) {
01661         /* Append to image lists */
01662         cpl_imagelist_set(datlist, 
01663                           cpl_image_duplicate(i->data), 
01664                           cpl_imagelist_get_size(datlist));
01665         cpl_imagelist_set(varlist,
01666                           cpl_image_duplicate(i->variance),
01667                           cpl_imagelist_get_size(varlist));
01668 
01669         i = fors_image_list_next_const(images);
01670         N++;
01671     }
01672     
01673 #ifdef CPL_IS_NOT_CRAP
01674     data    = cpl_imagelist_collapse_median_create(datlist);
01675 
01676     variance = cpl_imagelist_collapse_create(varlist);
01677 #else
01678     data    = fors_imagelist_collapse_median_create(datlist);
01679 
01680     variance = fors_imagelist_collapse_create(varlist);
01681 #endif
01682 
01683     cpl_image_divide_scalar(variance, N);
01684 
01685     cpl_image_multiply_scalar(variance, 
01686                   fors_utils_median_corr(N) * 
01687                   fors_utils_median_corr(N));
01688     
01689     cleanup;
01690     return fors_image_new(data, variance);
01691 }
01692 
01693 #undef cleanup
01694 #define cleanup
01695 
01712 void fors_image_draw(fors_image *image, int type,
01713              double x, double y,
01714              int radius, double color)
01715 {
01716     assure( image != NULL, return, NULL );
01717 
01718     assure( type == 0 || type == 1 || type == 2,
01719             return , "Unsupported type %d", type);
01720 
01721     assure( radius > 0, return, NULL );
01722 
01723     if (type == 2) {
01724         int i;
01725         for (i = 0; i < 360; i++) {
01726             /* Step size of 1 degree is arbitrary */
01727 
01728             int px = x + radius*cos(i/(2*M_PI));
01729             int py = y + radius*sin(i/(2*M_PI));
01730             
01731             if (1 <= px && px <= cpl_image_get_size_x(image->data) &&
01732                 1 <= py && py <= cpl_image_get_size_y(image->data)) {
01733                 cpl_image_set(image->data, px, py, color);
01734                 cpl_image_set(image->variance, px, py, color > 0 ? color : 0);
01735             }
01736         }
01737     }
01738     else {
01739         int i;
01740 
01741         for (i = -radius; i <= radius; i++) {
01742 
01743             int px, py;
01744             
01745             if (type == 0) {
01746                 px = x + i;
01747                 py = y;
01748             }
01749             else {
01750                 px = x;
01751                 py = y + i;
01752             }
01753             
01754             if (1 <= px && px <= cpl_image_get_size_x(image->data) &&
01755                 1 <= py && py <= cpl_image_get_size_y(image->data)) {
01756                 cpl_image_set(image->data    , px, py, color);
01757                 cpl_image_set(image->variance, px, py, color > 0 ? color : 0);
01758             }
01759         }
01760     }
01761 
01762     return;
01763 }
01764 
01765 hdrl_imagelist * fors_image_list_to_hdrl(const fors_image_list * imalist)
01766 {
01767     int i;
01768     hdrl_imagelist * images_hdrl = hdrl_imagelist_new();
01769     const fors_image * target = fors_image_list_first_const(imalist);
01770     for(i = 0 ; i < fors_image_list_size(imalist); ++i)
01771     {
01772         const cpl_image * ima_data  = target->data;
01773         cpl_image * ima_error = cpl_image_power_create(target->variance, 0.5);
01774         cpl_mask * old_bpm = cpl_image_set_bpm(ima_error, 
01775                                cpl_mask_duplicate(cpl_image_get_bpm_const(ima_data)));
01776         cpl_mask_delete(old_bpm);
01777         hdrl_image * ima_hdrl = hdrl_image_create(ima_data, ima_error);
01778         hdrl_imagelist_set(images_hdrl, ima_hdrl, 
01779                            hdrl_imagelist_get_size(images_hdrl));
01780         target = fors_image_list_next_const(imalist);
01781         cpl_image_delete(ima_error);
01782     }
01783     
01784     return images_hdrl;
01785 }
01786 
01787 fors_image * fors_image_from_hdrl(const hdrl_image * image)
01788 {
01789     const cpl_image * data = hdrl_image_get_image_const(image);
01790     cpl_image * variance = cpl_image_power_create
01791             (hdrl_image_get_error_const(image), 2);
01792     fors_image * ima = fors_image_new(cpl_image_duplicate(data), variance);
01793     return ima;
01794 }
01795 
01796 
01797 #define LIST_DEFINE
01798 #undef LIST_ELEM
01799 #define LIST_ELEM fors_image
01800 #include <list.h>
01801 

Generated on 12 Feb 2016 for FORS Pipeline Reference Manual by  doxygen 1.6.1