visir_util_clip_body.c

00001 /* $Id: visir_util_clip_body.c,v 1.18 2012/02/02 10:09:30 jtaylor Exp $
00002  *
00003  * This file is part of the irplib package 
00004  * Copyright (C) 2011 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: jtaylor $
00023  * $Date: 2012/02/02 10:09:30 $
00024  * $Revision: 1.18 $
00025  * $Name: visir-3_5_0 $
00026  */
00027 
00028 #include <math.h>
00029 
00030 #define TYPE_ADD(a) CONCAT2X(a, PIXEL_TYPE)
00031 #define TYPE_ADD_CONST(a) CONCAT2X(a, CONCAT2X(PIXEL_TYPE, const))
00032 
00033 /* Swap macro */
00034 #define PIXEL_TYPE_SWAP(a, b) \
00035     { register const PIXEL_TYPE t=(a); (a)=(b); (b)=t; }
00036 
00037 static PIXEL_TYPE TYPE_ADD(cpl_tools_get_kth)(PIXEL_TYPE *, int, int);
00038 
00039 static
00040 double TYPE_ADD(cpl_tools_get_variancesum)(const PIXEL_TYPE *, int, double *);
00041 
00042 
00043 /*----------------------------------------------------------------------------*/
00055 /*----------------------------------------------------------------------------*/
00056 double TYPE_ADD(cpl_tools_get_variancesum)(const PIXEL_TYPE * a,
00057                                           int n, double * pmean)
00058 {
00059     double varsum = 0.0;
00060     double mean = 0.0;
00061     int i;
00062 
00063     cpl_ensure(a != NULL, CPL_ERROR_NULL_INPUT,    0.0);
00064     cpl_ensure(n >= 0,    CPL_ERROR_ILLEGAL_INPUT, 0.0);
00065 
00066     for (i=0; i < n; i++) {
00067         const double delta = (double)a[i] - mean;
00068 
00069         varsum += i * delta * delta / (double)(i + 1);
00070         mean   += delta / (double)(i + 1);
00071     }
00072 
00073     if (pmean != NULL) *pmean = mean;
00074 
00075     return varsum;
00076 }
00077 
00078 /*----------------------------------------------------------------------------*/
00093 /*----------------------------------------------------------------------------*/
00094 static
00095 PIXEL_TYPE TYPE_ADD(cpl_tools_get_kth)(PIXEL_TYPE * self,
00096                                        int        n,
00097                                        int        k)
00098 {
00099     register int l = 0;
00100     register int m = n - 1;
00101     register int i = l;
00102     register int j = m;
00103 
00104     cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT,          (PIXEL_TYPE)0);
00105     cpl_ensure(k >= 0,       CPL_ERROR_ILLEGAL_INPUT,       (PIXEL_TYPE)0);
00106     cpl_ensure(k <  n,       CPL_ERROR_ACCESS_OUT_OF_RANGE, (PIXEL_TYPE)0);
00107 
00108     while (l < m) {
00109         register const PIXEL_TYPE x = self[k];
00110 
00111         do {
00112             while (self[i] < x) i++;
00113             while (x < self[j]) j--;
00114             if (i <= j) {
00115                 PIXEL_TYPE_SWAP(self[i], self[j]);
00116                 i++; j--;
00117             }
00118         } while (i <= j);
00119 
00120         /* assert( j < i ); */
00121 
00122         /* The original implementation has two index comparisons and
00123            two, three or four index assignments. This has been reduced
00124            to one or two index comparisons and two index assignments.
00125         */
00126 
00127         if (k <= j) {
00128             /* assert( k < i ); */
00129             m = j;
00130             i = l;
00131         } else {
00132             if (k < i) {
00133                 m = j;
00134             } else {
00135                 j = m;
00136             }
00137             l = i;
00138         }
00139     }
00140     return self[k];
00141 }
00142 
00143 
00144 /*----------------------------------------------------------------------------*/
00155 /*----------------------------------------------------------------------------*/
00156 static
00157 cpl_error_code TYPE_ADD(visir_util_clip_kappa_sigma)(cpl_imagelist * self,
00158                                                      cpl_imagelist * devlist,
00159                                                      double keepfrac,
00160                                                      double kappa, int maxite,
00161                                                      const int * shifts)
00162 {
00163     const int         nz  = cpl_imagelist_get_size(self);
00164     const cpl_image * img = cpl_imagelist_get_const(self, 0);
00165     const int         nx = cpl_image_get_size_x(img);
00166     const int         ny = cpl_image_get_size_y(img);
00167     /* Reject this many of the minimum (and maximum) values */
00168     const int         minrej = (int)((double)nz * 0.5 * (1.0 - keepfrac) + 0.5);
00169     PIXEL_TYPE * pvalues = (PIXEL_TYPE*)cpl_malloc(nz * sizeof(*pvalues));
00170     /* Pointers to the nz pixel buffers */
00171     const PIXEL_TYPE ** pimg = cpl_malloc((size_t)nz * sizeof(PIXEL_TYPE *));
00172     cpl_binary       ** pbpm = cpl_malloc((size_t)nz * sizeof(cpl_binary *));
00173     cpl_image         * imgstdev0 = cpl_image_new(nx, ny, STDEV_TYPE);
00174     cpl_image         * imgstdevn = cpl_image_new(nx, ny, STDEV_TYPE);
00175     int k, i, j;
00176 
00177 
00178     bug_if(cpl_image_get_type(img) != PIXEL_TYPE_CPL);
00179 
00180     //error_if(nz < 3, CPL_ERROR_DATA_NOT_FOUND, "nz = %d < 3", nz);
00181 
00182     error_if(keepfrac < 0.0, CPL_ERROR_ILLEGAL_INPUT, "Parameter keepfrac = "
00183              "%g < 0.0", keepfrac);
00184     error_if(keepfrac > 1.0, CPL_ERROR_ILLEGAL_INPUT, "Parameter keepfrac = "
00185              "%g > 1.0", keepfrac);
00186     error_if(kappa    < 0.0, CPL_ERROR_ILLEGAL_INPUT, "Parameter kappa = "
00187              "%g < 0.0", kappa);
00188     error_if(maxite   < 0,   CPL_ERROR_ILLEGAL_INPUT, "Parameter maxite = "
00189              "%d < 0", maxite);        
00190 
00191     for (k = 0; k < nz; k++) {
00192         cpl_image  * imgk = cpl_imagelist_get(self, k);
00193         cpl_mask   * bpm  = cpl_image_get_bpm(imgk);
00194 
00195         pimg[k] = TYPE_ADD_CONST(cpl_image_get_data)(imgk);
00196         pbpm[k] = cpl_mask_get_data(bpm);
00197 
00198         bug_if(pimg[k] == NULL);
00199         bug_if(pbpm[k] == NULL);
00200 
00201     }
00202 
00203     for (j = 0; j < ny; j++) {
00204         for (i = 0; i < nx; i++) {
00205             int nok = 0;
00206 
00207             for (k = 0; k < nz; k++) {
00208                 const int ii = (i + shifts[k * 2]) +
00209                                (j + shifts[k * 2 + 1]) * nx;
00210                 if (i + shifts[k * 2] >= nx || i + shifts[k * 2] < 0 ||
00211                     j + shifts[k * 2 + 1] >= ny || j + shifts[k * 2 + 1] < 0)
00212                     continue;
00213 
00214                 if (!pbpm[k][ii]) {
00215                     pvalues[nok++] = pimg[k][ii];
00216                 }
00217             }
00218 
00219             if (nok > 1) { /* Cannot clip with just one value */
00220                 /* Index of 1st value to skip */
00221                 const int ithmin = minrej - (nz - nok) / 2 - 1;
00222                 double median, mean, stdev, varsum;
00223                 PIXEL_TYPE * pmedian = pvalues;
00224                 int nmedian = nok;
00225                 int nite;
00226 
00227                 if (0 <= ithmin && 2 * ithmin + 3 <= nok) {
00228                     /* Need at least 3 values for a proper median + stdev */
00229                     /* Index of last value to skip */
00230                     const int ithmax = nok - ithmin - 1;
00231                     (void)TYPE_ADD(cpl_tools_get_kth)(pvalues, nok, ithmax);
00232                     (void)TYPE_ADD(cpl_tools_get_kth)(pvalues, ithmax, ithmin);
00233                     /* Already ignored values are skipped in median */
00234                     pmedian += ithmin     + 1;
00235                     nmedian -= ithmin * 2 + 2;
00236                 }
00237                 bug_if( nmedian <= 1 );
00238 
00239                 median = (double)TYPE_ADD(cpl_tools_get_kth)(pmedian, nmedian,
00240                                                              (nmedian - 1) / 2);
00241                 if (!(nmedian & 1)) {
00242                     /* Even number of samples, use mean of two central values */
00243                     /* Already did lower half */
00244                     median  += (double)TYPE_ADD(cpl_tools_get_kth)(pmedian +
00245                                                                    nmedian / 2,
00246                                                                    nmedian / 2,
00247                                                                    0);
00248                     median  *= 0.5;
00249                 }
00250 
00251                 varsum = TYPE_ADD(cpl_tools_get_variancesum)(pmedian, nmedian,
00252                                                              NULL);
00253                 stdev = sqrt(varsum / (double)(nmedian - 1));
00254 
00255                 bug_if(cpl_image_set(imgstdev0, 1 + i, 1 + j, stdev));
00256 
00257                 for (nite = 0; nite < maxite; nite++) {
00258                     /* For nite > 0 use mean of previous iteration */
00259                     const double center = nite ? mean : median;
00260                     const double lolim  = center - kappa * stdev;
00261                     const double hilim  = center + kappa * stdev;
00262                     const int    prevok = nok;
00263 
00264                     nok    = 0;
00265                     mean   = 0.0;
00266                     varsum = 0.0;
00267 
00268                     for (k = 0; k < nz; k++) {
00269                         const int ii = (i + shifts[k * 2]) +
00270                                        (j + shifts[k * 2 + 1]) * nx;
00271                         if (i + shifts[k * 2] >= nx || i + shifts[k * 2] < 0 ||
00272                             j + shifts[k * 2 + 1] >= ny || j + shifts[k * 2 + 1] < 0) {
00273                             continue;
00274                         }
00275                         /*
00276                         cpl_msg_debug(cpl_func, "it %d z%d x%d(%d) y%d(%d): "
00277                                       "%.2f <= %.2f <= %.2f, bad %d", nite, k,
00278                                       i + shifts[k * 2],
00279                                       shifts[k * 2], j + shifts[k * 2 + 1],
00280                                       shifts[k * 2 + 1], lolim,
00281                                       (double)pimg[k][ii + ishift], hilim,
00282                                       pbpm[k][ii + ishift]);
00283                         */
00284 
00285                         if (!pbpm[k][ii]) {
00286                             if (lolim <= pimg[k][ii] &&
00287                                 pimg[k][ii] <= hilim) {
00288                                 /* Compute also for last iteration, for final
00289                                    standard deviation */
00290                                 const double delta =
00291                                     (double)pimg[k][ii] - mean;
00292 
00293                                 varsum += nok * delta * delta
00294                                     / (double)(nok + 1);
00295                                 mean   += delta / (double)(nok + 1);
00296 
00297                                 nok++;
00298                             } else {
00299                                 /* Reject outlier */
00300                                 cpl_msg_debug(cpl_func, "rejected");
00301                                 pbpm[k][ii] = CPL_BINARY_1;
00302                             }
00303                         }
00304                     }
00305 
00306                     if (nok < 2) {
00307                         stdev = 0.0;
00308                         break; /* No more values */
00309                     }
00310                     if (nok == prevok) break; /* Convergence */
00311                     stdev = sqrt(varsum / (double)(nok - 1));
00312                 }
00313                 bug_if(cpl_image_set(imgstdevn, 1 + i, 1 + j, stdev));
00314             }
00315         }
00316     }
00317 
00318     bug_if(cpl_imagelist_set(devlist, imgstdev0, 0));
00319     imgstdev0 = NULL;
00320     bug_if(cpl_imagelist_set(devlist, imgstdevn, 1));
00321     imgstdevn = NULL;
00322 
00323     end_skip;
00324 
00325     cpl_image_delete(imgstdev0);
00326     cpl_image_delete(imgstdevn);
00327     cpl_free(pvalues);
00328     cpl_free(pimg);
00329     cpl_free(pbpm);
00330 
00331     return cpl_error_get_code();
00332 }
00333 
00334 #undef PIXEL_TYPE_SWAP

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