irplib_slitpos.c

00001 /* $Id: irplib_slitpos.c,v 1.18 2007/09/20 11:14:36 llundin Exp $
00002  *
00003  * This file is part of the irplib package
00004  * Copyright (C) 2002,2003 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  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: llundin $
00023  * $Date: 2007/09/20 11:14:36 $
00024  * $Revision: 1.18 $
00025  * $Name: uves-3_9_0 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /* The IRPLIB-based application may have checked for the availability of
00033    memrchr() in which case the macro HAVE_DECL_MEMRCHR is defined as either
00034    0 or 1. Without checks it is assumed that the function is not available.
00035    With a suitable version of autoconf the macro can be defined with this
00036    entry in configure.ac:
00037    AC_CHECK_DECLS([memrchr])
00038 */
00039 
00040 /*-----------------------------------------------------------------------------
00041                                 Includes
00042  -----------------------------------------------------------------------------*/
00043 
00044 #include <string.h>
00045 #include <math.h>
00046 #include <assert.h>
00047 #include <cpl.h>
00048 
00049 #include "irplib_slitpos.h"
00050 #include "irplib_flat.h"
00051 
00052 /*-----------------------------------------------------------------------------
00053                                 Defines
00054  -----------------------------------------------------------------------------*/
00055 
00056 #ifndef IRPLIB_SLITPOS_KERNEL_SIZE_Y
00057 #define IRPLIB_SLITPOS_KERNEL_SIZE_Y      5
00058 #endif
00059 
00060 #ifndef IRPLIB_SLITPOS_MAX_EROSION
00061 #define IRPLIB_SLITPOS_MAX_EROSION     1024
00062 #endif
00063 
00064 /*-----------------------------------------------------------------------------
00065                             Functions prototypes
00066  -----------------------------------------------------------------------------*/
00067 
00068 static cpl_error_code irplib_slitpos_find_edges_one_line(const cpl_image *,
00069                                                          int, int *, int *);
00070 static cpl_error_code irplib_slitpos_find_vert_slit_ends(const cpl_image *,
00071                                                          int, int *, int *);
00072 static cpl_error_code irplib_slitpos_find_vert_pos(const cpl_image *, int,
00073                                                    int *);
00074 
00075 /*----------------------------------------------------------------------------*/
00079 /*----------------------------------------------------------------------------*/
00080 
00082 /*----------------------------------------------------------------------------*/
00108 /*----------------------------------------------------------------------------*/
00109 cpl_table * irplib_slitpos_analysis(const cpl_image * imslit,
00110                                     int               slit_max_width,
00111                                     double          * slit_flux)
00112 {
00113     const int       slit_size = cpl_image_get_size_y(imslit);
00114     int             slit_length;
00115     int             slit_pos;
00116     cpl_image   *   filtered;
00117     cpl_matrix  *   kernel;
00118     cpl_image   *   thin_im;
00119     int             slit_top_y = 0; /* Avoid (false) uninit warning */
00120     int             slit_bot_y = 0; /* Avoid (false) uninit warning */
00121     cpl_table   *   self;
00122     double      *   slit_y,
00123                 *   slit_x_l,
00124                 *   slit_x_r;
00125     double      *   coeff_r;
00126     double      *   coeff_l;
00127     int             i;
00128     cpl_error_code error = CPL_ERROR_NONE;
00129 
00130     /* Initialize */
00131     if (slit_flux != NULL) *slit_flux = 0.0 ;
00132     
00133     /* Filter the input image to 'erase' the bad pixels */
00134     kernel = cpl_matrix_new(3, 3);
00135     cpl_ensure(!cpl_matrix_fill(kernel, 1.0), cpl_error_get_code(), NULL);
00136 
00137     filtered = cpl_image_filter_median(imslit, kernel);
00138     cpl_matrix_delete(kernel);
00139 
00140     if (filtered == NULL) {
00141         cpl_msg_error(cpl_func, "Could not filter the image");
00142         cpl_ensure(0, cpl_error_get_code(), NULL);
00143     }
00144 
00145     /* Find the position of the slit */
00146     if (irplib_slitpos_find_vert_pos(filtered, slit_max_width/2, &slit_pos)) {
00147         cpl_image_delete(filtered);
00148         cpl_msg_error(cpl_func, "Could not find the slit position");
00149         cpl_ensure(0, cpl_error_get_code(), NULL);
00150     }
00151 
00152     /* Extract a thin image containing the slit */
00153     if ((thin_im = cpl_image_extract(filtered,
00154                                      slit_pos-slit_max_width/2,
00155                                      1,
00156                                      slit_pos+slit_max_width/2,
00157                                      slit_size)) == NULL) {
00158         cpl_msg_error(cpl_func, "Could not extract the %d pixel thin image "
00159                       "around position %d", slit_max_width, slit_pos);
00160         cpl_image_delete(filtered);
00161         cpl_ensure(0, cpl_error_get_code(), NULL);
00162     }
00163 
00164     /* Find the ends of the slit */
00165     if ((irplib_slitpos_find_vert_slit_ends(thin_im,
00166                                             IRPLIB_SLITPOS_KERNEL_SIZE_Y,
00167                                             &slit_bot_y,
00168                                             &slit_top_y))) {
00169         cpl_msg_error(cpl_func, "Could not find the ends of the slit at %s",
00170                       cpl_error_get_where());
00171         cpl_image_delete(filtered);
00172         cpl_image_delete(thin_im);
00173         cpl_ensure(0, cpl_error_get_code(), NULL);
00174     }
00175     cpl_image_delete(thin_im);
00176 
00177     /* Extract an image with exactly the slit */
00178     thin_im = cpl_image_extract(filtered,
00179                                 slit_pos-slit_max_width/2,
00180                                 slit_bot_y,
00181                                 slit_pos+slit_max_width/2,
00182                                 slit_top_y);
00183     cpl_image_delete(filtered);
00184 
00185     if (thin_im == NULL) {
00186         cpl_msg_error(cpl_func, "Could not extract the thin image from %d to %d",
00187                       slit_bot_y, slit_top_y);
00188         cpl_ensure(0, cpl_error_get_code(), NULL);
00189     }
00190 
00191     slit_length = 1 + slit_top_y - slit_bot_y;
00192 
00193     /* Allocate some arrays */
00194     slit_y = cpl_malloc(slit_length * sizeof(double));
00195     slit_x_l = cpl_malloc(slit_length * sizeof(double));
00196     slit_x_r = cpl_malloc(slit_length * sizeof(double));
00197     
00198     /* Find the edges of the slit */
00199     for (i=0 ; i<slit_length ; i++) {
00200         int right_pos = 0; /* Avoid (false) uninit warning */
00201         int left_pos  = 0; /* Avoid (false) uninit warning */
00202 
00203         if (irplib_slitpos_find_edges_one_line(thin_im,
00204                                                 i,
00205                                                 &left_pos,
00206                                                 &right_pos)) {
00207             cpl_msg_error(cpl_func, "cannot find the edges of the [%d]th line", 
00208                     i+1);
00209             cpl_image_delete(thin_im);
00210             return NULL;
00211         }
00212 
00213         /* Update the slit_flux */
00214         if (slit_flux != NULL) {
00215             *slit_flux += cpl_image_get_flux_window(thin_im, left_pos+1,
00216                     i+1, right_pos+1, i+1) ;
00217         }
00218         
00219         /* Store the edges for the fit */
00220         slit_x_l[i] = (double)left_pos;
00221         slit_x_r[i] = (double)right_pos;
00222         slit_y[i]   = (double)(i+slit_bot_y-1);
00223     }
00224     cpl_image_delete(thin_im);
00225 
00226     /* Linear regression to find the edges */
00227     coeff_l = irplib_flat_fit_slope_robust(slit_y, slit_x_l, slit_length);
00228     coeff_r = irplib_flat_fit_slope_robust(slit_y, slit_x_r, slit_length);
00229     cpl_free(slit_y);
00230     cpl_free(slit_x_l);
00231     cpl_free(slit_x_r);
00232 
00233     /* Allocate the table containing the results */
00234     self = cpl_table_new(slit_length);
00235     error |= cpl_table_new_column(self, "SLIT_Y",      CPL_TYPE_INT);
00236     error |= cpl_table_new_column(self, "SLIT_LEFT",   CPL_TYPE_DOUBLE);
00237     error |= cpl_table_new_column(self, "SLIT_CENTER", CPL_TYPE_DOUBLE);
00238     error |= cpl_table_new_column(self, "SLIT_RIGHT",  CPL_TYPE_DOUBLE);
00239 
00240     error |= cpl_table_set_column_unit(self, "SLIT_Y", "pixel");
00241     error |= cpl_table_set_column_unit(self, "SLIT_LEFT", "pixel");
00242     error |= cpl_table_set_column_unit(self, "SLIT_CENTER", "pixel");
00243     error |= cpl_table_set_column_unit(self, "SLIT_RIGHT", "pixel");
00244 
00245     cpl_ensure(!error, cpl_error_get_code(), NULL);
00246 
00247     /* Rewrite the edges in the out table, and write the center */
00248     for (i=0 ; i < slit_length ; i++) {
00249         const int    islity = i + slit_bot_y;
00250         const double dslit  = slit_pos - slit_max_width / 2.0;
00251         const double dleft  = coeff_l[0] + coeff_l[1] * (double)islity + dslit;
00252         const double dright = coeff_r[0] + coeff_r[1] * (double)islity + dslit;
00253         const double dcent  = 0.5 * (dleft + dright);
00254 
00255         if (cpl_table_set_int(self,    "SLIT_Y",      i, islity)) break;
00256         if (cpl_table_set_double(self, "SLIT_LEFT",   i, dleft))  break;
00257         if (cpl_table_set_double(self, "SLIT_RIGHT",  i, dright)) break;
00258         if (cpl_table_set_double(self, "SLIT_CENTER", i, dcent))  break;
00259     }
00260 
00261     cpl_free(coeff_r);
00262     cpl_free(coeff_l);
00263 
00264     if (i != slit_length) {
00265         cpl_table_delete(self);
00266         cpl_ensure(0, cpl_error_get_code(), NULL);
00267     }
00268 
00269     return self;
00270 }
00271 
00274 /*----------------------------------------------------------------------------*/
00286 /*----------------------------------------------------------------------------*/
00287 static cpl_error_code irplib_slitpos_find_edges_one_line(const cpl_image * self,
00288                                                          int          line_pos,
00289                                                          int        * left_pos,
00290                                                          int        * right_pos)
00291 {
00292     const int     size_x = cpl_image_get_size_x(self);
00293     const float * pself;
00294     double        threshold;
00295     int           i;
00296 
00297     cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00298     cpl_ensure_code(cpl_image_get_type(self) == CPL_TYPE_FLOAT,
00299                     CPL_ERROR_INVALID_TYPE);
00300 
00301     pself = cpl_image_get_data_float_const(self);
00302 
00303     /* Find the threshold */
00304     threshold = cpl_image_get_mean_window(self, 1, line_pos+1, size_x,
00305                                           line_pos+1);
00306 
00307     /* Detect the left edge */
00308     i = 0;
00309     while (i < size_x && pself[line_pos*size_x+i] < threshold) i++;
00310     *left_pos = i;
00311 
00312     /* Detect the right edge */
00313     i = size_x - 1;
00314     while (i >= 0 && pself[line_pos*size_x+i] < threshold) i--;
00315     *right_pos = i;
00316 
00317     return CPL_ERROR_NONE;
00318 }
00319 
00320 /*----------------------------------------------------------------------------*/
00331 /*----------------------------------------------------------------------------*/
00332 static cpl_error_code irplib_slitpos_find_vert_slit_ends(const cpl_image * self,
00333                                                          int        kernel_size,
00334                                                          int      * bot_slit_y,
00335                                                          int      * top_slit_y)
00336 {
00337     cpl_mask         * binary;
00338     cpl_matrix       * kernel;
00339     cpl_image        * label_image;
00340     int                nobj, erosions_nb;
00341     const int          size_x = cpl_image_get_size_x(self);
00342     const int          npix = size_x * cpl_image_get_size_y(self);
00343     const cpl_binary * pbinary;
00344     const cpl_binary * pfind;
00345     int                i, itop, ibot;
00346 
00347 
00348     cpl_ensure_code(size_x > 0, cpl_error_get_code());
00349 
00350     /* Threshold to have a binary image */
00351     binary = cpl_mask_threshold_image_create(self, cpl_image_get_mean(self),
00352                                              cpl_image_get_max(self));
00353     cpl_ensure_code(binary != NULL, cpl_error_get_code());
00354 
00355     /* Define the kernel for morpho operations */
00356     kernel = cpl_matrix_new(kernel_size, 1);
00357 
00358     /* Erode until there is 1 object left in the image */
00359     label_image = cpl_image_labelise_mask_create(binary, &nobj);
00360     cpl_image_delete(label_image);
00361 
00362     if (label_image == NULL || kernel == NULL || cpl_matrix_fill(kernel, 1.0)) {
00363         cpl_mask_delete(binary);
00364         cpl_matrix_delete(kernel);
00365         cpl_ensure_code(0, cpl_error_get_code());
00366     }
00367 
00368     for (erosions_nb = 0; erosions_nb < IRPLIB_SLITPOS_MAX_EROSION && nobj > 1;
00369          erosions_nb++) {
00370 
00371         /* Should not be possible to break from this loop */
00372         if (cpl_mask_erosion(binary, kernel)) break;
00373 
00374         label_image = cpl_image_labelise_mask_create(binary, &nobj);
00375         if (label_image == NULL) break; /* Assuming nobj was not set to 1 */
00376         cpl_image_delete(label_image);
00377     }
00378 
00379     if (nobj > 1) {
00380         cpl_mask_delete(binary);
00381         cpl_matrix_delete(kernel);
00382         if (erosions_nb >= IRPLIB_SLITPOS_MAX_EROSION) {
00383             cpl_msg_error(cpl_func, "Number of erosions reached a limit of %d "
00384                           "with %d possible slits left",
00385                           IRPLIB_SLITPOS_MAX_EROSION, nobj);
00386             cpl_ensure_code(0, CPL_ERROR_CONTINUE);
00387         }
00388         cpl_ensure_code(0, cpl_error_get_code());
00389     } else if (nobj < 1) {
00390         cpl_mask_delete(binary);
00391         cpl_matrix_delete(kernel);
00392         if (erosions_nb == 0)
00393             cpl_msg_error(cpl_func, "No slit could be detected across %d "
00394                           "pixels", size_x);
00395         else 
00396             cpl_msg_error(cpl_func, "The last of %d erosions removed all the "
00397                           "possible slits", erosions_nb);
00398         cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
00399     }
00400 
00401     /* Reconstruct the slit with dilations */
00402     for (i=0 ; i < erosions_nb ; i++) {
00403         if (cpl_mask_dilation(binary, kernel)) break;
00404     }
00405     cpl_matrix_delete(kernel);
00406 
00407     if (i != erosions_nb) {
00408         cpl_msg_error(cpl_func, "Dilation number %d out of %d failed",
00409                       i, erosions_nb);
00410         cpl_mask_delete(binary);
00411         cpl_ensure_code(0, cpl_error_get_code());
00412     }
00413 
00414     /* Find the ends of the slit */
00415     pbinary = cpl_mask_get_data(binary);
00416     assert( pbinary != NULL );
00417 
00418     pfind = memchr(pbinary, CPL_BINARY_1, (size_t)npix);
00419     assert( pfind != NULL );
00420 
00421     ibot = (int)(pfind - pbinary);
00422 
00423 #if defined HAVE_DECL_MEMRCHR && HAVE_DECL_MEMRCHR == 1
00424     /* FIXME: Not tested */
00425     pfind = memrchr(pfind, CPL_BINARY_1, (size_t)(npix - ibot));
00426     assert( pfind != NULL );
00427 
00428     itop = (int)(pfind - pbinary);
00429 #else
00430 
00431     itop = npix - 1;
00432     while (itop > ibot && pbinary[itop] != CPL_BINARY_1) itop--;
00433 
00434 #endif
00435 
00436     *bot_slit_y = 1 + ibot / size_x;
00437     *top_slit_y = 1 + itop / size_x;
00438 
00439     cpl_msg_info(cpl_func, "Detected %d-pixel slit from pixel %d to %d "
00440                  "using %d erosions/dilations", cpl_mask_count(binary),
00441                  *bot_slit_y, *top_slit_y, erosions_nb);
00442 
00443     cpl_mask_delete(binary);
00444 
00445     /* Should really be an assert() */
00446     cpl_ensure_code(ibot <= itop, CPL_ERROR_DATA_NOT_FOUND);
00447 
00448     return CPL_ERROR_NONE;
00449 }
00450 
00451 /*----------------------------------------------------------------------------*/
00461 /*----------------------------------------------------------------------------*/
00462 static cpl_error_code irplib_slitpos_find_vert_pos(const cpl_image * self,
00463                                                    int               xwidth,
00464                                                    int             * slit_pos)
00465 {
00466     const int      size_x = cpl_image_get_size_x(self);
00467     cpl_image    * image1D;
00468     int            yone;
00469     cpl_error_code error;
00470 
00471 
00472     /* Collapse the image to a horizontal 1D image */
00473     image1D = cpl_image_collapse_create(self, 0);
00474 
00475     cpl_ensure_code(image1D != NULL, cpl_error_get_code());
00476 
00477     /* Search the max of the 1D image to identify the slit position */
00478     error = cpl_image_get_maxpos_window(image1D, 1+xwidth, 1, size_x-xwidth,
00479                                         1, slit_pos, &yone);
00480 
00481     cpl_image_delete(image1D);
00482 
00483     cpl_ensure_code(!error, error);
00484 
00485     return CPL_ERROR_NONE;
00486 }

Generated on Fri Apr 18 14:11:41 2008 for UVES Pipeline Reference Manual by  doxygen 1.5.1