IIINSTRUMENT Pipeline Reference Manual 4.6.1
visir_util_clip_body.c
1/* $Id: visir_util_clip_body.c,v 1.18 2012-02-02 10:09:30 jtaylor Exp $
2 *
3 * This file is part of the irplib package
4 * Copyright (C) 2011 European Southern Observatory
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19 */
20
21/*
22 * $Author: jtaylor $
23 * $Date: 2012-02-02 10:09:30 $
24 * $Revision: 1.18 $
25 * $Name: not supported by cvs2svn $
26 */
27
28#include <math.h>
29
30#define TYPE_ADD(a) CONCAT2X(a, PIXEL_TYPE)
31#define TYPE_ADD_CONST(a) CONCAT2X(a, CONCAT2X(PIXEL_TYPE, const))
32
33/* Swap macro */
34#define PIXEL_TYPE_SWAP(a, b) \
35 { register const PIXEL_TYPE t=(a); (a)=(b); (b)=t; }
36
37static PIXEL_TYPE TYPE_ADD(cpl_tools_get_kth)(PIXEL_TYPE *, int, int);
38
39static
40double TYPE_ADD(cpl_tools_get_variancesum)(const PIXEL_TYPE *, int, double *,
41 const double *);
42
43
44/*----------------------------------------------------------------------------*/
56/*----------------------------------------------------------------------------*/
57double TYPE_ADD(cpl_tools_get_variancesum)(const PIXEL_TYPE * a,
58 int n, double * pmean,
59 const double * cache)
60{
61 double varsum = 0.0;
62 double mean = 0.0;
63 int i;
64
65 cpl_ensure(a != NULL, CPL_ERROR_NULL_INPUT, 0.0);
66 cpl_ensure(n >= 0, CPL_ERROR_ILLEGAL_INPUT, 0.0);
67
68 for (i=0; i < n; i++) {
69 const double delta = (double)a[i] - mean;
70 double ri = cache[i];
71 //assert(ri == 1./(i + 1));
72
73 varsum += i * delta * delta * ri;
74 mean += delta * ri;
75 }
76
77 if (pmean != NULL) *pmean = mean;
78
79 return varsum;
80}
81
82/*----------------------------------------------------------------------------*/
97/*----------------------------------------------------------------------------*/
98static
99PIXEL_TYPE TYPE_ADD(cpl_tools_get_kth)(PIXEL_TYPE * self,
100 int n,
101 int k)
102{
103 register int l = 0;
104 register int m = n - 1;
105 register int i = l;
106 register int j = m;
107
108 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, (PIXEL_TYPE)0);
109 cpl_ensure(k >= 0, CPL_ERROR_ILLEGAL_INPUT, (PIXEL_TYPE)0);
110 cpl_ensure(k < n, CPL_ERROR_ACCESS_OUT_OF_RANGE, (PIXEL_TYPE)0);
111
112 while (l < m) {
113 register const PIXEL_TYPE x = self[k];
114
115 do {
116 while (self[i] < x) i++;
117 while (x < self[j]) j--;
118 if (i <= j) {
119 PIXEL_TYPE_SWAP(self[i], self[j]);
120 i++; j--;
121 }
122 } while (i <= j);
123
124 /* assert( j < i ); */
125
126 /* The original implementation has two index comparisons and
127 two, three or four index assignments. This has been reduced
128 to one or two index comparisons and two index assignments.
129 */
130
131 if (k <= j) {
132 /* assert( k < i ); */
133 m = j;
134 i = l;
135 } else {
136 if (k < i) {
137 m = j;
138 } else {
139 j = m;
140 }
141 l = i;
142 }
143 }
144 return self[k];
145}
146
147
148/*----------------------------------------------------------------------------*/
159/*----------------------------------------------------------------------------*/
160static
161cpl_error_code TYPE_ADD(visir_util_clip_kappa_sigma)(cpl_imagelist * self,
162 cpl_imagelist * devlist,
163 double keepfrac,
164 double kappa, int maxite,
165 const int * shifts)
166{
167 const int nz = cpl_imagelist_get_size(self);
168 const cpl_image * img = cpl_imagelist_get_const(self, 0);
169 const int nx = cpl_image_get_size_x(img);
170 const int ny = cpl_image_get_size_y(img);
171 /* Reject this many of the minimum (and maximum) values */
172 const int minrej = (int)((double)nz * 0.5 * (1.0 - keepfrac) + 0.5);
173 PIXEL_TYPE * pvalues = (PIXEL_TYPE*)cpl_malloc(nz * sizeof(*pvalues));
174 /* Pointers to the nz pixel buffers */
175 const PIXEL_TYPE ** pimg = cpl_malloc((size_t)nz * sizeof(PIXEL_TYPE *));
176 cpl_binary ** pbpm = cpl_malloc((size_t)nz * sizeof(cpl_binary *));
177 cpl_image * imgstdev0 = cpl_image_new(nx, ny, STDEV_TYPE);
178 cpl_image * imgstdevn = cpl_image_new(nx, ny, STDEV_TYPE);
179
180 /* precompute the quotient of the standard deviation computation
181 * improves performance by about 10%-20%
182 * typical burst nz size is around 1000 so it fits easily into the cache
183 * for larger stacks it needs to be reevaluated if the cache misses cost
184 * more than recomputing
185 * the variable is declared globally in the calling file for cleanup */
186OMP_PRAGMA(omp critical(clip_rnok_precompute))
187 if (prnok == NULL || prnok_nz < nz) {
188 if (prnok)
189 cpl_free(prnok);
190 prnok = cpl_malloc(nz * sizeof(prnok[0]));
191 for (int i = 0; i < nz; i++) {
192 prnok[i] = 1. / (i + 1);
193 }
194 prnok_nz = nz;
195 }
196
197
198 bug_if(cpl_image_get_type(img) != PIXEL_TYPE_CPL);
199
200 //error_if(nz < 3, CPL_ERROR_DATA_NOT_FOUND, "nz = %d < 3", nz);
201
202 error_if(keepfrac < 0.0, CPL_ERROR_ILLEGAL_INPUT, "Parameter keepfrac = "
203 "%g < 0.0", keepfrac);
204 error_if(keepfrac > 1.0, CPL_ERROR_ILLEGAL_INPUT, "Parameter keepfrac = "
205 "%g > 1.0", keepfrac);
206 error_if(kappa < 0.0, CPL_ERROR_ILLEGAL_INPUT, "Parameter kappa = "
207 "%g < 0.0", kappa);
208 error_if(maxite < 0, CPL_ERROR_ILLEGAL_INPUT, "Parameter maxite = "
209 "%d < 0", maxite);
210
211 for (int k = 0; k < nz; k++) {
212 cpl_image * imgk = cpl_imagelist_get(self, k);
213 cpl_mask * bpm = cpl_image_get_bpm(imgk);
214
215 pimg[k] = TYPE_ADD_CONST(cpl_image_get_data)(imgk);
216 pbpm[k] = cpl_mask_get_data(bpm);
217
218 bug_if(pimg[k] == NULL);
219 bug_if(pbpm[k] == NULL);
220
221 }
222
223 for (int j = 0; j < ny; j++) {
224 for (int i = 0; i < nx; i++) {
225 int nok = 0;
226
227 for (int k = 0; k < nz; k++) {
228 const int ii = (i + shifts[k * 2]) +
229 (j + shifts[k * 2 + 1]) * nx;
230 if (i + shifts[k * 2] >= nx || i + shifts[k * 2] < 0 ||
231 j + shifts[k * 2 + 1] >= ny || j + shifts[k * 2 + 1] < 0)
232 continue;
233
234 if (!pbpm[k][ii]) {
235 pvalues[nok++] = pimg[k][ii];
236 }
237 }
238
239 if (nok > 1) { /* Cannot clip with just one value */
240 /* Index of 1st value to skip */
241 const int ithmin = minrej - (nz - nok) / 2 - 1;
242 double median, mean, stdev, varsum;
243 PIXEL_TYPE * pmedian = pvalues;
244 int nmedian = nok;
245
246 if (0 <= ithmin && 2 * ithmin + 3 <= nok) {
247 /* Need at least 3 values for a proper median + stdev */
248 /* Index of last value to skip */
249 const int ithmax = nok - ithmin - 1;
250 (void)TYPE_ADD(cpl_tools_get_kth)(pvalues, nok, ithmax);
251 (void)TYPE_ADD(cpl_tools_get_kth)(pvalues, ithmax, ithmin);
252 /* Already ignored values are skipped in median */
253 pmedian += ithmin + 1;
254 nmedian -= ithmin * 2 + 2;
255 }
256 bug_if( nmedian <= 1 );
257
258 median = (double)TYPE_ADD(cpl_tools_get_kth)(pmedian, nmedian,
259 (nmedian - 1) / 2);
260 if (!(nmedian & 1)) {
261 /* Even number of samples, use mean of two central values */
262 /* Already did lower half */
263 median += (double)TYPE_ADD(cpl_tools_get_kth)(pmedian +
264 nmedian / 2,
265 nmedian / 2,
266 0);
267 median *= 0.5;
268 }
269
270 varsum = TYPE_ADD(cpl_tools_get_variancesum)(pmedian, nmedian,
271 NULL, prnok);
272 stdev = sqrt(varsum / (double)(nmedian - 1));
273
274 bug_if(cpl_image_set(imgstdev0, 1 + i, 1 + j, stdev));
275
276 for (int nite = 0; nite < maxite; nite++) {
277 /* For nite > 0 use mean of previous iteration */
278 const double center = nite ? mean : median;
279 const double lolim = center - kappa * stdev;
280 const double hilim = center + kappa * stdev;
281 const int prevok = nok;
282
283 nok = 0;
284 mean = 0.0;
285 varsum = 0.0;
286
287 for (int k = 0; k < nz; k++) {
288 const int ii = (i + shifts[k * 2]) +
289 (j + shifts[k * 2 + 1]) * nx;
290 if (i + shifts[k * 2] >= nx || i + shifts[k * 2] < 0 ||
291 j + shifts[k * 2 + 1] >= ny || j + shifts[k * 2 + 1] < 0) {
292 continue;
293 }
294 /*
295 cpl_msg_debug(cpl_func, "it %d z%d x%d(%d) y%d(%d): "
296 "%.2f <= %.2f <= %.2f, bad %d", nite, k,
297 i + shifts[k * 2],
298 shifts[k * 2], j + shifts[k * 2 + 1],
299 shifts[k * 2 + 1], lolim,
300 (double)pimg[k][ii + ishift], hilim,
301 pbpm[k][ii + ishift]);
302 */
303
304 if (!pbpm[k][ii]) {
305 if (lolim <= pimg[k][ii] &&
306 pimg[k][ii] <= hilim) {
307 /* Compute also for last iteration, for final
308 standard deviation */
309 const double delta =
310 (double)pimg[k][ii] - mean;
311 double rnok = prnok[nok];
312 //assert(rnok == 1./(nok + 1));
313
314 varsum += nok * delta * delta * rnok;
315 mean += delta * rnok;
316
317 nok++;
318 } else {
319 /* Reject outlier */
320 pbpm[k][ii] = CPL_BINARY_1;
321 }
322 }
323 }
324
325 if (nok < 2) {
326 stdev = 0.0;
327 break; /* No more values */
328 }
329 if (nok == prevok) break; /* Convergence */
330 stdev = sqrt(varsum / (double)(nok - 1));
331 }
332 bug_if(cpl_image_set(imgstdevn, 1 + i, 1 + j, stdev));
333 }
334 }
335 }
336
337 bug_if(cpl_imagelist_set(devlist, imgstdev0, 0));
338 imgstdev0 = NULL;
339 bug_if(cpl_imagelist_set(devlist, imgstdevn, 1));
340 imgstdevn = NULL;
341
342 end_skip;
343
344 cpl_image_delete(imgstdev0);
345 cpl_image_delete(imgstdevn);
346 cpl_free(pvalues);
347 cpl_free(pimg);
348 cpl_free(pbpm);
349
350 return cpl_error_get_code();
351}
352
353#undef PIXEL_TYPE_SWAP