irplib_slitpos.c

00001 /* $Id: irplib_slitpos.c,v 1.26 2010/05/05 16:02:24 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: 2010/05/05 16:02:24 $
00024  * $Revision: 1.26 $
00025  * $Name: uves-4_9_1 $
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 #include "irplib_filter.h"
00052 
00053 /*-----------------------------------------------------------------------------
00054                                 Defines
00055  -----------------------------------------------------------------------------*/
00056 
00057 #ifndef IRPLIB_SLITPOS_KERNEL_SIZE_Y
00058 #define IRPLIB_SLITPOS_KERNEL_SIZE_Y      5
00059 #endif
00060 
00061 #ifndef IRPLIB_SLITPOS_MAX_EROSION
00062 #define IRPLIB_SLITPOS_MAX_EROSION     1024
00063 #endif
00064 
00065 /*-----------------------------------------------------------------------------
00066                             Functions prototypes
00067  -----------------------------------------------------------------------------*/
00068 
00069 static cpl_error_code irplib_slitpos_find_edges_one_line(const cpl_image *,
00070                                                          int, int *, int *);
00071 static cpl_error_code irplib_slitpos_find_vert_slit_ends(const cpl_image *,
00072                                                          int, int *, int *);
00073 static cpl_error_code irplib_slitpos_find_vert_pos(const cpl_image *, int,
00074                                                    int *);
00075 
00076 /*----------------------------------------------------------------------------*/
00080 /*----------------------------------------------------------------------------*/
00081 
00083 /*----------------------------------------------------------------------------*/
00109 /*----------------------------------------------------------------------------*/
00110 cpl_table * irplib_slitpos_analysis(const cpl_image * imslit,
00111                                     int               slit_max_width,
00112                                     double          * slit_flux)
00113 {
00114     const int       size_x = cpl_image_get_size_x(imslit);
00115     const int       size_y = cpl_image_get_size_y(imslit);
00116     int             slit_length;
00117     int             slit_pos;
00118     cpl_image   *   filtered;
00119     cpl_mask    *   mask;
00120     cpl_image   *   thin_im;
00121     int             slit_top_y = 0; /* Avoid (false) uninit warning */
00122     int             slit_bot_y = 0; /* Avoid (false) uninit warning */
00123     cpl_table   *   self;
00124     double      *   slit_y,
00125                 *   slit_x_l,
00126                 *   slit_x_r;
00127     double      *   coeff_r;
00128     double      *   coeff_l;
00129     int             i;
00130     cpl_error_code error = CPL_ERROR_NONE;
00131 
00132     /* Initialize */
00133     if (slit_flux != NULL) *slit_flux = 0.0 ;
00134 
00135     /* Median vertical filtering 3x3 */
00136     mask = cpl_mask_new(3, 3) ;
00137     cpl_mask_not(mask) ;
00138     filtered = cpl_image_new(size_x, size_y, cpl_image_get_type(imslit));
00139     error = cpl_image_filter_mask(filtered, imslit, mask,
00140                                   CPL_FILTER_MEDIAN, CPL_BORDER_FILTER);
00141     cpl_mask_delete(mask);
00142 
00143     if (error) {
00144         cpl_image_delete(filtered);
00145         cpl_ensure(0, cpl_error_get_code(), NULL);
00146     }
00147 
00148     /* The background may vary strongly along the vertical line. */
00149     /* Detect and remove background with a 1+2*Slit_max x 1 median filter */
00150     error = irplib_image_filter_background_line(filtered, NULL, slit_max_width,
00151                                                 CPL_TRUE);
00152 
00153     if (error) {
00154         cpl_image_delete(filtered) ;
00155         cpl_ensure(0, cpl_error_get_code(), NULL);
00156     }
00157 
00158     /* Find the position of the slit */
00159     if (irplib_slitpos_find_vert_pos(filtered, slit_max_width/2, &slit_pos)) {
00160         cpl_image_delete(filtered);
00161         cpl_msg_error(cpl_func, "Could not find the slit position");
00162         cpl_ensure(0, cpl_error_get_code(), NULL);
00163     }
00164 
00165     /* Extract a thin image containing the slit */
00166     thin_im = cpl_image_extract(filtered, slit_pos-slit_max_width/2, 1,
00167                                 slit_pos+slit_max_width/2, size_y);
00168     if (thin_im == NULL) {
00169         cpl_msg_error(cpl_func, "Could not extract the %d pixel thin image "
00170                       "around position %d", slit_max_width, slit_pos);
00171         cpl_image_delete(filtered);
00172         cpl_ensure(0, cpl_error_get_code(), NULL);
00173     }
00174 
00175     /* Find the ends of the slit */
00176     error = irplib_slitpos_find_vert_slit_ends(thin_im,
00177                                                IRPLIB_SLITPOS_KERNEL_SIZE_Y,
00178                                                &slit_bot_y,
00179                                                &slit_top_y);
00180     cpl_image_delete(thin_im);
00181     if (error) {
00182         cpl_image_delete(filtered);
00183         cpl_ensure(0, cpl_error_get_code(), NULL);
00184     }
00185 
00186     /* Extract an image with exactly the slit */
00187     thin_im = cpl_image_extract(filtered,
00188                                 slit_pos-slit_max_width/2,
00189                                 slit_bot_y,
00190                                 slit_pos+slit_max_width/2,
00191                                 slit_top_y);
00192     cpl_image_delete(filtered);
00193 
00194     cpl_ensure(thin_im != NULL, cpl_error_get_code(), NULL);
00195 
00196     slit_length = 1 + slit_top_y - slit_bot_y;
00197 
00198     /* Allocate some arrays */
00199     slit_y = cpl_malloc(slit_length * sizeof(double));
00200     slit_x_l = cpl_malloc(slit_length * sizeof(double));
00201     slit_x_r = cpl_malloc(slit_length * sizeof(double));
00202     
00203     /* Find the edges of the slit */
00204     for (i=0 ; i<slit_length ; i++) {
00205         int right_pos = 0; /* Avoid (false) uninit warning */
00206         int left_pos  = 0; /* Avoid (false) uninit warning */
00207 
00208         if (irplib_slitpos_find_edges_one_line(thin_im,
00209                                                 i,
00210                                                 &left_pos,
00211                                                 &right_pos)) {
00212             cpl_msg_error(cpl_func, "cannot find the edges of the [%d]th line", 
00213                     i+1);
00214             cpl_image_delete(thin_im);
00215             return NULL;
00216         }
00217 
00218         /* Update the slit_flux */
00219         if (slit_flux != NULL) {
00220             *slit_flux += cpl_image_get_flux_window(thin_im, left_pos+1,
00221                     i+1, right_pos+1, i+1) ;
00222         }
00223         
00224         /* Store the edges for the fit */
00225         slit_x_l[i] = (double)left_pos;
00226         slit_x_r[i] = (double)right_pos;
00227         slit_y[i]   = (double)(i+slit_bot_y-1);
00228     }
00229     cpl_image_delete(thin_im);
00230 
00231     /* Linear regression to find the edges */
00232     coeff_l = irplib_flat_fit_slope_robust(slit_y, slit_x_l, slit_length);
00233     coeff_r = irplib_flat_fit_slope_robust(slit_y, slit_x_r, slit_length);
00234     cpl_free(slit_y);
00235     cpl_free(slit_x_l);
00236     cpl_free(slit_x_r);
00237 
00238     /* Allocate the table containing the results */
00239     self = cpl_table_new(slit_length);
00240     error |= cpl_table_new_column(self, "SLIT_Y",      CPL_TYPE_INT);
00241     error |= cpl_table_new_column(self, "SLIT_LEFT",   CPL_TYPE_DOUBLE);
00242     error |= cpl_table_new_column(self, "SLIT_CENTER", CPL_TYPE_DOUBLE);
00243     error |= cpl_table_new_column(self, "SLIT_RIGHT",  CPL_TYPE_DOUBLE);
00244 
00245     error |= cpl_table_set_column_unit(self, "SLIT_Y", "pixel");
00246     error |= cpl_table_set_column_unit(self, "SLIT_LEFT", "pixel");
00247     error |= cpl_table_set_column_unit(self, "SLIT_CENTER", "pixel");
00248     error |= cpl_table_set_column_unit(self, "SLIT_RIGHT", "pixel");
00249 
00250     cpl_ensure(!error, cpl_error_get_code(), NULL);
00251 
00252     /* Rewrite the edges in the out table, and write the center */
00253     for (i=0 ; i < slit_length ; i++) {
00254         const int    islity = i + slit_bot_y;
00255         const double dslit  = slit_pos - slit_max_width / 2.0;
00256         const double dleft  = coeff_l[0] + coeff_l[1] * (double)islity + dslit;
00257         const double dright = coeff_r[0] + coeff_r[1] * (double)islity + dslit;
00258         const double dcent  = 0.5 * (dleft + dright);
00259 
00260         if (cpl_table_set_int(self,    "SLIT_Y",      i, islity)) break;
00261         if (cpl_table_set_double(self, "SLIT_LEFT",   i, dleft))  break;
00262         if (cpl_table_set_double(self, "SLIT_RIGHT",  i, dright)) break;
00263         if (cpl_table_set_double(self, "SLIT_CENTER", i, dcent))  break;
00264     }
00265 
00266     cpl_free(coeff_r);
00267     cpl_free(coeff_l);
00268 
00269     if (i != slit_length) {
00270         cpl_table_delete(self);
00271         cpl_ensure(0, cpl_error_get_code(), NULL);
00272     }
00273 
00274     return self;
00275 }
00276 
00279 /*----------------------------------------------------------------------------*/
00291 /*----------------------------------------------------------------------------*/
00292 static cpl_error_code irplib_slitpos_find_edges_one_line(const cpl_image * self,
00293                                                          int          line_pos,
00294                                                          int        * left_pos,
00295                                                          int        * right_pos)
00296 {
00297     const int     size_x = cpl_image_get_size_x(self);
00298     const float * pself;
00299     double        threshold;
00300     int           i;
00301 
00302     cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00303     cpl_ensure_code(cpl_image_get_type(self) == CPL_TYPE_FLOAT,
00304                     CPL_ERROR_INVALID_TYPE);
00305 
00306     pself = cpl_image_get_data_float_const(self);
00307 
00308     /* Find the threshold */
00309     threshold = cpl_image_get_mean_window(self, 1, line_pos+1, size_x,
00310                                           line_pos+1);
00311 
00312     /* Detect the left edge */
00313     i = 0;
00314     while (i < size_x && pself[line_pos*size_x+i] < threshold) i++;
00315     *left_pos = i;
00316 
00317     /* Detect the right edge */
00318     i = size_x - 1;
00319     while (i >= 0 && pself[line_pos*size_x+i] < threshold) i--;
00320     *right_pos = i;
00321 
00322     return CPL_ERROR_NONE;
00323 }
00324 
00325 /*----------------------------------------------------------------------------*/
00336 /*----------------------------------------------------------------------------*/
00337 static
00338 cpl_error_code irplib_slitpos_find_vert_slit_ends(const cpl_image * self,
00339                                                   int        kernel_size,
00340                                                   int      * bot_slit_y,
00341                                                   int      * top_slit_y)
00342 {
00343     cpl_mask         * binary;
00344 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(5, 2, 0)
00345     cpl_mask         * copy = NULL;
00346     cpl_mask         * kernel;
00347 #else
00348     cpl_matrix       * kernel;
00349 #endif
00350     cpl_image        * label_image;
00351     int                nobj, erosions_nb;
00352     const int          size_x = cpl_image_get_size_x(self);
00353     const int          size_y = cpl_image_get_size_y(self);
00354     const int          npix = size_x * size_y;
00355     const cpl_binary * pbinary;
00356     const cpl_binary * pfind;
00357     int                i, itop, ibot;
00358 
00359 
00360     cpl_ensure_code(size_x      > 0, cpl_error_get_code());
00361     cpl_ensure_code(kernel_size > 0, cpl_error_get_code());
00362 
00363     /* Threshold to have a binary image */
00364     binary = cpl_mask_threshold_image_create(self, cpl_image_get_mean(self),
00365                                              cpl_image_get_max(self));
00366     cpl_ensure_code(binary != NULL, cpl_error_get_code());
00367 
00368     /* Erode until there is 1 object left in the image */
00369     label_image = cpl_image_labelise_mask_create(binary, &nobj);
00370     cpl_image_delete(label_image);
00371 
00372     if (label_image == NULL) {
00373         cpl_mask_delete(binary);
00374         cpl_ensure_code(0, cpl_error_get_code());
00375     }
00376 
00377     /* Define the kernel for morpho operations */
00378 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(5, 2, 0)
00379     kernel = cpl_mask_new(kernel_size, 1);
00380     cpl_mask_not(kernel);
00381     copy = cpl_mask_wrap(size_x, size_y, cpl_malloc(size_x * size_y *
00382                                                     sizeof(cpl_binary)));
00383 #else
00384     kernel = cpl_matrix_new(kernel_size, 1);
00385     cpl_matrix_fill(kernel, 1.0);
00386 #endif
00387 
00388     for (erosions_nb = 0; erosions_nb < IRPLIB_SLITPOS_MAX_EROSION && nobj > 1;
00389          erosions_nb++) {
00390         /* Should not be possible to break from this loop */
00391 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(5, 2, 0)
00392         cpl_mask_copy(copy, binary, 1, 1);
00393         if (cpl_mask_filter(binary, copy, kernel, CPL_FILTER_EROSION,
00394                             CPL_BORDER_ZERO)) break;
00395 #else
00396         if (cpl_mask_erosion(binary, kernel)) break;
00397 #endif
00398 
00399         label_image = cpl_image_labelise_mask_create(binary, &nobj);
00400         if (label_image == NULL) break; /* Assuming nobj was not set to 1 */
00401         cpl_image_delete(label_image);
00402     }
00403 
00404     if (nobj > 1) {
00405         cpl_mask_delete(binary);
00406 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(5, 2, 0)
00407         cpl_mask_delete(copy);
00408         cpl_mask_delete(kernel);
00409 #else
00410         cpl_matrix_delete(kernel);
00411 #endif
00412         if (erosions_nb >= IRPLIB_SLITPOS_MAX_EROSION) {
00413             cpl_msg_error(cpl_func, "Number of erosions reached a limit of %d "
00414                           "with %d possible slits left",
00415                           IRPLIB_SLITPOS_MAX_EROSION, nobj);
00416             cpl_ensure_code(0, CPL_ERROR_CONTINUE);
00417         }
00418         cpl_ensure_code(0, cpl_error_get_code());
00419     } else if (nobj < 1) {
00420         cpl_mask_delete(binary);
00421 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(5, 2, 0)
00422         cpl_mask_delete(copy);
00423         cpl_mask_delete(kernel);
00424 #else
00425         cpl_matrix_delete(kernel);
00426 #endif
00427         if (erosions_nb == 0)
00428             cpl_msg_error(cpl_func, "No slit could be detected across %d "
00429                           "pixels", size_x);
00430         else 
00431             cpl_msg_error(cpl_func, "The last of %d erosions removed all the "
00432                           "possible slits", erosions_nb);
00433         cpl_ensure_code(0, CPL_ERROR_DATA_NOT_FOUND);
00434     }
00435 
00436     /* Reconstruct the slit with dilations */
00437     for (i=0 ; i < erosions_nb ; i++) {
00438 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(5, 2, 0)
00439         cpl_mask_copy(copy, binary, 1, 1);
00440         if (cpl_mask_filter(binary, copy, kernel, CPL_FILTER_DILATION,
00441                             CPL_BORDER_ZERO)) break;
00442 #else
00443         if (cpl_mask_dilation(binary, kernel)) break;
00444 #endif
00445     }
00446 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(5, 2, 0)
00447     cpl_mask_delete(copy);
00448     cpl_mask_delete(kernel);
00449 #else
00450     cpl_matrix_delete(kernel);
00451 #endif
00452 
00453     if (i != erosions_nb) {
00454         cpl_msg_error(cpl_func, "Dilation number %d out of %d failed",
00455                       i, erosions_nb);
00456         cpl_mask_delete(binary);
00457         cpl_ensure_code(0, cpl_error_get_code());
00458     }
00459 
00460     /* Find the ends of the slit */
00461     pbinary = cpl_mask_get_data(binary);
00462     assert( pbinary != NULL );
00463 
00464     pfind = memchr(pbinary, CPL_BINARY_1, (size_t)npix);
00465     assert( pfind != NULL );
00466 
00467     ibot = (int)(pfind - pbinary);
00468 
00469 #if defined HAVE_DECL_MEMRCHR && HAVE_DECL_MEMRCHR == 1
00470     /* FIXME: Not tested */
00471     pfind = memrchr(pfind, CPL_BINARY_1, (size_t)(npix - ibot));
00472     assert( pfind != NULL );
00473 
00474     itop = (int)(pfind - pbinary);
00475 #else
00476 
00477     itop = npix - 1;
00478     while (itop > ibot && pbinary[itop] != CPL_BINARY_1) itop--;
00479 
00480 #endif
00481 
00482     *bot_slit_y = 1 + ibot / size_x;
00483     *top_slit_y = 1 + itop / size_x;
00484 
00485     cpl_msg_info(cpl_func, "Detected %d-pixel slit from pixel %d to %d "
00486                  "using %d erosions/dilations", cpl_mask_count(binary),
00487                  *bot_slit_y, *top_slit_y, erosions_nb);
00488 
00489     cpl_mask_delete(binary);
00490 
00491     /* Should really be an assert() */
00492     cpl_ensure_code(ibot <= itop, CPL_ERROR_DATA_NOT_FOUND);
00493 
00494     return CPL_ERROR_NONE;
00495 }
00496 
00497 /*----------------------------------------------------------------------------*/
00507 /*----------------------------------------------------------------------------*/
00508 static cpl_error_code irplib_slitpos_find_vert_pos(const cpl_image * self,
00509                                                    int               xwidth,
00510                                                    int             * slit_pos)
00511 {
00512     const int      size_x = cpl_image_get_size_x(self);
00513     cpl_image    * image1D;
00514     int            yone;
00515     cpl_error_code error;
00516 
00517 
00518     /* Collapse the image to a horizontal 1D image */
00519     image1D = cpl_image_collapse_create(self, 0);
00520 
00521     cpl_ensure_code(image1D != NULL, cpl_error_get_code());
00522 
00523     /* Search the max of the 1D image to identify the slit position */
00524     error = cpl_image_get_maxpos_window(image1D, 1+xwidth, 1, size_x-xwidth,
00525                                         1, slit_pos, &yone);
00526 
00527     cpl_image_delete(image1D);
00528 
00529     cpl_ensure_code(!error, error);
00530 
00531     return CPL_ERROR_NONE;
00532 }

Generated on 8 Mar 2011 for UVES Pipeline Reference Manual by  doxygen 1.6.1