visir_spc_distortion.c

00001 /* $Id: visir_spc_distortion.c,v 1.44 2009/08/21 12:23:39 llundin Exp $
00002  *
00003  * This file is part of the VISIR Pipeline
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: 2009/08/21 12:23:39 $
00024  * $Revision: 1.44 $
00025  * $Name: HEAD $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033                                        Includes
00034  -----------------------------------------------------------------------------*/
00035 
00036 #include <string.h>
00037 #include <math.h>
00038 
00039 #include <cpl.h>
00040 
00041 #include "visir_spc_distortion.h"
00042 #include "visir_utils.h"
00043 
00044 /*----------------------------------------------------------------------------*/
00048 /*----------------------------------------------------------------------------*/
00049 
00050 /*-----------------------------------------------------------------------------
00051                                    Functions prototypes
00052  -----------------------------------------------------------------------------*/
00053 
00054 static cpl_error_code visir_spc_det_warp(cpl_image **, int, double, double,
00055                                          double, double);
00056 
00057 static cpl_error_code visir_spc_det_warp_xy(int, double, double, double, double,
00058                                             double, double, double, double,
00059                                             double *, double*);
00060 
00061 /*-----------------------------------------------------------------------------
00062                                    Functions code
00063  -----------------------------------------------------------------------------*/
00066 /*----------------------------------------------------------------------------*/
00092 /*----------------------------------------------------------------------------*/
00093 cpl_error_code visir_spc_det_fix(cpl_image ** images, int nimages,
00094                                  cpl_boolean is_interm,
00095                                  double wlen, visir_spc_resol resol,
00096                                  double phi, double ksi, double eps, 
00097                                  double delta, int doplot)
00098 {
00099 
00100     cpl_image * spectrum = NULL;
00101 
00102     int nx = 0;  /* Avoid (false) uninit warning */
00103     int ny = 0;  /* Avoid (false) uninit warning */
00104     int k;
00105 
00106 
00107     skip_if (0);
00108 
00109     skip_if (images == NULL);
00110     skip_if (nimages <= 0);
00111 
00112     skip_if (!is_interm && nimages != 1);
00113 
00114     for (k=0; k < nimages; k++) {
00115         if (images[k] == NULL) break;
00116 
00117         if (cpl_image_get_type(images[k]) != CPL_TYPE_FLOAT) {
00118             /* Done only with --fixcombi (used for backwards compatability */
00119             cpl_image * to_float = cpl_image_cast(images[k], CPL_TYPE_FLOAT);
00120 
00121             cpl_image_delete(images[k]);
00122 
00123             images[k] = to_float;
00124 
00125         }
00126 
00127         if (k == 0) {
00128             nx = cpl_image_get_size_x(images[0]);
00129             ny = cpl_image_get_size_y(images[0]);
00130 
00131             skip_if (nx < 1);
00132         } else {
00133             skip_if (nx != cpl_image_get_size_x(images[k]));
00134             skip_if (ny != cpl_image_get_size_y(images[k]));
00135         }
00136 
00137     }
00138 
00139     /* In HR only phi is used */
00140     /* HR Grism mode has its own recipe and needs no hard-coded changes here */
00141     if (resol == VISIR_SPC_R_HR) {
00142 
00143         visir_optmod ins_settings;
00144 
00145         if (visir_spc_optmod_init(VISIR_SPC_R_HR, wlen, &ins_settings)) {
00146             visir_error_set(CPL_ERROR_ILLEGAL_INPUT);
00147             skip_if(1);
00148         }
00149 
00150         if (visir_spc_optmod_side_is_A(&ins_settings)) {
00151             /* Line curvature is zero in HR-A */
00152             eps   = 0;
00153             /* Spectrum curvature is 1.5 times bigger in HR-A than in LMR */
00154             delta *= 1.5;
00155         } else {
00156             /* Line curvature is 2.21 times bigger in HR-B than in LR */
00157             eps   *= 0.115/0.052;
00158             /* Spectrum curvature is 2 times smaller in HR-B than in LMR */
00159             delta *= 0.5;
00160         }
00161         ksi = 0; /* ksi is zero */
00162     } else if (resol == VISIR_SPC_R_MR) {
00163         eps *=  0.25; /* Line curvature is 4 times smaller in MR than in LR */
00164     }
00165 
00166     cpl_msg_info(cpl_func, "Skew and Curvature: %g %g %g %g", phi, ksi, eps,
00167                  delta);
00168 
00169     /* The angles are coded in degrees and then converted to radians */
00170     ksi *= CPL_MATH_RAD_DEG; 
00171     phi *= CPL_MATH_RAD_DEG;
00172 
00173     if (!is_interm) {
00174 
00175         float * px;
00176         const double fdead = 0.25;
00177         int ndead = 0; /* Number of rows of dead pixels */
00178         const int mdeadmax = 4; /* Check 3 outermost rows */
00179         int i,j;
00180 
00181         skip_if (visir_image_reject_hot(images[0], NULL));
00182 
00183         /* Check that the top row of pixels are not too small */
00184 
00185         spectrum = cpl_image_collapse_create(images[0], 1);
00186         skip_if (0);
00187 
00188         px = cpl_image_get_data(spectrum);
00189 
00190         if (doplot > 1) visir_image_col_plot("", "t 'The collapsed 1/2-cycle "
00191                                              "spectrum'", "", spectrum, 1,1,1);
00192 
00193         for (j = 1; j < mdeadmax; j++) {
00194             const float g0 = px[ny  -j] - px[ny-1-j];
00195             const float g1 = px[ny-1-j] - px[ny-2-j];
00196 
00197             cpl_msg_debug(cpl_func, "GRAD(%g): %g <> %g", ny-j-0.5, g0, g1);
00198 
00199             if ((g1 < 0 && g0 * fdead < g1) || (g1 >=0 && g0 < g1 * fdead))
00200                 ndead = j;
00201         }
00202 
00203         if (ndead) {
00204             cpl_msg_info(cpl_func, "Rejecting dead pixels %d -> %d. "
00205                             "GRAD: %g << %g", ny-ndead, ny-1,
00206                             px[ny  -ndead] - px[ny-1-ndead],
00207                             px[ny-1-ndead] - px[ny-2-ndead]);
00208 
00209             for (i = 0; i < nx; i++) {
00210                 for (j = ny-ndead; j < ny; j++) {
00211                     skip_if (cpl_image_reject(images[0], i+1, j+1));
00212                 }
00213             }
00214             ndead = 0;
00215         }
00216 
00217         px = cpl_image_get_data(spectrum);
00218 
00219         for (j = 1; j < mdeadmax; j++) {
00220             const float g0 = px[j-1] - px[j];
00221             const float g1 = px[j] - px[j+1];
00222 
00223             cpl_msg_debug(cpl_func, "GRAD(%g:%d): %g <> %g", j-0.5, ndead, g0, g1);
00224      
00225             if ((g1 < 0 && g0 * fdead < g1) || (g1 >=0 && g0 < g1 * fdead))
00226                 ndead = j;
00227         }
00228 
00229         if (ndead) {
00230             cpl_msg_info(cpl_func, "Rejecting dead pixels 1 -> %d. GRAD: "
00231                             "%g << %g", ndead, px[ndead-1] - px[ndead],
00232                             px[ndead] - px[ndead+1]);
00233 
00234             for (i = 0; i < nx; i++) {
00235                 for (j = 0; j < ndead; j++) {
00236                     skip_if (cpl_image_reject(images[0], i+1, j+1));
00237                 }
00238             }
00239         }
00240         cpl_image_delete(spectrum);
00241         spectrum = NULL;
00242 
00243     }
00244 
00245     /* Apply the distortion correction  */
00246     skip_if (visir_spc_det_warp(images, nimages, phi, ksi, eps, delta));
00247 
00248     if (doplot > 1) visir_image_plot("", "t 'The first corrected image'",
00249                                      "", images[0]);
00250 
00251     end_skip;
00252 
00253     cpl_image_delete(spectrum);
00254 
00255     return cpl_error_get_code();
00256 
00257 }
00258 
00259 
00262 /*----------------------------------------------------------------------------*/
00278 /*----------------------------------------------------------------------------*/
00279 static cpl_error_code visir_spc_det_warp(cpl_image ** images, int nimages,
00280                                          double phi, double ksi,
00281                                          double eps, double delta)
00282 {
00283 
00284 
00285     const double radius = CPL_KERNEL_DEF_WIDTH;
00286     const int tabsperpix = CPL_KERNEL_TABSPERPIX;
00287     const int nx = cpl_image_get_size_x(images[0]);
00288     const int ny = cpl_image_get_size_y(images[0]);
00289     const cpl_boolean do_warp = phi != 0 || ksi != 0 || eps != 0 || delta != 0;
00290     int iu, iv;
00291     int iimage;
00292     int ipix;
00293 
00294     cpl_image  * copy = NULL;
00295     cpl_vector * xyprofile = NULL;
00296     cpl_image  * coord_x = NULL;
00297     cpl_image  * coord_y = NULL;
00298     double * piv = NULL; /* Avoid (false) uninit warning */
00299     double * piu = NULL;
00300     cpl_error_code didfail = CPL_ERROR_NONE;
00301     cpl_errorstate cleanstate = cpl_errorstate_get();
00302 
00303 
00304     skip_if (0);
00305 
00306     if (do_warp) {
00307         double x = 0.0; /* Avoid (false) uninit warning */ 
00308         double y = 0.0; /* Avoid (false) uninit warning */ 
00309 
00310         /* Avoid unnecessary interpolation */
00311 
00312         xyprofile = cpl_vector_new(1 + radius * tabsperpix);
00313         cpl_vector_fill_kernel_profile(xyprofile, CPL_KERNEL_DEFAULT, radius);
00314         coord_x = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
00315         coord_y = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
00316 
00317         piu = cpl_image_get_data(coord_x);
00318         piv = cpl_image_get_data(coord_y);
00319 
00320         skip_if (0);
00321 
00322         for (ipix = 0, iv = 1; iv <= ny; iv++) {
00323             for (iu = 1; iu <= nx; iu++, ipix++) {
00324 
00325                 skip_if (visir_spc_det_warp_xy(1, nx, ny, iu, iv, phi, ksi, eps,
00326                                                delta, &x, &y));
00327                 piu[ipix] = x;
00328                 piv[ipix] = y;
00329             }
00330         }
00331 
00332     }
00333 
00334 #ifdef _OPENMP
00335 #pragma omp parallel for private(iimage, ipix, iv, iu, copy)
00336 #endif
00337     for (iimage = 0 ; iimage < nimages; iimage++) {
00338         cpl_image * image = images[iimage];
00339         cpl_mask  * rejected = NULL;
00340         float     * px    = cpl_image_get_data(image);
00341         double fluxprev, fluxpost;
00342         int nbad = 0; /* Avoid (false) uninit warning */
00343         cpl_binary * preject = NULL;
00344 
00345 
00346         if (!do_warp || cpl_msg_get_level() <= CPL_MSG_DEBUG) {
00347             nbad = cpl_image_count_rejected(image);
00348 
00349             cpl_msg_debug(cpl_func, "Raw image has %d bad pixels", nbad);
00350         }
00351 
00352         if (cpl_error_get_code()) {
00353             didfail = cpl_error_set(cpl_func, cpl_error_get_code());
00354             irplib_error_recover(cleanstate, "Failure for image %d", iimage+1);
00355             continue;
00356         }
00357 
00358         if (!do_warp && nbad == 0) continue;
00359 
00360         fluxprev = cpl_image_get_flux(image);
00361 
00362         if (cpl_error_get_code()) {
00363             didfail = cpl_error_set(cpl_func, cpl_error_get_code());
00364             irplib_error_recover(cleanstate, "Failure for image %d", iimage+1);
00365             continue;
00366         }
00367 
00368         if (do_warp) {
00369             copy = cpl_image_duplicate(image);
00370 
00371             if (cpl_error_get_code()) {
00372                 didfail = cpl_error_set(cpl_func, cpl_error_get_code());
00373                 irplib_error_recover(cleanstate, "Failure for image %d",
00374                                      iimage+1);
00375                 continue;
00376             }
00377 
00378             nbad = 0;
00379             for (ipix = 0, iv = 1; iv <= ny; iv++) {
00380                 for (iu = 1; iu <= nx; iu++, ipix++) {
00381                     double value;
00382                     double confidence;
00383 
00384                     value = cpl_image_get_interpolated(copy, piu[ipix], piv[ipix],
00385                                                        xyprofile, radius,
00386                                                        xyprofile, radius,
00387                                                        &confidence);
00388                     if (confidence < 0) {
00389                         cpl_mask_delete(rejected);
00390                         didfail = cpl_error_set(cpl_func,
00391                                                 CPL_ERROR_ILLEGAL_INPUT);
00392                         irplib_error_recover(cleanstate, "Failure for image %d",
00393                                              iimage+1);
00394                         continue;
00395                     }
00396 
00397                     if (confidence < 0.5) {
00398                         nbad++;
00399                         if (rejected == NULL) {
00400                             rejected = cpl_mask_new(nx, ny);
00401                             preject = cpl_mask_get_data(rejected);
00402                         }
00403                         preject[ipix] = CPL_BINARY_1;
00404                     } else {
00405                         /* The equivalent of at least 2 of the
00406                            nearest 4 pixels are good */
00407                         px[ipix] = value;
00408                     }
00409                 }
00410             }
00411 
00412             cpl_image_delete(copy);
00413             copy = NULL;
00414         }
00415 
00416         if (nbad > 0) {
00417             if (do_warp) {
00418                 const cpl_error_code error
00419                     = cpl_image_reject_from_mask(image, rejected);
00420 
00421                 cpl_mask_delete(rejected);
00422                 rejected = NULL;
00423                 preject = NULL;
00424 
00425                 if (error) {
00426                     didfail = cpl_error_set(cpl_func, cpl_error_get_code());
00427                     irplib_error_recover(cleanstate, "Failure for image %d",
00428                                          iimage+1);
00429                     continue;
00430                 }
00431             }
00432             if (iimage == 0)
00433                 cpl_msg_info(cpl_func, "Cleaning %d bad pixels in "
00434                              "each of the %d images", nbad, nimages);
00435             if (cpl_detector_interpolate_rejected(image)) {
00436                 didfail = cpl_error_set(cpl_func, cpl_error_get_code());
00437                 irplib_error_recover(cleanstate, "Failure for image %d",
00438                                      iimage+1);
00439                 continue;
00440             }
00441 
00442         }
00443 
00444         fluxpost = cpl_image_get_flux(image);
00445 
00446         if (cpl_error_get_code()) {
00447             didfail = cpl_error_set(cpl_func, cpl_error_get_code());
00448             irplib_error_recover(cleanstate, "Failure for image %d", iimage+1);
00449             continue;
00450         }
00451 
00452         cpl_msg_info(cpl_func, "Corrected distortion in image %d, flux: %g => %g",
00453                      1+iimage, fluxprev, fluxpost);
00454 
00455     }
00456     skip_if(didfail);
00457 
00458     end_skip;
00459 
00460     if (cpl_error_get_code())
00461         cpl_msg_error(cpl_func, "Detector unwarp failed (at %s): %s",
00462                       cpl_error_get_where(), cpl_error_get_message());
00463 
00464     cpl_vector_delete(xyprofile);
00465     cpl_image_delete(copy);
00466     cpl_image_delete(coord_x);
00467     cpl_image_delete(coord_y);
00468 
00469     return cpl_error_get_code();
00470 }
00471 
00472 /*----------------------------------------------------------------------------*/
00504 /*----------------------------------------------------------------------------*/
00505 static cpl_error_code visir_spc_det_warp_xy(int inv, double nx, double ny,
00506                                      double x, double y,
00507                                      double phi, double ksi,
00508                                      double eps, double delta,
00509                                      double *pu, double *pv)
00510 {
00511 
00512 
00513 #ifdef VISIR_DET_WARP_ROTATE
00514     double z;
00515     const double skew = phi + ksi;
00516 #endif
00517 
00518     cpl_ensure_code(pu,       CPL_ERROR_NULL_INPUT);
00519     cpl_ensure_code(pv,       CPL_ERROR_NULL_INPUT);
00520 
00521     cpl_ensure_code(nx > 0, CPL_ERROR_ILLEGAL_INPUT);
00522     cpl_ensure_code(ny > 0, CPL_ERROR_ILLEGAL_INPUT);
00523 
00524 
00525     /* Transform Origo to center of detector */
00526     x -= (nx+1)/2;
00527     y -= (ny+1)/2;
00528 
00529     if (inv) {
00530 
00531         if (delta != 0) {
00532             /* Correct vertical curvature */
00533             const double R = ((ny/2)*(ny/2) + delta*delta) / fabs(2 * delta);
00534 
00535             cpl_ensure_code(R >= y, CPL_ERROR_ILLEGAL_INPUT);
00536 
00537             x -= (R - sqrt(R*R - y * y)) * (delta > 0 ? 1 : -1);
00538         }
00539 
00540         if (eps != 0) {
00541             /* Correct horizontal curvature */
00542             const double R = ((ny/2)*(ny/2) + eps*eps) / fabs(2 * eps);
00543 
00544             cpl_ensure_code(R >= x, CPL_ERROR_ILLEGAL_INPUT);
00545 
00546             y += (R - sqrt(R*R - x * x)) * (eps > 0 ? 1 : -1);
00547         }
00548 
00549         /* Skew into horizontal lines */
00550         y -= x * tan(phi);
00551 
00552         /* Skew into vertical lines */
00553         x -= y * tan(ksi);
00554 
00555     } else {
00556 
00557         /* Skew into vertical lines */
00558         x += y * tan(ksi);
00559 
00560         /* Skew into horizontal lines */
00561         y += x * tan(phi);
00562 
00563         if (eps != 0) {
00564             /* Correct horizontal curvature */
00565             const double R = ((ny/2)*(ny/2) + eps*eps) / fabs(2 * eps);
00566 
00567             cpl_ensure_code(R >= x, CPL_ERROR_ILLEGAL_INPUT);
00568 
00569             y -= (R - sqrt(R*R - x * x)) * (eps > 0 ? 1 : -1);
00570         }
00571         if (delta != 0) {
00572             /* Correct vertical curvature */
00573             const double R = ((ny/2)*(ny/2) + delta*delta) / fabs(2 * delta);
00574 
00575             cpl_ensure_code(R >= y, CPL_ERROR_ILLEGAL_INPUT);
00576 
00577             x += (R - sqrt(R*R - y * y)) * (delta > 0 ? 1 : -1);
00578         }
00579     }
00580 
00581     /* Transform Origo back from center of detector */
00582     x += (nx+1)/2;
00583     y += (ny+1)/2;
00584 
00585     *pu = x;
00586     *pv = y;
00587 
00588     return cpl_error_get_code();
00589 
00590 }

Generated on Thu Mar 24 11:59:39 2011 for VISIR Pipeline Reference Manual by  doxygen 1.5.8