visir_spc_distortion.c

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

Generated on Mon Feb 6 15:23:49 2012 for VISIR Pipeline Reference Manual by  doxygen 1.5.8