/* $Id: cpl_image_iqe.c,v 1.15 2008/02/07 16:28:10 llundin Exp $ * * This file is part of the ESO Common Pipeline Library * Copyright (C) 2001-2004 European Southern Observatory * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * $Author: llundin $ * $Date: 2008/02/07 16:28:10 $ * $Revision: 1.15 $ * $Name: $ */ #ifdef HAVE_CONFIG_H #include #endif /*----------------------------------------------------------------------------- Includes -----------------------------------------------------------------------------*/ #include #include #include #include #include #include #include "cpl_image_iqe.h" #include "cpl_bivector.h" #include "cpl_image_basic.h" #include "cpl_image_defs.h" #include "cpl_math_const.h" /*----------------------------------------------------------------------------- Private Function prototypes - more are declared below -----------------------------------------------------------------------------*/ static int cpl_iqe(float *, int, int, float *, float *) ; /*----------------------------------------------------------------------------*/ /** * @defgroup cpl_image_iqe Images quality estimator routines * * * @par Synopsis: * @code * #include "cpl_image_iqe.h" * @endcode */ /*----------------------------------------------------------------------------*/ /**@{*/ /*----------------------------------------------------------------------------- Function codes -----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /** @brief Compute an image quality estimation for an object @param in the input image @param llx @param lly the zone to analyse ((1, 1) for the first pixel) @param urx The zone must be at least 4 by 4 pixels @param ury @return a newly allocated cpl_bivector containing the results or NULL in error case. This function makes internal use of the iqe() MIDAS function (called here cpl_iqe()) written by P. Grosbol. The code should not be changed, it is duplicated from the MIDAS package. Refer to the MIDAS documentation for more details. This function has proven to give good results over the years when called from RTD. The goal is to provide the exact same functionality in CPL as the one provided in RTD. The code is just copied, it is not maintained by the CPL team. The returned object must be deallocated with cpl_bivector_delete(). It contains in the first vector the computed values, and in the second one, the associated errors. The computed values are: - x position of the object - y position of the object - FWHM along the first axis - FWHM along the second axis - the angle of the first axis with the horizontal in degrees - the peak value of the object - the background computed The bad pixels map of the image is not taken into account. The input image must be of type float. Possible #_cpl_error_code_ set in this function: - CPL_ERROR_NULL_INPUT if (one of) the input pointer(s) is NULL - CPL_ERROR_ILLEGAL_INPUT if the specified zone is not valid or if the computation fails on this zone - CPL_ERROR_TYPE_MISMATCH if the input image has the wrong type */ /*----------------------------------------------------------------------------*/ cpl_bivector * cpl_image_iqe( const cpl_image * in, int llx, int lly, int urx, int ury) { cpl_image * extracted ; float parm[8], sdev[8]; float * pextracted ; cpl_bivector * res ; double * res_x ; double * res_y ; /* Check entries */ cpl_ensure(in, CPL_ERROR_NULL_INPUT, NULL); cpl_ensure(in->type == CPL_TYPE_FLOAT, CPL_ERROR_TYPE_MISMATCH, NULL); cpl_ensure(urx >= llx + 3, CPL_ERROR_ILLEGAL_INPUT, NULL); cpl_ensure(ury >= lly + 3, CPL_ERROR_ILLEGAL_INPUT, NULL); /* Extract the image */ extracted = cpl_image_extract(in, llx, lly, urx, ury) ; cpl_ensure(extracted, CPL_ERROR_ILLEGAL_INPUT, NULL); /* Get the pointer to the data */ pextracted = cpl_image_get_data_float(extracted) ; /* Call the cpl_iqe() function */ if (cpl_iqe(pextracted, extracted->nx, extracted->ny, parm, sdev) != 0) { cpl_image_delete(extracted) ; cpl_ensure(0, CPL_ERROR_ILLEGAL_INPUT, NULL); } cpl_image_delete(extracted) ; /* Create the result cpl_bivector */ res = cpl_bivector_new(7) ; res_x = cpl_bivector_get_x_data(res) ; res_y = cpl_bivector_get_y_data(res) ; res_x[0] = llx + parm[0] ; res_y[0] = sdev[0] ; res_x[1] = lly + parm[2] ; res_y[1] = sdev[2] ; res_x[2] = parm[1] ; res_y[2] = sdev[1] ; res_x[3] = parm[3] ; res_y[3] = sdev[3] ; res_x[4] = parm[4] ; res_y[4] = sdev[4] ; res_x[5] = parm[5] ; res_y[5] = sdev[5] ; res_x[6] = parm[6] ; res_y[6] = sdev[6] ; return res ; } /**@}*/ /* Declare local functions private to avoid namespace conflicts */ /* Also add function declaration, to prevent problems in case the ieq() code is copied once again from RTD. */ static int gaussj(double *, int, double *, int); static int covsrt(double *, int, int [], int); static int estm9p(float *, int, int, int, int, float *, float *, float *); static int iqebgv(float *, int, int, float *, float *, int *); static int iqemnt(float *, int, int, float, float, float *); static int iqesec(float *, int, int, float, float *, float *); static int iqefit(float *, int, int, float, float *, float *, float *); static void indexx(int, float [], int []); static void hsort(int, float *); static int mrqmin(int, float [], int, int [], int, double *, double *, double *, int (*)(), double *); static int mrqcof(int, float [], int, int [], int, double *, double [], double *, int (*)()); static int g2efit(float *, float *, int, int, float [], float [], double *); static int g2einit(float *, float *, int, int); static int g2efunc(int, float *, float *, float *, float *, float *, int); /******************************************************************************/ /* iqe() COPIED FROM RTD 20-06-2003 */ /* - unused function definition indexd() removed */ /* - static modifier added to private functions */ /* - old-style function definitions replaced */ /******************************************************************************/ static double hsq2 = 0.7071067811865475244; /* constant 0.5*sqrt(2) */ #define MA 6 /* No. of variables */ #define MITER 64 /* Max. no. of iterations */ static float *pval; static float *pwght; static int mx, mp, winsize; static double w[9]; static double xi[9]; static double yi[9]; static int cpl_iqe( /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Estimate parameters for the Image Quality using a small frame around the object. The following parameters are estimated and given in the array 'parm': parm[0] = mean X position within array, first pixel = 0 parm[1] = FWHM in X parm[2] = mean Y position within array, first pixel = 0 parm[3] = FWHM in Y parm[4] = angle of major axis, degrees, along X = 0 parm[5] = peak value of object above background parm[6] = mean background level Further, estimates of the standard deviation of the parameters are given in 'sdev'. The routine is just a sequence of calls to 'iqebgv', 'iqemnt', 'iqesec' and 'iqefit'. .RETURN status, 0: OK, <0: estimate failed, ------------------------------------------------------------------------*/ float *pfm, int mx, int my, float *parm, float *sdev ) { int n, err, nbg; float bgv, bgs; float ap[6], cv[6], est[6], sec[6]; for (n=0; n<7; n++) parm[n] = sdev[n] = 0.0; winsize = (mx * my) - 1; /* size of sub window */ if ((err=iqebgv(pfm, mx, my, &bgv, &bgs, &nbg))) return -1; parm[6] = bgv; sdev[6] = bgs; if ((err=iqemnt(pfm, mx, my, bgv, bgs, est))) return -2; parm[0] = est[1]; parm[1] = CPL_MATH_FWHM_SIG*est[2]; /* Sigma to FWHM */ parm[2] = est[3]; parm[3] = CPL_MATH_FWHM_SIG*est[4]; /* Sigma to FWHM */ parm[5] = est[0]; if ((err=iqesec(pfm, mx, my, bgv, est, sec))) return -3; parm[4] = CPL_MATH_DEG_RAD*sec[5]; /* Radian to Degrees */ if ((err=iqefit(pfm, mx, my, bgv, sec, ap, cv))<0) return -4; parm[0] = ap[1]; sdev[0] = cv[1]; parm[1] = CPL_MATH_FWHM_SIG*ap[2]; /* Sigma to FWHM */ sdev[1] = CPL_MATH_FWHM_SIG*cv[2]; /* Sigma to FWHM */ parm[2] = ap[3]; sdev[2] = cv[3]; parm[3] = CPL_MATH_FWHM_SIG*ap[4]; /* Sigma to FWHM */ sdev[3] = CPL_MATH_FWHM_SIG*cv[4]; /* Sigma to FWHM */ parm[4] = fmod(CPL_MATH_DEG_RAD*ap[5]+180.0, 180.0); sdev[4] = CPL_MATH_DEG_RAD*cv[5]; /* Radian to Degrees */ if (sdev[4] > 180.) sdev[4] = 180.0; /* max is: Pi */ parm[5] = ap[0]; sdev[5] = cv[0]; return 0; } static int iqebgv( /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Estimate background level for subimage .RETURN status, 0: OK, -1:no buffer space, -2: no points left ------------------------------------------------------------------------*/ float *pfm, int mx, int my, float *bgm, float *bgs, int *nbg ) { int n, m, ns, ms, nt, mt; float *pfb, *pwb, *pf, *pw; float *pf0, *pf1, *pf2, *pf3, *pfs0, *pfs1, *pfs2, *pfs3; double val, fks, ba, bm, bs; *bgm = 0.0; *bgs = 0.0; *nbg = 0; pfs0 = pfm; pfs1 = pfm + mx - 1; pfs2 = pfm + mx*(my-1); pfs3 = pfm + mx*my - 1; ns = (mx winsize)) return -99; val = *pf - bgv; am = val; ax = val*x; ay = val*y; axx = val*x*x; ayy = val*y*y; axy = val*x*y; nt++; ki = ks = kn = 1; while (n--) { k = kn; if (!ki && ks==-1) { if (nx) nx = 0; else break; } ioff = (ki) ? ks : ks*mx; while (k--) { if (ki) x += ks; else y += ks; if (x<0.0 || y<0.0 || xm winsize)) break; val = *pf - bgv; if (dv winsize)) break; dx = x - xc; dy = y - yc; r = sqrt(dx*dx + dy*dy); if (rl winsize)) return -99; pf = pfb; pw = pwb; iy = ny; while (iy--) { ix = nx; while (ix--) { *pf++ = *pfm++ - bgv; psize = pfm - pfmo; if (psize > winsize) return -99; *pw++ = 1.0; } pfm += mx - nx; psize = pfm - pfmo; if ((psize < 0) || (psize > winsize)) return -99; } /* initialize parameters for fitting */ ap[0] = est[0]; ap[1] = est[1] - nxs; ap[2] = est[2]; ap[3] = est[3] - nys; ap[4] = est[4]; ap[5] = est[5]; /* perform actual 2D Gauss fit on small subimage */ n = g2efit(pfb, pwb, nx, ny, ap, cm, &chi); /* normalize parameters and uncertainties, and exit */ ap[1] += nxs; ap[3] += nys; free(pfb); return n; } static int g2einit( /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Initiate gauss fit function, set pointers to data and weights .RETURN status, 0: OK, -1: error - bad pixel no. ------------------------------------------------------------------------*/ float *val, float *wght, int nx, int ny ) { double fh, w1, w2, w3; if (nx<1) { /* if NO x-pixel set to NULL */ pval = (float *) 0; pwght = (float *) 0; mx = mp = 0; return -1; } pval = val; /* otherwise initiate static varables */ pwght = wght; mx = nx; mp = (0 1) return -1; } if (kk != ma) return -2; *alamda = 0.001; mrqcof(ndata, a, ma, lista, mfit, alpha, beta, chisq, funcs); if (*chisq<=0.0) return -4; ochisq = (*chisq); } for (j=0; j= big) { big = dum; irow = j; icol = k; } } else if (ipiv[k] > 1) return -1; } } ++(ipiv[icol]); if (irow != icol) { for (l=0; l=0; l--) { if (indxr[l] != indxc[l]) for (k=0; k lista[i]) covar[lista[j]+lista[i]*ma] = covar[i+j*ma]; else covar[lista[i]+lista[j]*ma] = covar[i+j*ma]; } swap = covar[0]; for (j=0; j> 1; ir = n - 1; while(1) { if (l>0) { indxt = indx[--l]; q = arrin[indxt]; } else { indxt = indx[ir]; q = arrin[indxt]; indx[ir] = indx[0]; if (--ir == 0) { indx[0] = indxt; return; } } i = l; j = (l<<1) + 1; while (j<=ir) { if (j> 1; ir = n - 1; while (1) { if (l>0) rra = ra[--l]; else { rra = ra[ir]; ra[ir] = ra[0]; if (--ir == 0) { ra[0] = rra; return; } } i = l; j = (l << 1) + 1; while (j<=ir) { if (j