Add a class for handling reentrant randomization.
[Ale.git] / d2 / image_weighted_median.h
blob70fb3a10b0c8dedca89ca1729df8a65b5e01d87c
1 // Copyright 2002, 2003, 2004 David Hilvert <dhilvert@auricle.dyndns.org>,
2 // <dhilvert@ugcs.caltech.edu>
4 /* This file is part of the Anti-Lamenessing Engine.
6 The Anti-Lamenessing Engine 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.
11 The Anti-Lamenessing Engine 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.
16 You should have received a copy of the GNU General Public License
17 along with the Anti-Lamenessing Engine; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * image_weighted_median.h: Image representing a weighted median of inputs.
25 #ifndef __image_weighted_median_h__
26 #define __image_weighted_median_h__
28 #include "exposure/exposure.h"
29 #include "point.h"
30 #include "image.h"
32 class image_weighted_median : public image_weighted_avg {
33 private:
36 * Array 'colors' stores image colors, sorted by intensity for each
37 * channel at each pixel location.
39 * Array 'weights' stores the weights associated with each color, where
40 * the weights are represented cumulatively, so that for weights and
41 * intensities:
43 * Color: 1 2 3 6 7
44 * Weight: 2 2 1 1 1
46 * The (cumulative) representation would be:
48 * Color: 1 2 3 6 7
49 * Weight: 2 4 5 6 7
51 * XXX: This storage approach may have poor cache characteristics.
52 * It might be better to localize elements having identical spatial
53 * coordinates.
55 image_ale_real **colors;
56 image_ale_real **weights;
57 unsigned int capacity;
59 public:
60 image_weighted_median (unsigned int dimy, unsigned int dimx, unsigned int
61 depth, int capacity = -1, char *name = "anonymous")
62 : image_weighted_avg(dimy, dimx, depth, name) {
64 if (capacity == -1) {
65 this->capacity = image_rw::count();
66 } else if (capacity >= 0) {
67 this->capacity = (unsigned int) capacity;
68 } else
69 assert(0);
71 colors = (image_ale_real **) malloc(this->capacity * sizeof(image_ale_real *));
72 weights = (image_ale_real **) malloc(this->capacity * sizeof(image_ale_real *));
74 assert(colors);
75 assert(weights);
77 if (!colors || !weights) {
78 fprintf(stderr, "Could not allocate memory for image data.\n");
79 exit(1);
82 for (unsigned int f = 0; f < this->capacity; f++) {
83 colors[f] = new image_ale_real(dimy, dimx, depth);
84 weights[f] = new image_ale_real(dimy, dimx, depth);
86 assert(colors[f]);
87 assert(weights[f]);
89 if (!colors[f] || !weights[f]) {
90 fprintf(stderr, "Could not allocate memory for image data.\n");
91 exit(1);
96 virtual ~image_weighted_median() {
97 for (unsigned int f = 0; f < capacity; f++) {
98 delete colors[f];
99 delete weights[f];
102 free(colors);
103 free(weights);
107 * Extend the image area to the top, bottom, left, and right,
108 * initializing the new image areas with black pixels. Negative values
109 * shrink the image.
111 void extend(int top, int bottom, int left, int right) {
113 for (unsigned int f = 0; f < capacity; f++) {
114 colors[f]->extend(top, bottom, left, right);
115 weights[f]->extend(top, bottom, left, right);
118 _dimx = colors[0]->width();
119 _dimy = colors[0]->height();
120 _offset = colors[0]->offset();
123 int accumulate_norender(int i, int j) {
124 return 0;
128 * Perform insertion sort on the arrays, where sort is by color.
130 * XXX: This does a poor job of handling multiple contributions from
131 * the same frame, especially when the number of frames is 1.
133 void accumulate(int i, int j, int f, pixel new_value, pixel new_weight) {
134 for (unsigned int k = 0; k < 3; k++) {
137 * XXX: This initialization should not be necessary.
139 if (f == 0)
140 for (unsigned int ff = 0; ff < capacity; ff++)
141 weights[ff]->pix(i, j)[k] = 0;
143 assert (finite(new_weight[k]));
145 if (new_weight[k] <= 0)
146 continue;
148 for (unsigned int ff = 0; ff < capacity; ff++) {
149 assert (ff <= (unsigned int) f);
150 if (ff == capacity - 1) {
151 colors[ff]->pix(i, j)[k] = new_value[k];
152 weights[ff]->pix(i, j)[k] += new_weight[k];
153 break;
155 if ((ff == 0 && weights[ff]->pix(i, j)[k] == 0)
156 || (ff > 0 && weights[ff]->pix(i, j)[k] == weights[ff - 1]->pix(i, j)[k])) {
157 colors[ff]->pix(i, j)[k] = new_value[k];
158 for (unsigned int fff = ff; fff < capacity; fff++)
159 weights[fff]->pix(i, j)[k] += new_weight[k];
160 break;
162 if (colors[ff]->pix(i, j)[k] == new_value[k]) {
163 for (unsigned int fff = ff; fff < capacity; fff++)
164 weights[fff]->pix(i, j)[k] += new_weight[k];
165 break;
167 if (colors[ff]->pix(i, j)[k] > new_value[k]) {
168 for (unsigned int fff = capacity - 1; fff > ff; fff--) {
169 weights[fff]->pix(i, j)[k] = weights[fff - 1]->pix(i, j)[k] + new_weight[k];
170 colors[fff]->pix(i, j)[k] = colors[fff - 1]->pix(i, j)[k];
172 colors[ff]->pix(i, j)[k] = new_value[k];
173 weights[ff]->pix(i, j)[k] = new_weight[k];
174 if (ff > 0)
175 weights[ff]->pix(i, j)[k] += weights[ff - 1]->pix(i, j)[k];
177 break;
184 * XXX: This is inefficient in cases where only one channel is desired.
186 pixel get_pixel(unsigned int y, unsigned int x) const {
187 pixel result;
189 for (int k = 0; k < 3; k++) {
190 ale_real midpoint = weights[capacity - 1]->chan(y, x, k) / 2;
192 if (midpoint == 0)
193 return pixel::zero();
196 * Binary search.
199 unsigned int l = 0;
200 unsigned int h = capacity - 1;
201 unsigned int m = h / 2;
203 while (h > l + 1) {
204 if (weights[m]->chan(y, x, k) < midpoint)
205 l = m;
206 else
207 h = m;
208 m = (h + l) / 2;
211 if (weights[l]->chan(y, x, k) < midpoint)
212 l = h;
213 if (weights[l]->chan(y, x, k) > midpoint)
214 result[k] = colors[l]->chan(y, x, k);
215 else if (weights[l]->chan(y, x, k) == midpoint)
216 result[k] = (colors[l]->chan(y, x, k)
217 + colors[l + 1]->chan(y, x, k)) / 2;
218 else
219 assert(0);
223 return result;
226 image *get_weights() {
227 return weights[capacity - 1];
230 image *get_colors() {
231 return this;
236 #endif