CR2RE Pipeline Reference Manual 1.7.0
irplib_hist.c
1
2
3/*
4 * This file is part of the irplib package
5 * Copyright (C) 2002, 2003 European Southern Observatory
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
20 */
21
22/*
23 * $Author: jtaylor $
24 * $Id: irplib_hist.c,v 1.8 2013-07-04 12:10:12 jtaylor Exp $
25 * $Date: 2013-07-04 12:10:12 $
26 * $Revision: 1.8 $
27 * $Name: not supported by cvs2svn $
28 */
29
30#ifdef HAVE_CONFIG_H
31#include <config.h>
32#endif
33
34#include <stdlib.h>
35#include <stdio.h>
36
37#include <math.h>
38
39#include "irplib_hist.h"
40
41struct _irplib_hist_
42{
43 unsigned long *bins;
44 unsigned long nbins;
45 double start;
46 double range;
47};
48
49/*
50 * Create a new empty histogram
51 */
52
53irplib_hist *
54irplib_hist_new(void)
55{
56 return (irplib_hist *)cpl_calloc(1, sizeof(irplib_hist));
57}
58
59/*
60 * Delete a histogram
61 */
62
63void
64irplib_hist_delete(irplib_hist *d)
65{
66 if (d == NULL)
67 return;
68
69 if (d->bins)
70 cpl_free(d->bins);
71
72 cpl_free(d);
73}
74
75/*
76 * Initialise a histogram with user-defined values
77 */
78
79cpl_error_code
80irplib_hist_init(irplib_hist *hist,
81 unsigned long nbins,
82 double start,
83 double range)
84{
85 /* Test the entries */
86 cpl_ensure_code(hist != NULL, CPL_ERROR_NULL_INPUT);
87 cpl_ensure_code(nbins > 0, CPL_ERROR_ILLEGAL_INPUT);
88 cpl_ensure_code(range > 0, CPL_ERROR_ILLEGAL_INPUT);
89 cpl_ensure_code(hist->bins == NULL, CPL_ERROR_ILLEGAL_INPUT);
90
91 /* Initialise the histogram structure */
92 hist->bins = (unsigned long *)cpl_calloc(nbins, sizeof(unsigned long));
93 hist->nbins = nbins;
94 hist->start = start;
95 hist->range = range;
96
97 return cpl_error_get_code();
98}
99
100/*
101 * Return the value of a histogram bin.
102 * An uninitialised histogram is considered an illegal input.
103 */
104
105unsigned long
106irplib_hist_get_value(const irplib_hist *hist, const unsigned long binpos)
107{
108 cpl_ensure(hist != NULL, CPL_ERROR_NULL_INPUT, 0);
109 cpl_ensure(hist->bins != NULL, CPL_ERROR_ILLEGAL_INPUT, 0);
110 cpl_ensure(binpos < hist->nbins, CPL_ERROR_ILLEGAL_INPUT, 0);
111
112 return hist->bins[binpos];
113}
114
115/*
116 * Return the number of bins in the histogram.
117 */
118
119unsigned long
120irplib_hist_get_nbins(const irplib_hist *hist)
121{
122 cpl_ensure(hist != NULL, CPL_ERROR_NULL_INPUT, 0);
123
124 return hist->nbins;
125}
126
127/*
128 * Return the binwidth of the histogram.
129 */
130
131double
132irplib_hist_get_bin_size(const irplib_hist *hist)
133{
134 cpl_ensure(hist != NULL, CPL_ERROR_NULL_INPUT, 0);
135 cpl_ensure(hist->bins != NULL, CPL_ERROR_ILLEGAL_INPUT, 0);
136
137 return hist->range / (double)(hist->nbins - 2);
138}
139
140/*
141 * Return the range covered by the histogram.
142 */
143
144double
145irplib_hist_get_range(const irplib_hist *hist)
146{
147 cpl_ensure(hist != NULL, CPL_ERROR_NULL_INPUT, 0);
148
149 return hist->range;
150}
151
152/*
153 * Return the real value corresponding
154 * to the inferior limit of the histogram..
155 */
156
157double
158irplib_hist_get_start(const irplib_hist *hist)
159{
160 cpl_ensure(hist != NULL, CPL_ERROR_NULL_INPUT, 0);
161 cpl_ensure(hist->bins != NULL, CPL_ERROR_ILLEGAL_INPUT, 0);
162
163 return hist->start;
164}
165
166/*
167 * Fill a histogram for an image.
168 * If the histogram is uninitialised,
169 * the function initialises it with default values.
170 */
171
172cpl_error_code
173irplib_hist_fill(irplib_hist *hist, const cpl_image *image)
174{
175 double binwidth = 1.0;
176 int nsamples;
177 int i;
178 const float *data = 0;
179 const cpl_binary *bpm_data = 0;
180 const cpl_mask *bpm = 0;
181
182 /* Test the entries */
183 cpl_ensure_code(hist != NULL, CPL_ERROR_NULL_INPUT);
184 cpl_ensure_code(image != NULL, CPL_ERROR_NULL_INPUT);
185
186 if (hist->bins == NULL) {
187 const double hstart = cpl_image_get_min(image);
188 const double hrange = cpl_image_get_max(image) - hstart;
189 cpl_error_code error;
190
191 /*
192 * Whichever function that computes an optimal binwidth
193 * should be introduced inside this if-statement, here.
194 */
195
196 /* 2 extra-bins for possible out-of-range values */
197 const unsigned long nbins = (unsigned long)(hrange / binwidth) + 2;
198
199 error = irplib_hist_init(hist, nbins, hstart, hrange);
200 cpl_ensure_code(!error, error);
201 }
202 else {
203 cpl_ensure_code(hist->range > 0, CPL_ERROR_ILLEGAL_INPUT);
204
205 /* 2 bins reserved for possible out-of-range values */
206 binwidth = hist->range / (double)(hist->nbins - 2);
207 }
208
209 nsamples = cpl_image_get_size_x(image) * cpl_image_get_size_y(image);
210 data = cpl_image_get_data_float_const(image);
211 bpm = cpl_image_get_bpm_const(image);
212 if (bpm) {
213 bpm_data = cpl_mask_get_data_const(bpm); // bad pixel mask
214 }
215
216 for (i = 0; i < nsamples; i++) {
217 int pos = 0;
218 if (bpm_data && bpm_data[i] != CPL_BINARY_0) {
219 continue;
220 }
221 pos = (int)((data[i] - hist->start) / binwidth);
222 if (pos < 0) {
223 hist->bins[0]++;
224 }
225 else if ((unsigned long)pos >= (hist->nbins - 2)) {
226 hist->bins[hist->nbins - 1]++;
227 }
228 else {
229 hist->bins[pos + 1]++;
230 }
231 }
232
233 return cpl_error_get_code();
234}
235
236/*
237 * Compute the maximum of a histogram.
238 * Return: the maximum value.
239 * The parameter max_where is a pointer to the position
240 * of the maximum in the histogram.
241 */
242
243unsigned long
244irplib_hist_get_max(const irplib_hist *hist, unsigned long *maxpos)
245{
246 unsigned long max = 0;
247 unsigned long ui;
248
249 cpl_ensure(hist != NULL, CPL_ERROR_NULL_INPUT, 0);
250 cpl_ensure(maxpos != NULL, CPL_ERROR_NULL_INPUT, 0);
251 cpl_ensure(hist->bins != NULL, CPL_ERROR_ILLEGAL_INPUT, 0);
252
253 for (ui = 0; ui < hist->nbins; ui++) {
254 double c_value = irplib_hist_get_value(hist, ui);
255 if (c_value > max) {
256 max = c_value;
257 *maxpos = ui;
258 }
259 }
260
261 return max;
262}
263
264/*
265 * Cast a histogram into a table with a single column named "HIST"
266 */
267
268cpl_table *
269irplib_hist_cast_table(const irplib_hist *hist)
270{
271 cpl_table *table;
272 cpl_error_code error;
273
274 cpl_ensure(hist != NULL, CPL_ERROR_NULL_INPUT, NULL);
275 cpl_ensure(hist->bins != NULL, CPL_ERROR_ILLEGAL_INPUT, NULL);
276
277 table = cpl_table_new(hist->nbins);
278
279 error = cpl_table_new_column(table, "HIST", CPL_TYPE_INT);
280 cpl_ensure(!error, error, NULL);
281
282 error = cpl_table_copy_data_int(table, "HIST", (int *)(hist->bins));
283 cpl_ensure(!error, error, NULL);
284
285 return table;
286}
287
288/*
289 * Collapse the histogram: add the values of all bins.
290 * Used now only for debugging purposes.
291 */
292
293cpl_error_code
294irplib_hist_collapse(irplib_hist *hist, unsigned long new_nbins)
295{
296 unsigned long ui, nuj;
297 unsigned long *old_bins;
298 unsigned long old_nbins;
299 double collapse_rate;
300 cpl_error_code error;
301 unsigned long rest;
302
303 cpl_ensure_code(hist != NULL, CPL_ERROR_NULL_INPUT);
304 cpl_ensure_code(hist->bins != NULL, CPL_ERROR_ILLEGAL_INPUT);
305 cpl_ensure_code(new_nbins > 0, CPL_ERROR_ILLEGAL_INPUT);
306 cpl_ensure_code(new_nbins <= hist->nbins, CPL_ERROR_ILLEGAL_INPUT);
307
308 old_bins = hist->bins;
309 old_nbins = hist->nbins;
310
311 hist->bins = NULL;
312 error = irplib_hist_init(hist, new_nbins, hist->start, hist->range);
313 cpl_ensure_code(!error, error);
314
315 collapse_rate = (double)(old_nbins - 2) / (double)(new_nbins - 2);
316
317 /* The out-of-range values are not affected by the collapsing operation */
318 hist->bins[0] = old_bins[0];
319 hist->bins[new_nbins - 1] = old_bins[old_nbins - 1];
320
321 rest = 0;
322 nuj = 1;
323
324 for (ui = 1; ui < new_nbins - 1; ui++) {
325 unsigned long uj;
326 const double up = collapse_rate * ui;
327
328 hist->bins[ui] += rest;
329
330 for (uj = nuj; uj < (unsigned long)up + 1; uj++)
331 hist->bins[ui] += old_bins[uj];
332
333 rest = (unsigned long)(up - (unsigned long)up) * old_bins[uj];
334 hist->bins[ui] += rest;
335
336 rest = old_bins[uj] - rest;
337 nuj = uj + 1;
338 }
339
340 cpl_free(old_bins);
341
342 return cpl_error_get_code();
343}