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"
32 class image_weighted_median
: public image_weighted_avg
{
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
46 * The (cumulative) representation would be:
51 * XXX: This storage approach may have poor cache characteristics.
52 * It might be better to localize elements having identical spatial
55 image_ale_real
**colors
;
56 image_ale_real
**weights
;
57 unsigned int capacity
;
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
) {
65 this->capacity
= image_rw::count();
66 } else if (capacity
>= 0) {
67 this->capacity
= (unsigned int) capacity
;
71 colors
= (image_ale_real
**) malloc(this->capacity
* sizeof(image_ale_real
*));
72 weights
= (image_ale_real
**) malloc(this->capacity
* sizeof(image_ale_real
*));
77 if (!colors
|| !weights
) {
78 fprintf(stderr
, "Could not allocate memory for image data.\n");
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
);
89 if (!colors
[f
] || !weights
[f
]) {
90 fprintf(stderr
, "Could not allocate memory for image data.\n");
96 virtual ~image_weighted_median() {
97 for (unsigned int f
= 0; f
< capacity
; f
++) {
107 * Extend the image area to the top, bottom, left, and right,
108 * initializing the new image areas with black pixels. Negative values
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
) {
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.
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)
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
];
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
];
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
];
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
];
175 weights
[ff
]->pix(i
, j
)[k
] += weights
[ff
- 1]->pix(i
, j
)[k
];
184 * XXX: This is inefficient in cases where only one channel is desired.
186 pixel
get_pixel(unsigned int y
, unsigned int x
) const {
189 for (int k
= 0; k
< 3; k
++) {
190 ale_real midpoint
= weights
[capacity
- 1]->chan(y
, x
, k
) / 2;
193 return pixel::zero();
200 unsigned int h
= capacity
- 1;
201 unsigned int m
= h
/ 2;
204 if (weights
[m
]->chan(y
, x
, k
) < midpoint
)
211 if (weights
[l
]->chan(y
, x
, k
) < midpoint
)
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;
226 image
*get_weights() {
227 return weights
[capacity
- 1];
230 image
*get_colors() {