ale/d2/image_weighted_median.h
2022-07-30 14:46:04 -03:00

249 lines
6.7 KiB
C++

// Copyright 2002, 2003, 2004 David Hilvert <dhilvert@auricle.dyndns.org>,
// <dhilvert@ugcs.caltech.edu>
/* This file is part of the Anti-Lamenessing Engine.
The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the Anti-Lamenessing Engine; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* image_weighted_median.h: Image representing a weighted median of inputs.
*/
#ifndef __image_weighted_median_h__
#define __image_weighted_median_h__
#include "exposure/exposure.h"
#include "point.h"
#include "image.h"
class image_weighted_median : public image_weighted_avg {
private:
/*
* Array 'colors' stores image colors, sorted by intensity for each
* channel at each pixel location.
*
* Array 'weights' stores the weights associated with each color, where
* the weights are represented cumulatively, so that for weights and
* intensities:
*
* Color: 1 2 3 6 7
* Weight: 2 2 1 1 1
*
* The (cumulative) representation would be:
*
* Color: 1 2 3 6 7
* Weight: 2 4 5 6 7
*
* XXX: This storage approach may have poor cache characteristics.
* It might be better to localize elements having identical spatial
* coordinates.
*/
image **colors;
image **weights;
unsigned int capacity;
public:
image_weighted_median (unsigned int dimy, unsigned int dimx, unsigned int
depth, int capacity = -1, const char *name = "anonymous")
: image_weighted_avg(dimy, dimx, depth, name) {
if (capacity == -1) {
this->capacity = image_rw::count();
} else if (capacity >= 0) {
this->capacity = (unsigned int) capacity;
} else
assert(0);
colors = (image **) malloc(this->capacity * sizeof(image *));
weights = (image **) malloc(this->capacity * sizeof(image *));
assert(colors);
assert(weights);
if (!colors || !weights) {
fprintf(stderr, "Could not allocate memory for image data.\n");
exit(1);
}
for (unsigned int f = 0; f < this->capacity; f++) {
colors[f] = new_image_ale_real(dimy, dimx, depth);
weights[f] = new_image_ale_real(dimy, dimx, depth);
assert(colors[f]);
assert(weights[f]);
if (!colors[f] || !weights[f]) {
fprintf(stderr, "Could not allocate memory for image data.\n");
exit(1);
}
}
}
virtual ~image_weighted_median() {
for (unsigned int f = 0; f < capacity; f++) {
delete colors[f];
delete weights[f];
}
free(colors);
free(weights);
}
/*
* Extend the image area to the top, bottom, left, and right,
* initializing the new image areas with black pixels. Negative values
* shrink the image.
*/
image *_extend(int top, int bottom, int left, int right) {
for (unsigned int f = 0; f < capacity; f++) {
extend(&colors[f], top, bottom, left, right);
extend(&weights[f], top, bottom, left, right);
}
_dimx = colors[0]->width();
_dimy = colors[0]->height();
_offset = colors[0]->offset();
return NULL;
}
int accumulate_norender(int i, int j) {
return 0;
}
/*
* Perform insertion sort on the arrays, where sort is by color.
*
* XXX: This does a poor job of handling multiple contributions from
* the same frame, especially when the number of frames is 1.
*/
void accumulate(int i, int j, int f, pixel new_value, pixel new_weight) {
for (unsigned int k = 0; k < 3; k++) {
if (fabs(new_weight[k]) > ale_real_weight_floor)
new_value[k] /= new_weight[k];
else
continue;
/*
* XXX: This initialization should not be necessary.
*/
if (f == 0)
for (unsigned int ff = 0; ff < capacity; ff++)
weights[ff]->set_chan(i, j, k, 0);
assert (finite(new_weight[k]));
if (new_weight[k] <= 0)
continue;
for (unsigned int ff = 0; ff < capacity; ff++) {
assert (ff <= (unsigned int) f);
if (ff == capacity - 1) {
colors[ff]->set_chan(i, j, k, new_value[k]);
weights[ff]->set_chan(i, j, k,
weights[ff]->get_chan(i, j, k) + new_weight[k]);
break;
}
if ((ff == 0 && weights[ff]->get_chan(i, j, k) == 0)
|| (ff > 0 && weights[ff]->get_chan(i, j, k) == weights[ff - 1]->get_chan(i, j, k))) {
colors[ff]->set_chan(i, j, k, new_value[k]);
for (unsigned int fff = ff; fff < capacity; fff++)
weights[fff]->set_chan(i, j, k,
weights[fff]->get_chan(i, j, k) + new_weight[k]);
break;
}
if (colors[ff]->get_chan(i, j, k) == (ale_sreal) new_value[k]) {
for (unsigned int fff = ff; fff < capacity; fff++)
weights[fff]->set_chan(i, j, k,
weights[fff]->get_chan(i, j, k) + new_weight[k]);
break;
}
if (colors[ff]->get_chan(i, j, k) > (ale_sreal) new_value[k]) {
for (unsigned int fff = capacity - 1; fff > ff; fff--) {
weights[fff]->set_chan(i, j, k, weights[fff - 1]->get_pixel(i, j)[k] + new_weight[k]);
colors[fff]->set_chan(i, j, k, colors[fff - 1]->get_pixel(i, j)[k]);
}
colors[ff]->set_chan(i, j, k, new_value[k]);
weights[ff]->set_chan(i, j, k, new_weight[k]);
if (ff > 0)
weights[ff]->set_chan(i, j, k,
weights[ff]->get_chan(i, j, k)
+ weights[ff - 1]->get_chan(i, j, k));
break;
}
}
}
}
/*
* XXX: This is inefficient in cases where only one channel is desired.
*/
spixel get_pixel(unsigned int y, unsigned int x) const {
pixel result;
for (int k = 0; k < 3; k++) {
ale_real midpoint = weights[capacity - 1]->get_chan(y, x, k) / 2;
if (midpoint == 0)
return pixel::zero();
/*
* Binary search.
*/
unsigned int l = 0;
unsigned int h = capacity - 1;
unsigned int m = h / 2;
while (h > l + 1) {
if ((ale_real) weights[m]->get_chan(y, x, k) < midpoint)
l = m;
else
h = m;
m = (h + l) / 2;
}
if ((ale_real) weights[l]->get_chan(y, x, k) < midpoint)
l = h;
if ((ale_real) weights[l]->get_chan(y, x, k) > midpoint)
result[k] = colors[l]->get_chan(y, x, k);
else if ((ale_real) weights[l]->get_chan(y, x, k) == midpoint)
result[k] = (colors[l]->get_chan(y, x, k)
+ colors[l + 1]->get_chan(y, x, k)) / 2;
else
assert(0);
}
return result;
}
image *get_weights() {
return weights[capacity - 1];
}
image *get_colors() {
return this;
}
};
#endif