initial commit
This commit is contained in:
519
d2/render/combine.h
Normal file
519
d2/render/combine.h
Normal file
@@ -0,0 +1,519 @@
|
||||
// Copyright 2002, 2007 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* combine.h: A renderer that combines two renderings.
|
||||
*/
|
||||
|
||||
#ifndef __combine_h__
|
||||
#define __combine_h__
|
||||
|
||||
#include "../transformation.h"
|
||||
#include "../image.h"
|
||||
#include "../point.h"
|
||||
#include "incremental.h"
|
||||
#include "../filter/filter.h"
|
||||
|
||||
/*
|
||||
* Combine two renderings.
|
||||
*
|
||||
* Available data is taken from the PARTIAL rendering. When no data from
|
||||
* the PARTIAL rendering is available, data from the DEFAULT rendering
|
||||
* is substituted.
|
||||
*/
|
||||
|
||||
class combine : public render {
|
||||
private:
|
||||
render *_default;
|
||||
render *partial;
|
||||
mutable image *output_image;
|
||||
mutable image *defined_image;
|
||||
int synced;
|
||||
|
||||
class refilter : public thread::decompose_domain {
|
||||
combine *c;
|
||||
const render *fine;
|
||||
const render *coarse;
|
||||
const filter::filter *f;
|
||||
const image *fine_weight;
|
||||
const image *fine_image;
|
||||
const image *coarse_image;
|
||||
const image *coarse_defined;
|
||||
image *output_image;
|
||||
|
||||
/*
|
||||
* Attempt to determine a distance by finding two nearby defined
|
||||
* pixels, such that each pixel is in a 90-degree axis-aligned
|
||||
* cone opposite the other.
|
||||
*/
|
||||
|
||||
ale_pos find_nonzero_weight_distance(int i, int j, int k) {
|
||||
|
||||
assert (i >= 0);
|
||||
assert (j >= 0);
|
||||
assert (i < (int) coarse_defined->height());
|
||||
assert (j < (int) coarse_defined->width());
|
||||
|
||||
assert (coarse_defined->get_chan(i, j, k) > 0);
|
||||
|
||||
ale_pos zero = +0.0;
|
||||
ale_pos one = +1.0;
|
||||
|
||||
ale_pos nearest = one / zero;
|
||||
|
||||
assert (isinf(nearest) && nearest > 0);
|
||||
|
||||
int radius = 0;
|
||||
int in_bounds = 1;
|
||||
|
||||
int coords[2];
|
||||
|
||||
while (radius < nearest && in_bounds) {
|
||||
in_bounds = 0;
|
||||
|
||||
for (int ii = i - radius; ii <= i + radius; ii++)
|
||||
for (int jj = j - radius; jj <= j + radius;
|
||||
jj += ((abs(i - ii) == radius)
|
||||
? 1
|
||||
: radius * 2)) {
|
||||
if (ii < 0
|
||||
|| jj < 0
|
||||
|| ii >= (int) coarse_defined->height()
|
||||
|| jj >= (int) coarse_defined->width()
|
||||
|| !(coarse_defined->get_chan(ii, jj, k) > 0))
|
||||
continue;
|
||||
|
||||
in_bounds = 1;
|
||||
|
||||
if (!(fine_weight->get_chan(ii, jj, k) > 0))
|
||||
continue;
|
||||
|
||||
ale_pos distance = sqrt( (ale_pos) ((i - ii) * (i - ii)
|
||||
+ (j - jj) * (j - jj)));
|
||||
|
||||
if (distance < nearest) {
|
||||
nearest = distance;
|
||||
coords[0] = ii;
|
||||
coords[1] = jj;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
radius++;
|
||||
}
|
||||
|
||||
if (isinf(nearest))
|
||||
return nearest;
|
||||
|
||||
int cone_axis = 0;
|
||||
int cone_dir = 1;
|
||||
|
||||
if (abs(coords[0] - i) < abs(coords[1] - j))
|
||||
cone_axis = 1;
|
||||
|
||||
int orig_coords[2] = {i, j};
|
||||
|
||||
if (coords[cone_axis] - orig_coords[cone_axis] > 0)
|
||||
cone_dir = -1;
|
||||
|
||||
nearest = one / zero;
|
||||
|
||||
assert (isinf(nearest) && nearest > 0);
|
||||
|
||||
radius = 1;
|
||||
in_bounds = 1;
|
||||
|
||||
int coords2[2];
|
||||
|
||||
i = coords[0];
|
||||
j = coords[1];
|
||||
|
||||
while (radius < nearest && in_bounds) {
|
||||
in_bounds = 0;
|
||||
|
||||
coords2[cone_axis] = orig_coords[cone_axis] + radius * cone_dir;
|
||||
|
||||
for (coords2[1 - cone_axis] = orig_coords[1 - cone_axis] - radius;
|
||||
coords2[1 - cone_axis] < orig_coords[1 - cone_axis] + radius;
|
||||
coords2[1 - cone_axis]++) {
|
||||
|
||||
int ii = coords2[0];
|
||||
int jj = coords2[1];
|
||||
|
||||
if (ii < 0
|
||||
|| jj < 0
|
||||
|| ii >= (int) coarse_defined->height()
|
||||
|| jj >= (int) coarse_defined->width()
|
||||
|| !(coarse_defined->get_chan(ii, jj, k) > 0))
|
||||
continue;
|
||||
|
||||
in_bounds = 1;
|
||||
|
||||
if (!(fine_weight->get_chan(ii, jj, k) > 0))
|
||||
continue;
|
||||
|
||||
ale_pos distance = sqrt( (ale_pos) ((i - ii) * (i - ii)
|
||||
+ (j - jj) * (j - jj)));
|
||||
|
||||
if (distance < nearest)
|
||||
nearest = distance;
|
||||
}
|
||||
|
||||
radius++;
|
||||
}
|
||||
|
||||
return nearest;
|
||||
}
|
||||
|
||||
protected:
|
||||
void subdomain_algorithm(unsigned int thread,
|
||||
int i_min, int i_max, int j_min, int j_max) {
|
||||
|
||||
for (int i = i_min; i < i_max; i++)
|
||||
for (int j = j_min; j < j_max; j++)
|
||||
for (unsigned int k = 0; k < 3; k++){
|
||||
|
||||
if (!(coarse_defined->get_chan(i, j, k) > 0))
|
||||
continue;
|
||||
|
||||
ale_pos filter_scale = 1;
|
||||
ale_real filtered_weight;
|
||||
ale_real filtered_value;
|
||||
|
||||
/*
|
||||
* Attempt to set an initial filter scale based
|
||||
* on the proximity of two nearby k-defined
|
||||
* pixels.
|
||||
*/
|
||||
|
||||
ale_pos n1 = find_nonzero_weight_distance(i, j, k);
|
||||
|
||||
if (!finite(n1)) {
|
||||
output_image->set_chan(i, j, k, coarse_image->get_pixel(i, j)[k]);
|
||||
continue;
|
||||
}
|
||||
|
||||
filter_scale = n1;
|
||||
|
||||
do {
|
||||
|
||||
filtered_weight = 0;
|
||||
filtered_value = 0;
|
||||
|
||||
/*
|
||||
* lrintf() may be faster than ceil/floor() on some architectures.
|
||||
* See render/psf/raster.h for more details.
|
||||
*/
|
||||
|
||||
int support_extreme = (int) lrintf(f->support() * filter_scale);
|
||||
assert (support_extreme >= 0);
|
||||
|
||||
for (int ii = -support_extreme;
|
||||
ii < support_extreme; ii++)
|
||||
for (int jj = -support_extreme;
|
||||
jj < support_extreme; jj++) {
|
||||
|
||||
if (ii + i < 0
|
||||
|| jj + j < 0
|
||||
|| ii + i >= (int) fine_weight->height()
|
||||
|| jj + j >= (int) fine_weight->width())
|
||||
continue;
|
||||
|
||||
ale_real pw = fine_weight->get_chan(i + ii, j + jj, k);
|
||||
|
||||
if (!(pw > 0))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* XXX: Set the weight to one
|
||||
* for now, to prevent
|
||||
* interference from certainty
|
||||
* values calculated under
|
||||
* different assumptions.
|
||||
*/
|
||||
|
||||
pw = 1;
|
||||
|
||||
ale_real w = pw * f->response(point(ii / filter_scale,
|
||||
jj / filter_scale));
|
||||
|
||||
ale_real v = fine_image->get_pixel(i + ii, j + jj)[k];
|
||||
|
||||
if (!finite(w) || !finite(v))
|
||||
continue;
|
||||
|
||||
filtered_weight += w;
|
||||
filtered_value += w * v;
|
||||
}
|
||||
|
||||
if (filtered_weight < render::get_wt())
|
||||
/* filter_scale += 1; */
|
||||
filter_scale *= 2;
|
||||
|
||||
} while (filtered_weight < render::get_wt()
|
||||
&& filter_scale < coarse_defined->width()
|
||||
+ coarse_defined->height());
|
||||
|
||||
output_image->set_chan(i, j, k, filtered_value / filtered_weight);
|
||||
}
|
||||
}
|
||||
public:
|
||||
refilter(combine *_c,
|
||||
const render *_fine,
|
||||
const render *_coarse,
|
||||
const filter::filter *_f,
|
||||
const image *_fine_weight,
|
||||
const image *_fine_image,
|
||||
const image *_coarse_image,
|
||||
const image *_coarse_defined,
|
||||
image *_output_image) : decompose_domain(0, _coarse_defined->height(),
|
||||
0, _coarse_defined->width()) {
|
||||
|
||||
c = _c;
|
||||
fine = _fine;
|
||||
coarse = _coarse;
|
||||
f = _f;
|
||||
fine_weight = _fine_weight;
|
||||
fine_image = _fine_image;
|
||||
coarse_image = _coarse_image;
|
||||
coarse_defined = _coarse_defined;
|
||||
output_image = _output_image;
|
||||
}
|
||||
};
|
||||
|
||||
const image *get_image_dynamic() const {
|
||||
assert(typeid(*partial) == typeid(incremental));
|
||||
|
||||
if (typeid(*_default) != typeid(combine) || !synced) {
|
||||
/*
|
||||
* Degenerate case.
|
||||
*/
|
||||
output_image = _default->get_image()->clone("degenerate dynamic filter");
|
||||
return output_image;
|
||||
}
|
||||
|
||||
combine *c = (combine *)_default;
|
||||
const render *fine = c->get_partial();
|
||||
const render *coarse = c->get_default();
|
||||
const filter::filter *f = ((incremental *)partial)->get_invariant()->ssfe()->
|
||||
get_scaled_filter()->get_filter();
|
||||
const image *fine_weight = fine->get_defined();
|
||||
const image *fine_image = fine->get_image();
|
||||
const image *coarse_image = coarse->get_image();
|
||||
const image *coarse_defined = coarse->get_defined();
|
||||
|
||||
output_image = new_image_ale_real(coarse_defined->height(),
|
||||
coarse_defined->width(), 3, NULL);
|
||||
|
||||
output_image->set_offset(coarse_defined->offset());
|
||||
|
||||
assert (coarse_defined->width() == fine_image->width());
|
||||
assert (coarse_defined->height() == fine_image->height());
|
||||
assert (coarse_defined->width() == fine_weight->width());
|
||||
assert (coarse_defined->height() == fine_weight->height());
|
||||
|
||||
ui::get()->refilter_start();
|
||||
|
||||
refilter r(c, fine, coarse, f, fine_weight, fine_image, coarse_image,
|
||||
coarse_defined, output_image);
|
||||
r.run();
|
||||
|
||||
ui::get()->refilter_done();
|
||||
|
||||
return output_image;
|
||||
}
|
||||
public:
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
combine(render *_default, render *partial) {
|
||||
this->_default = _default;
|
||||
this->partial = partial;
|
||||
this->output_image = NULL;
|
||||
this->defined_image = NULL;
|
||||
this->synced = 0;
|
||||
}
|
||||
|
||||
virtual ~combine() {
|
||||
if (output_image)
|
||||
delete output_image;
|
||||
if (defined_image)
|
||||
delete defined_image;
|
||||
}
|
||||
|
||||
/*
|
||||
* Result of rendering.
|
||||
*/
|
||||
|
||||
virtual const image *get_image() const {
|
||||
|
||||
if (output_image)
|
||||
return output_image;
|
||||
|
||||
assert(typeid(*partial) != typeid(combine));
|
||||
|
||||
/*
|
||||
* Dynamic filtering is handled separately.
|
||||
*/
|
||||
if (typeid(*partial) == typeid(incremental)
|
||||
&& (((incremental *)partial)->get_invariant()->
|
||||
ssfe()->get_scaled_filter()->is_dynamic()))
|
||||
return get_image_dynamic();
|
||||
|
||||
const image *default_image = _default->get_image();
|
||||
|
||||
output_image = new_image_ale_real(default_image->height(),
|
||||
default_image->width(), 3, NULL);
|
||||
|
||||
output_image->set_offset(default_image->offset());
|
||||
|
||||
const image *partial_image = partial->get_image();
|
||||
const image *partial_weight = partial->get_defined();
|
||||
|
||||
assert (default_image->width() == partial_image->width());
|
||||
assert (default_image->height() == partial_image->height());
|
||||
|
||||
for (unsigned int i = 0; i < default_image->height(); i++)
|
||||
for (unsigned int j = 0; j < default_image->width(); j++)
|
||||
output_image->set_pixel(i, j,
|
||||
((ale_real) ((pixel) partial_weight->get_pixel(i, j)).min_norm()
|
||||
>= render::get_wt())
|
||||
? partial_image->get_pixel(i, j)
|
||||
: default_image->get_pixel(i, j));
|
||||
|
||||
return output_image;
|
||||
}
|
||||
|
||||
/*
|
||||
* Definition map. Unit-depth image whose pixels are nonzero where
|
||||
* the image is defined.
|
||||
*/
|
||||
|
||||
virtual const image *get_defined() const {
|
||||
unsigned int i, j, k;
|
||||
|
||||
if (defined_image)
|
||||
return defined_image;
|
||||
|
||||
const image *partial_weight = partial->get_defined();
|
||||
const image *default_weight = _default->get_defined();
|
||||
|
||||
assert (default_weight->width() == partial_weight->width());
|
||||
assert (default_weight->height() == partial_weight->height());
|
||||
|
||||
defined_image = new_image_ale_real(default_weight->height(),
|
||||
default_weight->width(), 3, NULL);
|
||||
|
||||
defined_image->set_offset(default_weight->offset());
|
||||
|
||||
for (i = 0; i < default_weight->height(); i++)
|
||||
for (j = 0; j < default_weight->width(); j++)
|
||||
for (k = 0; k < default_weight->depth(); k++)
|
||||
defined_image->set_pixel(i, j,
|
||||
((ale_real) ((pixel) partial_weight->get_pixel(i, j)).min_norm()
|
||||
>= render::get_wt())
|
||||
? partial_weight->get_pixel(i, j)
|
||||
: default_weight->get_pixel(i, j));
|
||||
|
||||
return defined_image;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform rendering steps requiring no frames beyond frame N.
|
||||
*/
|
||||
|
||||
virtual void sync(int n) {
|
||||
render::sync(n);
|
||||
if (output_image) {
|
||||
delete output_image;
|
||||
output_image = NULL;
|
||||
}
|
||||
if (defined_image) {
|
||||
delete defined_image;
|
||||
defined_image = NULL;
|
||||
}
|
||||
_default->sync(n);
|
||||
partial->sync(n);
|
||||
}
|
||||
|
||||
virtual void step() {
|
||||
}
|
||||
|
||||
virtual int sync() {
|
||||
if (output_image) {
|
||||
delete output_image;
|
||||
output_image = NULL;
|
||||
}
|
||||
if (defined_image) {
|
||||
delete defined_image;
|
||||
defined_image = NULL;
|
||||
}
|
||||
_default->sync();
|
||||
partial->sync();
|
||||
synced = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual void init_point_renderer(unsigned int h, unsigned int w, unsigned int d) {
|
||||
_default->init_point_renderer(h, w, d);
|
||||
partial->init_point_renderer(h, w, d);
|
||||
output_image = new image_zero(h, w, d);
|
||||
defined_image = new image_zero(h, w, d);
|
||||
}
|
||||
|
||||
virtual void point_render(unsigned int i, unsigned int j, unsigned int f, transformation t) {
|
||||
_default->point_render(i, j, f, t);
|
||||
partial->point_render(i, j, f, t);
|
||||
}
|
||||
|
||||
virtual void finish_point_rendering() {
|
||||
_default->finish_point_rendering();
|
||||
partial->finish_point_rendering();
|
||||
delete defined_image;
|
||||
delete output_image;
|
||||
|
||||
/*
|
||||
* These will be generated upon a call to get_image() or
|
||||
* get_defined().
|
||||
*/
|
||||
|
||||
defined_image = NULL;
|
||||
output_image = NULL;
|
||||
}
|
||||
|
||||
const render *get_default() const {
|
||||
return _default;
|
||||
}
|
||||
|
||||
const render *get_partial() const {
|
||||
return partial;
|
||||
}
|
||||
|
||||
void free_memory() {
|
||||
delete output_image;
|
||||
delete defined_image;
|
||||
output_image = NULL;
|
||||
defined_image = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
427
d2/render/incremental.h
Normal file
427
d2/render/incremental.h
Normal file
@@ -0,0 +1,427 @@
|
||||
// Copyright 2002, 2004, 2007 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
|
||||
*/
|
||||
|
||||
#ifndef __incremental_h__
|
||||
#define __incremental_h__
|
||||
|
||||
#include "invariant.h"
|
||||
#include "../render.h"
|
||||
#include "../transformation.h"
|
||||
#include "../image.h"
|
||||
#include "../point.h"
|
||||
|
||||
/*
|
||||
* Class for incremental renderers.
|
||||
*/
|
||||
|
||||
class incremental : public render {
|
||||
protected:
|
||||
image_weighted_avg *accum_image;
|
||||
invariant *inv;
|
||||
|
||||
/*
|
||||
* Set extents of image and weight according to a new image to be
|
||||
* merged. This function should remove only superfluous undefined
|
||||
* areas.
|
||||
*/
|
||||
|
||||
void set_extents_by_map(unsigned int frame_num, transformation t) {
|
||||
|
||||
assert (accum_image != NULL);
|
||||
|
||||
ale_pos extend_offset_i = accum_image->offset()[0];
|
||||
ale_pos extend_offset_j = accum_image->offset()[1];
|
||||
|
||||
int extend_top = 0;
|
||||
int extend_bottom = 0;
|
||||
int extend_left = 0;
|
||||
int extend_right = 0;
|
||||
|
||||
ale_pos zero = 0;
|
||||
ale_pos infinity = 1 / zero;
|
||||
|
||||
assert (!finite(infinity));
|
||||
assert (!isnan(infinity));
|
||||
assert (infinity > 0);
|
||||
|
||||
point min, max;
|
||||
|
||||
min[0] = min[1] = infinity;
|
||||
max[0] = max[1] = -infinity;
|
||||
|
||||
for (unsigned int i = 0; i < t.unscaled_height(); i++)
|
||||
for (unsigned int j = 0; j < t.unscaled_width(); j++) {
|
||||
|
||||
if (is_excluded_f(i, j, frame_num))
|
||||
continue;
|
||||
|
||||
point p = t.transform_unscaled(point(i, j));
|
||||
|
||||
if (is_excluded_r(accum_image->offset(), p, frame_num))
|
||||
continue;
|
||||
|
||||
if (p[0] < min[0]) {
|
||||
min[0] = p[0];
|
||||
}
|
||||
if (p[0] > max[0]) {
|
||||
max[0] = p[0];
|
||||
}
|
||||
if (p[1] < min[1]) {
|
||||
min[1] = p[1];
|
||||
}
|
||||
if (p[1] > max[1]) {
|
||||
max[1] = p[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (!finite(max[0])
|
||||
|| !finite(max[1])
|
||||
|| !finite(min[0])
|
||||
|| !finite(min[1]))
|
||||
return;
|
||||
|
||||
extend_top = (int) ceil(extend_offset_i - floor(min[0]));
|
||||
extend_left = (int) ceil(extend_offset_j - floor(min[1]));
|
||||
extend_bottom = (int) ceil(ceil(max[0]) - (ale_pos) (accum_image->height() - 1 + extend_offset_i));
|
||||
extend_right = (int) ceil(ceil(max[1]) - (ale_pos) (accum_image->width() - 1 + extend_offset_j));
|
||||
|
||||
accum_image->_extend(extend_top, extend_bottom,
|
||||
extend_left, extend_right);
|
||||
}
|
||||
|
||||
void increase_extents_by_map(unsigned int frame_num, transformation t) {
|
||||
|
||||
assert (accum_image != NULL);
|
||||
|
||||
ale_pos extend_offset_i = accum_image->offset()[0];
|
||||
ale_pos extend_offset_j = accum_image->offset()[1];
|
||||
|
||||
int extend_top = 0;
|
||||
int extend_bottom = 0;
|
||||
int extend_left = 0;
|
||||
int extend_right = 0;
|
||||
|
||||
double zero = 0;
|
||||
double infinity = 1 / zero;
|
||||
|
||||
assert (!finite(infinity));
|
||||
assert (!isnan(infinity));
|
||||
assert (infinity > 0);
|
||||
|
||||
point min, max;
|
||||
|
||||
min[0] = min[1] = infinity;
|
||||
max[0] = max[1] = -infinity;
|
||||
|
||||
for (unsigned int i = 0; i < t.unscaled_height(); i++)
|
||||
for (unsigned int j = 0; j < t.unscaled_width(); j++) {
|
||||
|
||||
if (is_excluded_f(i, j, frame_num))
|
||||
continue;
|
||||
|
||||
point p = t.transform_unscaled(point(i, j));
|
||||
|
||||
if (is_excluded_r(point(0, 0), p, frame_num))
|
||||
continue;
|
||||
|
||||
if (p[0] < min[0]) {
|
||||
min[0] = p[0];
|
||||
}
|
||||
if (p[0] > max[0]) {
|
||||
max[0] = p[0];
|
||||
}
|
||||
if (p[1] < min[1]) {
|
||||
min[1] = p[1];
|
||||
}
|
||||
if (p[1] > max[1]) {
|
||||
max[1] = p[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (!finite(max[0])
|
||||
|| !finite(max[1])
|
||||
|| !finite(min[0])
|
||||
|| !finite(min[1]))
|
||||
return;
|
||||
|
||||
if (ceil(min[0]) < extend_offset_i)
|
||||
extend_top = (int) ceil(extend_offset_i - floor(min[0]));
|
||||
if (ceil(min[1]) < extend_offset_j)
|
||||
extend_left = (int) ceil(extend_offset_j - floor(min[1]));
|
||||
if (floor(max[0]) > accum_image->height() - 1 + extend_offset_i)
|
||||
extend_bottom = (int) ceil(ceil(max[0]) - (ale_pos) (accum_image->height() - 1 + extend_offset_i));
|
||||
if (floor(max[1]) > accum_image->width() - 1 + extend_offset_j)
|
||||
extend_right = (int) ceil(ceil(max[1]) - (ale_pos) (accum_image->width() - 1 + extend_offset_j));
|
||||
|
||||
accum_image->_extend(extend_top, extend_bottom,
|
||||
extend_left, extend_right);
|
||||
}
|
||||
|
||||
/*
|
||||
* Merge operation for a single pixel in the accumulated image.
|
||||
*/
|
||||
void _merge_pixel(int frame, const image *delta, transformation t, int i, int j, const filter::ssfe *_ssfe) {
|
||||
|
||||
if (_ssfe->ex_is_honored() && is_excluded_r(i, j, frame))
|
||||
return;
|
||||
|
||||
if (accum_image->accumulate_norender(i, j))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Pixel value to be merged, and the associated
|
||||
* confidence
|
||||
*/
|
||||
|
||||
pixel value, confidence;
|
||||
|
||||
if (exposure::get_confidence() != 0) {
|
||||
_ssfe->filtered(i, j, frame, &value, &confidence, ((pixel) accum_image->get_pixel(i, j)), accum_image->get_weights()->get_pixel(i, j));
|
||||
} else {
|
||||
_ssfe->filtered(i, j, frame, &value, &confidence);
|
||||
}
|
||||
|
||||
accum_image->accumulate(i, j, frame, value, confidence);
|
||||
}
|
||||
|
||||
/*
|
||||
* Merge part of a delta frame with part of the accumulated image using
|
||||
* the specified transformation.
|
||||
*/
|
||||
|
||||
class merge : public thread::decompose_domain {
|
||||
incremental *instance;
|
||||
int frame;
|
||||
const image *delta;
|
||||
transformation t;
|
||||
invariant *inv;
|
||||
image_weighted_avg *accum_image;
|
||||
protected:
|
||||
void prepare_subdomains(unsigned int N) {
|
||||
ale_pos_disable_casting();
|
||||
ale_real_disable_casting();
|
||||
ale_accum_disable_casting();
|
||||
}
|
||||
void subdomain_algorithm(unsigned int thread,
|
||||
int i_min, int i_max, int j_min, int j_max) {
|
||||
|
||||
point offset = accum_image->offset();
|
||||
|
||||
assert (accum_image != NULL);
|
||||
assert (delta != NULL);
|
||||
|
||||
const filter::ssfe *_ssfe = inv->ssfe();
|
||||
|
||||
for (int i = i_min; i < i_max; i++)
|
||||
for (int j = j_min; j < j_max; j++) {
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* This is untested, but it should work, and is less
|
||||
* verbose than what follows.
|
||||
*/
|
||||
|
||||
instance->_merge_pixel(frame, delta, t, i, j, _ssfe);
|
||||
#else
|
||||
|
||||
if (_ssfe->ex_is_honored() && instance->is_excluded_r(i, j, frame))
|
||||
continue;
|
||||
|
||||
if (accum_image->accumulate_norender(i, j))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Pixel value to be merged, and the associated
|
||||
* confidence
|
||||
*/
|
||||
|
||||
pixel value, confidence;
|
||||
|
||||
if (exposure::get_confidence() != 0) {
|
||||
_ssfe->filtered(i, j, frame, &value, &confidence,
|
||||
((pixel) accum_image->get_pixel(i, j)),
|
||||
accum_image->get_weights()->get_pixel(i, j));
|
||||
} else {
|
||||
_ssfe->filtered(i, j, frame, &value, &confidence);
|
||||
}
|
||||
|
||||
accum_image->accumulate(i, j, frame, value, confidence);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
void finish_subdomains(unsigned int N) {
|
||||
ale_pos_enable_casting();
|
||||
ale_real_enable_casting();
|
||||
ale_accum_enable_casting();
|
||||
}
|
||||
|
||||
public:
|
||||
merge(incremental *_instance,
|
||||
int _frame,
|
||||
const image *_delta,
|
||||
transformation _t) : decompose_domain(0, _instance->accum_image->height(),
|
||||
0, _instance->accum_image->width()),
|
||||
t(_t) {
|
||||
|
||||
instance = _instance;
|
||||
frame = _frame;
|
||||
delta = _delta;
|
||||
t = _t;
|
||||
|
||||
inv = instance->inv;
|
||||
accum_image = instance->accum_image;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
_merge(int frame, const image *delta, transformation t) {
|
||||
|
||||
ui::get()->d2_incremental_start();
|
||||
|
||||
point offset = accum_image->offset();
|
||||
|
||||
assert (accum_image != NULL);
|
||||
assert (delta != NULL);
|
||||
|
||||
const filter::ssfe *_ssfe = inv->ssfe();
|
||||
|
||||
_ssfe->set_parameters(t, delta, offset);
|
||||
|
||||
merge m(this, frame, delta, t);
|
||||
m.run();
|
||||
|
||||
ui::get()->d2_incremental_stop();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
incremental(invariant *inv) {
|
||||
this->inv = inv;
|
||||
accum_image = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invariant
|
||||
*/
|
||||
const invariant *get_invariant() const {
|
||||
return inv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Result of rendering.
|
||||
*/
|
||||
|
||||
virtual const image *get_image() const {
|
||||
assert (accum_image != NULL);
|
||||
return accum_image;
|
||||
}
|
||||
|
||||
/*
|
||||
* Definition map. Unit-depth image whose pixels are nonzero where
|
||||
* the image is defined.
|
||||
*/
|
||||
|
||||
virtual const image *get_defined() const {
|
||||
assert (accum_image != NULL);
|
||||
return accum_image->get_weights();
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the current rendering step.
|
||||
*/
|
||||
virtual void step() {
|
||||
|
||||
/*
|
||||
* Dynamic invariants are not incrementally updated.
|
||||
*/
|
||||
if (inv->ssfe()->get_scaled_filter()->is_dynamic()) {
|
||||
/*
|
||||
* Create a trivial image for the case where there is
|
||||
* no chain suffix.
|
||||
*/
|
||||
if (accum_image == NULL)
|
||||
accum_image = new image_weighted_simple(1, 1, 3, inv);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
assert (get_step() >= -1);
|
||||
if (get_step() == 0) {
|
||||
transformation t = align::of(0);
|
||||
|
||||
const image *im = image_rw::open(0);
|
||||
|
||||
ui::get()->rendering();
|
||||
if (inv->is_median())
|
||||
accum_image = new image_weighted_median(1, 1, 3);
|
||||
else
|
||||
accum_image = new image_weighted_simple(1, 1, 3, inv);
|
||||
|
||||
set_extents_by_map(0, t);
|
||||
|
||||
_merge(0, im, t);
|
||||
|
||||
image_rw::close(0);
|
||||
} else if (align::match(get_step())) {
|
||||
transformation t = align::of(get_step());
|
||||
ui::get()->rendering();
|
||||
if (is_extend())
|
||||
increase_extents_by_map(get_step(), t);
|
||||
const image *im = image_rw::open(get_step());
|
||||
_merge(get_step(), im, t);
|
||||
image_rw::close(get_step());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual void init_point_renderer(unsigned int h, unsigned int w, unsigned int d) {
|
||||
assert(accum_image == NULL);
|
||||
|
||||
if (inv->is_median())
|
||||
accum_image = new image_weighted_median(h, w, d);
|
||||
else
|
||||
accum_image = new image_weighted_simple(h, w, d, inv);
|
||||
|
||||
assert(accum_image);
|
||||
}
|
||||
|
||||
virtual void point_render(unsigned int i, unsigned int j, unsigned int f, transformation t) {
|
||||
const image *im = d2::image_rw::get_open(f);
|
||||
|
||||
const filter::ssfe *_ssfe = inv->ssfe();
|
||||
|
||||
_ssfe->set_parameters(t, im, accum_image->offset());
|
||||
_merge_pixel(f, im, t, i, j, _ssfe);
|
||||
}
|
||||
|
||||
virtual void finish_point_rendering() {
|
||||
return;
|
||||
}
|
||||
|
||||
void free_memory() {
|
||||
delete accum_image;
|
||||
accum_image = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
117
d2/render/invariant.h
Normal file
117
d2/render/invariant.h
Normal file
@@ -0,0 +1,117 @@
|
||||
// Copyright 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
|
||||
*/
|
||||
|
||||
#ifndef __invariant_h__
|
||||
#define __invariant_h__
|
||||
|
||||
#include "../filter.h"
|
||||
|
||||
/*
|
||||
* Class for incremental renderer invariants.
|
||||
*/
|
||||
|
||||
#define min 0
|
||||
#define max 1
|
||||
#define avg 2
|
||||
#define first 3
|
||||
#define last 4
|
||||
#define median 5
|
||||
#define avgf 6
|
||||
|
||||
class invariant {
|
||||
public:
|
||||
int type;
|
||||
double type_param;
|
||||
filter::ssfe *s;
|
||||
|
||||
invariant(filter::ssfe *s) {
|
||||
this->s = s;
|
||||
type = 2;
|
||||
type_param = 0;
|
||||
}
|
||||
int equals(const invariant *i) const {
|
||||
return (i->type == type
|
||||
&& i->type_param == type_param
|
||||
&& s->equals(i->ssfe()));
|
||||
}
|
||||
const filter::ssfe *ssfe() const {
|
||||
return s;
|
||||
}
|
||||
int is_max() const {
|
||||
return type == max;
|
||||
}
|
||||
int is_min() const {
|
||||
return type == min;
|
||||
}
|
||||
int is_avg() const {
|
||||
return type == avg;
|
||||
}
|
||||
int is_avgf() const {
|
||||
return type == avgf;
|
||||
}
|
||||
int is_avgx() const {
|
||||
return (type == avg || type == avgf);
|
||||
}
|
||||
int is_first() const {
|
||||
return type == first;
|
||||
}
|
||||
int is_last() const {
|
||||
return type == last;
|
||||
}
|
||||
int is_median() const {
|
||||
return type == median;
|
||||
}
|
||||
void set_max() {
|
||||
type = max;
|
||||
}
|
||||
void set_min() {
|
||||
type = min;
|
||||
}
|
||||
void set_avg() {
|
||||
type = avg;
|
||||
}
|
||||
void set_avgf(double p) {
|
||||
type = avgf;
|
||||
type_param = p;
|
||||
}
|
||||
void set_first() {
|
||||
type = first;
|
||||
}
|
||||
void set_last() {
|
||||
type = last;
|
||||
}
|
||||
void set_median() {
|
||||
type = median;
|
||||
}
|
||||
double get_param() {
|
||||
return type_param;
|
||||
}
|
||||
~invariant() {
|
||||
delete s;
|
||||
}
|
||||
};
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
#undef avg
|
||||
#undef first
|
||||
#undef last
|
||||
|
||||
#endif
|
||||
1388
d2/render/ipc.h
Normal file
1388
d2/render/ipc.h
Normal file
File diff suppressed because it is too large
Load Diff
329
d2/render/psf/backprojector.h
Normal file
329
d2/render/psf/backprojector.h
Normal file
@@ -0,0 +1,329 @@
|
||||
// Copyright 2003 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
|
||||
*/
|
||||
|
||||
#ifndef __backprojector_h__
|
||||
#define __backprojector_h__
|
||||
|
||||
#include "../../point.h"
|
||||
#include "rasterizer.h"
|
||||
#include "raster.h"
|
||||
|
||||
/*
|
||||
* Backprojector for rasterized PSFs.
|
||||
*
|
||||
* This class converts a rasterized PSF into a rasterized backprojection array.
|
||||
*/
|
||||
|
||||
class backprojector : public raster {
|
||||
raster *input;
|
||||
public:
|
||||
unsigned int varieties() const {
|
||||
return input->varieties();
|
||||
}
|
||||
|
||||
unsigned int select(unsigned int i, unsigned int j) const {
|
||||
return input->select(i, j);
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
* Backprojection for the Irani-Peleg renderer
|
||||
*
|
||||
* Applying a special case of theorem 4.1 of the source paper by Irani
|
||||
* and Peleg, convergence can be assured for a single image, with
|
||||
* uniform PSF, no change in sampling rate, and taking the normalizing
|
||||
* divisor c == 1, if H[psf](f)H[aux](f) is real and within the open
|
||||
* interval (0, 2), where H[psf] is the frequency-domain representation
|
||||
* of the point-spread function and H[aux] is the frequency-domain
|
||||
* representation of the backprojection kernel. We can guarantee that
|
||||
* H[psf](f)H[aux](f) is real by making H[aux](f) == k(f)H[psf](f)*,
|
||||
* where k is a real function and '*' indicates the complex conjugate.
|
||||
* If k(f) is equal to 1 for all f, then this is equivalent to the
|
||||
* condition h[aux](x) == h[psf](-x), where h[] are the time domain
|
||||
* representations of the respective functions. Since this negation
|
||||
* of position is implicitly performed in ipc.h, we don't perform it
|
||||
* here.
|
||||
*
|
||||
* However, to ensure that the range (0, 2) is satisfied, it may be
|
||||
* necessary for k(f) to assume a value other than 1. We choose a
|
||||
* constant function k, in accordance with the source paper's
|
||||
* normalizing divisor c, but this is not required. We use FFTW
|
||||
* when available, but it is likely that common cases will not observe
|
||||
* any speed improvement.
|
||||
*/
|
||||
void initialize_response_array(ale_real *response_array) {
|
||||
int cols = _filter_dim_j;
|
||||
int rows = _filter_dim_i;
|
||||
|
||||
#ifdef USE_FFTW
|
||||
fftw_complex *inout;
|
||||
fftw_plan p_forward;
|
||||
fftw_plan p_backward;
|
||||
|
||||
inout = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * cols * rows);
|
||||
|
||||
p_forward = fftw_plan_dft_2d(rows, cols, inout, inout, FFTW_FORWARD, FFTW_ESTIMATE);
|
||||
p_backward = fftw_plan_dft_2d(rows, cols, inout, inout, FFTW_BACKWARD, FFTW_ESTIMATE);
|
||||
|
||||
for (int k = 0; k < 3; k++) {
|
||||
|
||||
for (int i = 0; i < rows * cols; i++) {
|
||||
/*
|
||||
* Write the values to the FFTW input array,
|
||||
* shifting by (rows * cols - 1) / 2 in order
|
||||
* to accommodate the implicit translation.
|
||||
*/
|
||||
|
||||
inout[i][0] = response_array[((i + (rows * cols - 1)/2) * 3 + k)
|
||||
% (rows * cols * 3)];
|
||||
inout[i][1] = 0;
|
||||
}
|
||||
|
||||
fftw_execute(p_forward);
|
||||
|
||||
/*
|
||||
* Find the frequency with maximum magnitude, then
|
||||
* adjust this according to the sampling rate
|
||||
* (filter resolution).
|
||||
*/
|
||||
|
||||
ale_real max_magnitude = 0;
|
||||
|
||||
for (int i = 0; i < rows * cols; i++) {
|
||||
ale_real input_magnitude;
|
||||
|
||||
input_magnitude = sqrt(pow(inout[i][0], 2) + pow(inout[i][1], 2));
|
||||
if (input_magnitude > max_magnitude)
|
||||
max_magnitude = input_magnitude;
|
||||
}
|
||||
|
||||
max_magnitude *= (4 * _height * _width) / (rows * cols);
|
||||
|
||||
/*
|
||||
* Scale the magnitude of all of the frequencies and perform
|
||||
* conjugation.
|
||||
*/
|
||||
|
||||
for (int i = 0; i < rows * cols; i++) {
|
||||
|
||||
/*
|
||||
* Adjust the magnitude
|
||||
*
|
||||
* Note: since we're currently dividing all frequencies
|
||||
* by the same value, there's no need to divide in the
|
||||
* frequency domain. However, we might want to do
|
||||
* something else in the future, so it might be
|
||||
* good to leave the code like this for now.
|
||||
*/
|
||||
|
||||
inout[i][0] = inout[i][0] * pow(0.9 / max_magnitude, 2);
|
||||
inout[i][1] = inout[i][1] * pow(0.9 / max_magnitude, 2);
|
||||
|
||||
/*
|
||||
* Perform conjugation
|
||||
*
|
||||
* Note: conjugation is implicit in ipc.h, so we omit the
|
||||
* step here.
|
||||
*/
|
||||
|
||||
/* inout[i][1] = -inout[i][1]; */
|
||||
}
|
||||
|
||||
fftw_execute(p_backward);
|
||||
|
||||
for (int i = 0; i < rows * cols; i++) {
|
||||
/*
|
||||
* Read the values from the FFTW output array,
|
||||
* shifting by (rows * cols - 1) / 2 in order
|
||||
* to accommodate the implicit translation.
|
||||
*/
|
||||
|
||||
response_array[((i + (rows * cols - 1)/2) * 3 + k)
|
||||
% (rows * cols * 3)]
|
||||
= inout[i][0]
|
||||
/ (rows * cols);
|
||||
}
|
||||
}
|
||||
|
||||
fftw_destroy_plan(p_forward);
|
||||
fftw_destroy_plan(p_backward);
|
||||
fftw_free(inout);
|
||||
#else
|
||||
|
||||
for (int k = 0; k < 3; k++) {
|
||||
ale_real *real1 = (ale_real *) calloc(rows * cols, sizeof(ale_real));
|
||||
ale_real *imag1 = (ale_real *) calloc(rows * cols, sizeof(ale_real));
|
||||
ale_real *real2 = (ale_real *) calloc(rows * cols, sizeof(ale_real));
|
||||
ale_real *imag2 = (ale_real *) calloc(rows * cols, sizeof(ale_real));
|
||||
|
||||
assert (real1 && imag1 && real2 && imag2);
|
||||
|
||||
if (!(real1 && imag1 && real2 && imag2)) {
|
||||
fprintf(stderr, "Unable to allocate memory in backprojector.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate frequencies. We implement the equations indicated by
|
||||
* the FFTW3 info page (section "What FFTW Really Computes").
|
||||
*/
|
||||
|
||||
for (int i = 0; i < rows; i++)
|
||||
for (int j = 0; j < cols; j++)
|
||||
for (int jj = 0; jj < cols; jj++) {
|
||||
real1[i * cols + j] += response_array[((i * cols + jj +
|
||||
(rows * cols - 1)/2) * 3 + k)
|
||||
% (rows * cols * 3)]
|
||||
* (ale_real) cos((-2 * M_PI * j * jj) / cols);
|
||||
imag1[i * cols + j] += response_array[((i * cols + jj +
|
||||
(rows * cols - 1)/2) * 3 + k)
|
||||
% (rows * cols * 3)]
|
||||
* (ale_real) sin((-2 * M_PI * j * jj) / cols);
|
||||
}
|
||||
|
||||
for (int i = 0; i < rows; i++)
|
||||
for (int j = 0; j < cols; j++)
|
||||
for (int ii = 0; ii < rows; ii++) {
|
||||
real2[i * cols + j] += real1[ii * cols + j]
|
||||
* (ale_real) cos((-2 * M_PI * i * ii) / rows)
|
||||
- imag1[ii * cols + j]
|
||||
* (ale_real) sin((-2 * M_PI * i * ii) / rows);
|
||||
imag2[i * cols + j] += real1[ii * cols + j]
|
||||
* (ale_real) sin((-2 * M_PI * i * ii) / rows)
|
||||
+ imag1[ii * cols + j]
|
||||
* (ale_real) cos((-2 * M_PI * i * ii) / rows);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the frequency with maximum magnitude, then
|
||||
* adjust this according to the sampling rate
|
||||
* (filter resolution).
|
||||
*/
|
||||
|
||||
ale_real max_magnitude = 0;
|
||||
|
||||
for (int i = 0; i < rows * cols; i++) {
|
||||
ale_real input_magnitude;
|
||||
|
||||
input_magnitude = sqrt(pow(real2[i], 2) + pow(imag2[i], 2));
|
||||
if (input_magnitude > max_magnitude)
|
||||
max_magnitude = input_magnitude;
|
||||
}
|
||||
|
||||
max_magnitude *= (4 * _height * _width) / (rows * cols);
|
||||
|
||||
for (int i = 0; i < rows * cols; i++)
|
||||
response_array[i * 3 + k] *= pow(0.9 / max_magnitude, 2);
|
||||
|
||||
free(real1);
|
||||
free(imag1);
|
||||
free(real2);
|
||||
free(imag2);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
backprojector (raster *input) {
|
||||
this->input = input;
|
||||
|
||||
_height = -input->min_i();
|
||||
assert (input->max_i() == _height);
|
||||
|
||||
_width = -input->min_j();
|
||||
assert (input->max_j() == _width);
|
||||
|
||||
/*
|
||||
* The element structure matches that of the input.
|
||||
*/
|
||||
|
||||
_filter_dim_i = input->max_elem_i();
|
||||
_filter_dim_j = input->max_elem_j();
|
||||
|
||||
/*
|
||||
* Ensure that the array has an odd number of elements in each
|
||||
* direction. This allows us to move the center to the right
|
||||
* place when using a discrete FT.
|
||||
*/
|
||||
|
||||
assert (_filter_dim_i % 2 == 1);
|
||||
assert (_filter_dim_j % 2 == 1);
|
||||
|
||||
/*
|
||||
* Determine the number of arrays to create.
|
||||
*/
|
||||
|
||||
num_arrays = input->varieties();
|
||||
|
||||
/*
|
||||
* Create arrays
|
||||
*/
|
||||
|
||||
response_arrays = (ale_real **)malloc(num_arrays * sizeof(ale_real *));
|
||||
|
||||
if (!response_arrays) {
|
||||
fprintf(stderr, "Could not allocate in backprojector.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (unsigned int n = 0; n < num_arrays; n++) {
|
||||
response_arrays[n] = (ale_real *)malloc(_filter_dim_i * _filter_dim_j * 3
|
||||
* sizeof(ale_real));
|
||||
|
||||
if (!response_arrays[n]) {
|
||||
fprintf(stderr, "Could not allocate in backprojector.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < _filter_dim_i; i++)
|
||||
for (unsigned int j = 0; j < _filter_dim_j; j++)
|
||||
for (unsigned int k = 0; k < 3; k++) {
|
||||
response_arrays[n][i * _filter_dim_j * 3 + j * 3 + k]
|
||||
= input->element(n, i, j, k);
|
||||
}
|
||||
|
||||
initialize_response_array(response_arrays[n]);
|
||||
}
|
||||
|
||||
#if 0
|
||||
avg_response = (ale_real *)malloc(_filter_dim_i * _filter_dim_j * 3
|
||||
* sizeof(ale_real));
|
||||
|
||||
if (!avg_response) {
|
||||
fprintf(stderr, "Could not allocate in backprojector.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < _filter_dim_i; i++)
|
||||
for (unsigned int j = 0; j < _filter_dim_j; j++)
|
||||
for (unsigned int k = 0; k < 3; k++) {
|
||||
avg_response[i * _filter_dim_j * 3 + j * 3 + k]
|
||||
= input->element(i, j, k);
|
||||
}
|
||||
|
||||
initialize_response_array(avg_response);
|
||||
#endif
|
||||
|
||||
compute_integrals();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
82
d2/render/psf/box.h
Normal file
82
d2/render/psf/box.h
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright 2003 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
|
||||
*/
|
||||
|
||||
#ifndef __psf_box_h__
|
||||
#define __psf_box_h__
|
||||
|
||||
#include "../../point.h"
|
||||
#include "psf.h"
|
||||
|
||||
/*
|
||||
* Point-spread function module.
|
||||
*
|
||||
* This module implements the box filter.
|
||||
*/
|
||||
|
||||
class box : public psf {
|
||||
ale_real _radius;
|
||||
public:
|
||||
|
||||
/*
|
||||
* The following four functions indicate filter boundaries. Filter
|
||||
* support may include everything up to and including the boundaries
|
||||
* specified here.
|
||||
*/
|
||||
ale_real min_i() const { return -_radius; }
|
||||
ale_real max_i() const { return _radius; }
|
||||
ale_real min_j() const { return -_radius; }
|
||||
ale_real max_j() const { return _radius; }
|
||||
|
||||
/*
|
||||
* Response function
|
||||
*
|
||||
* Get the response to the rectangle bounded by (top, bot, lef, rig).
|
||||
* This function must correctly handle points which fall outside of the
|
||||
* filter support. The variety the responding pixel is provided, in
|
||||
* case response is not uniform for all pixels (e.g. some sensor arrays
|
||||
* stagger red, green, and blue sensors).
|
||||
*/
|
||||
psf_result operator()(ale_real top, ale_real bot, ale_real lef, ale_real rig,
|
||||
unsigned int variety) const {
|
||||
|
||||
psf_result result;
|
||||
|
||||
if (top < min_i())
|
||||
top = min_i();
|
||||
if (bot > max_i())
|
||||
bot = max_i();
|
||||
if (lef < min_j())
|
||||
lef = min_j();
|
||||
if (rig > max_j())
|
||||
rig = max_j();
|
||||
|
||||
if (bot > top && rig > lef)
|
||||
for (int k = 0; k < 3; k++)
|
||||
result.matrix(k, k) = (bot - top) * (rig - lef) / (4 * _radius * _radius);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
box(ale_real radius) {
|
||||
_radius = radius;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
85
d2/render/psf/circle.h
Normal file
85
d2/render/psf/circle.h
Normal file
@@ -0,0 +1,85 @@
|
||||
// Copyright 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
|
||||
*/
|
||||
|
||||
#ifndef __psf_circle_h__
|
||||
#define __psf_circle_h__
|
||||
|
||||
#include "../../point.h"
|
||||
#include "psf.h"
|
||||
|
||||
/*
|
||||
* Point-spread function module.
|
||||
*
|
||||
* This module implements a circular filter.
|
||||
*/
|
||||
|
||||
class circle : public psf {
|
||||
ale_real _radius;
|
||||
public:
|
||||
|
||||
/*
|
||||
* The following four functions indicate filter boundaries. Filter
|
||||
* support may include everything up to and including the boundaries
|
||||
* specified here.
|
||||
*/
|
||||
ale_real min_i() const { return -_radius; }
|
||||
ale_real max_i() const { return _radius; }
|
||||
ale_real min_j() const { return -_radius; }
|
||||
ale_real max_j() const { return _radius; }
|
||||
|
||||
/*
|
||||
* Response function
|
||||
*
|
||||
* Get the response to the rectangle bounded by (top, bot, lef, rig).
|
||||
* This function must correctly handle points which fall outside of the
|
||||
* filter support. The variety of the responding pixel is provided, in
|
||||
* case response is not uniform for all pixels (e.g. some sensor arrays
|
||||
* stagger red, green, and blue sensors).
|
||||
*/
|
||||
psf_result operator()(ale_real top, ale_real bot, ale_real lef, ale_real rig,
|
||||
unsigned int variety) const {
|
||||
|
||||
psf_result result;
|
||||
|
||||
for (int k = 0; k < 3; k++)
|
||||
result.matrix(k, k) = 0;
|
||||
|
||||
ale_real total = (bot - top) * (rig - lef) / (M_PI * _radius * _radius);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
for (int j = 0; j < 10; j++) {
|
||||
ale_real one_half = 1 / (ale_real) 2;
|
||||
ale_real r = pow(top + (bot - top) * ((i + one_half) / (ale_real) 10), 2)
|
||||
+ pow(lef + (rig - lef) * ((j + one_half) / (ale_real) 10), 2);
|
||||
if (r < _radius * _radius)
|
||||
for (int k = 0; k < 3; k++)
|
||||
result.matrix(k, k) += (total / (ale_real) 100);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
circle(ale_real radius) {
|
||||
_radius = radius;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
145
d2/render/psf/convolution.h
Normal file
145
d2/render/psf/convolution.h
Normal file
@@ -0,0 +1,145 @@
|
||||
// Copyright 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
|
||||
*/
|
||||
|
||||
#ifndef __psf_convolution_h__
|
||||
#define __psf_convolution_h__
|
||||
|
||||
#include "../../point.h"
|
||||
#include "psf.h"
|
||||
|
||||
/*
|
||||
* XXX: This doesn't work yet.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Point-spread function module.
|
||||
*
|
||||
* This module implements the convolution (f1 * f2) of point-spread functions f1 and
|
||||
* f2.
|
||||
*/
|
||||
|
||||
class convolution : public psf {
|
||||
ale_pos _radius;
|
||||
psf *f1, *f2;
|
||||
ale_real _min_i, _max_i, _min_j, _max_j;
|
||||
|
||||
public:
|
||||
/*
|
||||
* The following four functions indicate filter boundaries. Filter
|
||||
* support may include everything up to and including the boundaries
|
||||
* specified here.
|
||||
*/
|
||||
ale_real min_i() const { return _min_i; }
|
||||
ale_real max_i() const { return _max_i; }
|
||||
ale_real min_j() const { return _min_j; }
|
||||
ale_real max_j() const { return _max_j; }
|
||||
|
||||
/*
|
||||
* Get the number of varieties supported by this PSF. These usually
|
||||
* correspond to different points in the sensor array.
|
||||
*/
|
||||
virtual unsigned int varieties() {
|
||||
return f1->varieties() * f2->varieties();
|
||||
}
|
||||
|
||||
/*
|
||||
* Select the variety appropriate for a given position in the sensor
|
||||
* array.
|
||||
*/
|
||||
virtual unsigned int select(unsigned int i, unsigned int j) {
|
||||
return (f1->select(i, j) * f2->varieties() + f2->select(i, j));
|
||||
}
|
||||
|
||||
/*
|
||||
* Response function
|
||||
*
|
||||
* Get the response to the rectangle bounded by (top, bot, lef, rig).
|
||||
* This function must correctly handle points which fall outside of the
|
||||
* filter support. The variety of the responding pixel is provided, in
|
||||
* case response is not uniform for all pixels (e.g. some sensor arrays
|
||||
* stagger red, green, and blue sensors).
|
||||
*/
|
||||
psf_result operator()(ale_real top, ale_real bot, ale_real lef, ale_real rig,
|
||||
unsigned int variety) const {
|
||||
psf_result result;
|
||||
psf_result r1, r2;
|
||||
|
||||
unsigned int v1 = variety / f2->varieties();
|
||||
unsigned int v2 = variety % f2->varieties();
|
||||
|
||||
/*
|
||||
* This code uses a rasterized approximation of the filters involved.
|
||||
*/
|
||||
|
||||
ale_real vertical_center = (top + bot) / 2;
|
||||
ale_real horizontal_center = (lef + rig) / 2;
|
||||
ale_real vertical_resolution = bot - top;
|
||||
ale_real horizontal_resolution = rig - lef;
|
||||
|
||||
if (!(vertical_resolution > 0
|
||||
&& horizontal_resolution > 0))
|
||||
return result; /* zero */
|
||||
|
||||
for (ale_real i = f1->min_i() + (vertical_resolution / 2);
|
||||
i < f1->max_i() - (vertical_resolution / 2);
|
||||
i += vertical_resolution)
|
||||
for (ale_real j = f1->min_j() + (horizontal_resolution / 2);
|
||||
j < f1->max_j() - (horizontal_resolution / 2);
|
||||
j += horizontal_resolution) {
|
||||
|
||||
ale_real t = i - (vertical_resolution / 2);
|
||||
ale_real b = i + (vertical_resolution / 2);
|
||||
ale_real l = j - (horizontal_resolution / 2);
|
||||
ale_real r = j + (horizontal_resolution / 2);
|
||||
ale_real vc = vertical_center;
|
||||
ale_real hc = horizontal_center;
|
||||
|
||||
r1 = (*f1)(t, b, l, r, v1);
|
||||
r2 = (*f2)(vc - b, vc - t, hc - r, hc - l, v2);
|
||||
|
||||
for (int k1 = 0; k1 < 3; k1++)
|
||||
for (int k2 = 0; k2 < 3; k2++)
|
||||
result.set_matrix(k1, k2, result.get_matrix(k1, k2)
|
||||
+ r1.get_matrix(k1, k2)
|
||||
* r2.get_matrix(k1, k2));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
convolution(psf *f1, psf *f2) {
|
||||
|
||||
this->f1 = f1;
|
||||
this->f2 = f2;
|
||||
|
||||
/*
|
||||
* XXX: I'm fairly sure that this is correct for filters with
|
||||
* zero-centered bounding boxes, and I _think_ it's correct for
|
||||
* other filters also, but I haven't formally proven this.
|
||||
*/
|
||||
|
||||
_min_i = f1->min_i() + f2->min_i();
|
||||
_min_j = f1->min_j() + f2->min_j();
|
||||
_max_i = f1->max_i() + f2->max_i();
|
||||
_max_j = f1->max_j() + f2->max_j();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
127
d2/render/psf/gauss.h
Normal file
127
d2/render/psf/gauss.h
Normal file
@@ -0,0 +1,127 @@
|
||||
// code by HJ Hornbeck, based on code copyright 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
|
||||
*/
|
||||
|
||||
#ifndef __psf_gauss_h__
|
||||
#define __psf_gauss_h__
|
||||
|
||||
#include "../../point.h"
|
||||
#include "psf.h"
|
||||
|
||||
/*
|
||||
* A Gaussian point-spread function. It's aimed at duplicating the most common type
|
||||
* of blurring in many optical systems. It is uniform across the entire image, so
|
||||
* it can't correct for poor focus at the edges.
|
||||
*/
|
||||
|
||||
#define D2_GAUSS_CUTOFF ((ale_real) 2.0)
|
||||
|
||||
class gauss : public psf {
|
||||
ale_real sigma; // radius, in pixels per standard deviation
|
||||
|
||||
/*
|
||||
* Disabled the following definition because some compilers may not be
|
||||
* able to handle static const definitions within a class (and because
|
||||
* the C++ specification may disallow such for non-integral types,
|
||||
* anyway).
|
||||
*
|
||||
* -- dhilvert@auricle.dyndns.org 18-May-2007
|
||||
*/
|
||||
|
||||
// static const ale_pos cutoff = 2; // standard deviations before we cut off
|
||||
|
||||
// helper variables
|
||||
ale_real radius;
|
||||
ale_real sigma_premult;
|
||||
public:
|
||||
|
||||
/*
|
||||
* The following four functions indicate filter boundaries. Filter
|
||||
* support may include everything up to and including the boundaries
|
||||
* specified here.
|
||||
*/
|
||||
inline ale_real max_i() const { return radius; }
|
||||
inline ale_real min_i() const { return -max_i(); } // we're symmetrical, so it works!
|
||||
inline ale_real min_j() const { return -max_i(); }
|
||||
inline ale_real max_j() const { return max_i(); }
|
||||
|
||||
/*
|
||||
* Response function
|
||||
*
|
||||
* Get the response to the rectangle bounded by (top, bot, lef, rig).
|
||||
* This function must correctly handle points which fall outside of the
|
||||
* filter support. The variety of the responding pixel is provided, in
|
||||
* case response is not uniform for all pixels (e.g. some sensor arrays
|
||||
* stagger red, green, and blue sensors).
|
||||
*/
|
||||
psf_result operator()(ale_real top, ale_real bot, ale_real lef, ale_real rig,
|
||||
unsigned int variety) const {
|
||||
|
||||
psf_result result;
|
||||
|
||||
// calculate some needed values
|
||||
ale_pos area_premult = (bot - top) * (rig - lef) / 25;
|
||||
ale_real vert_step = (bot - top) / 4;
|
||||
ale_real horiz_step = (rig - lef) / 4;
|
||||
ale_real total = 0;
|
||||
|
||||
|
||||
// determine the final value by simple sampling:
|
||||
for (ale_real i = top; i < bot + vert_step / 2; i += vert_step)
|
||||
for (ale_real j = lef; j < rig + horiz_step / 2; j += horiz_step) {
|
||||
|
||||
// calculate radius for given sample
|
||||
ale_real r = sqrt( i*i + j*j );
|
||||
|
||||
if ( r < radius ) // calculate gaussian falloff
|
||||
total += exp( -r * r * sigma_premult ) ;
|
||||
// outside our radius? must be 0...
|
||||
}
|
||||
|
||||
// adjust for point sampling and area
|
||||
total *= area_premult;
|
||||
|
||||
// pre-fill the colour result matrix
|
||||
for (int k = 0; k < 3; k++)
|
||||
result.matrix(k, k) = 0;
|
||||
|
||||
// fill in the results
|
||||
for (int k = 0; k < 3; k++)
|
||||
result.matrix(k, k) = total;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Our glorious constructor
|
||||
*/
|
||||
gauss(ale_real sig) {
|
||||
|
||||
sigma = sig;
|
||||
|
||||
// fill in our helper variables
|
||||
radius = sigma * D2_GAUSS_CUTOFF;
|
||||
sigma_premult = 1 / (sigma * sigma);
|
||||
}
|
||||
};
|
||||
|
||||
#undef D2_GAUSS_CUTOFF
|
||||
|
||||
#endif
|
||||
|
||||
141
d2/render/psf/normalizer.h
Normal file
141
d2/render/psf/normalizer.h
Normal file
@@ -0,0 +1,141 @@
|
||||
// Copyright 2003 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
|
||||
*/
|
||||
|
||||
#ifndef __normalizer_h__
|
||||
#define __normalizer_h__
|
||||
|
||||
#include "../../point.h"
|
||||
#include "rasterizer.h"
|
||||
#include "raster.h"
|
||||
|
||||
/*
|
||||
* Normalizer for rasterized PSFs.
|
||||
*
|
||||
* This class normalizes a rasterized PSF.
|
||||
*/
|
||||
|
||||
class normalizer : public raster {
|
||||
raster *input;
|
||||
public:
|
||||
unsigned int varieties() const {
|
||||
return input->varieties();
|
||||
}
|
||||
|
||||
unsigned int select(unsigned int i, unsigned int j) const {
|
||||
return input->select(i, j);
|
||||
}
|
||||
|
||||
private:
|
||||
void initialize_response_array(ale_real *response_array) {
|
||||
pixel integral;
|
||||
|
||||
integral = integrate(response_array);
|
||||
|
||||
for (unsigned int i = 0; i < _filter_dim_i; i++)
|
||||
for (unsigned int j = 0; j < _filter_dim_j; j++)
|
||||
for (unsigned int k = 0; k < 3 ; k++)
|
||||
response_array[i * _filter_dim_j * 3 + j * 3 + k] /= integral[k];
|
||||
}
|
||||
|
||||
public:
|
||||
normalizer (raster *input) {
|
||||
this->input = input;
|
||||
|
||||
_height = -input->min_i();
|
||||
assert (input->max_i() == _height);
|
||||
|
||||
_width = -input->min_j();
|
||||
assert (input->max_j() == _width);
|
||||
|
||||
/*
|
||||
* The element structure matches that of the input.
|
||||
*/
|
||||
|
||||
_filter_dim_i = input->max_elem_i();
|
||||
_filter_dim_j = input->max_elem_j();
|
||||
|
||||
/*
|
||||
* Ensure that the array has an odd number of elements in each
|
||||
* direction. This allows us to move the center to the right
|
||||
* place when using FFTW.
|
||||
*/
|
||||
|
||||
assert (_filter_dim_i % 2 == 1);
|
||||
assert (_filter_dim_j % 2 == 1);
|
||||
|
||||
/*
|
||||
* Determine the number of arrays to create.
|
||||
*/
|
||||
|
||||
num_arrays = input->varieties();
|
||||
|
||||
/*
|
||||
* Create arrays
|
||||
*/
|
||||
|
||||
response_arrays = (ale_real **)malloc(num_arrays * sizeof(ale_real *));
|
||||
|
||||
if (!response_arrays) {
|
||||
fprintf(stderr, "Could not allocate in normalizer.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (unsigned int n = 0; n < num_arrays; n++) {
|
||||
response_arrays[n] = (ale_real *)malloc(_filter_dim_i * _filter_dim_j * 3
|
||||
* sizeof(ale_real));
|
||||
|
||||
if (!response_arrays[n]) {
|
||||
fprintf(stderr, "Could not allocate in normalizer.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < _filter_dim_i; i++)
|
||||
for (unsigned int j = 0; j < _filter_dim_j; j++)
|
||||
for (unsigned int k = 0; k < 3; k++) {
|
||||
response_arrays[n][i * _filter_dim_j * 3 + j * 3 + k]
|
||||
= input->element(n, i, j, k);
|
||||
}
|
||||
|
||||
initialize_response_array(response_arrays[n]);
|
||||
}
|
||||
|
||||
#if 0
|
||||
avg_response = (ale_real *)malloc(_filter_dim_i * _filter_dim_j * 3
|
||||
* sizeof(ale_real));
|
||||
|
||||
if (!avg_response) {
|
||||
fprintf(stderr, "Could not allocate in normalizer.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < _filter_dim_i; i++)
|
||||
for (unsigned int j = 0; j < _filter_dim_j; j++)
|
||||
for (unsigned int k = 0; k < 3; k++) {
|
||||
avg_response[i * _filter_dim_j * 3 + j * 3 + k]
|
||||
= input->element(i, j, k);
|
||||
}
|
||||
|
||||
initialize_response_array(avg_response);
|
||||
#endif
|
||||
compute_integrals();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
184
d2/render/psf/psf.h
Normal file
184
d2/render/psf/psf.h
Normal file
@@ -0,0 +1,184 @@
|
||||
// Copyright 2003 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
|
||||
*/
|
||||
|
||||
#ifndef __psf_h__
|
||||
#define __psf_h__
|
||||
|
||||
#include "../../point.h"
|
||||
|
||||
/*
|
||||
* Point-spread function module abstract base class.
|
||||
*/
|
||||
|
||||
class psf {
|
||||
public:
|
||||
/*
|
||||
* Result type is a matrix.
|
||||
*/
|
||||
class psf_result {
|
||||
friend class psf;
|
||||
protected:
|
||||
ale_real _matrix[3][3];
|
||||
|
||||
public:
|
||||
psf_result() {
|
||||
|
||||
/*
|
||||
* Simplified version -- diagonal matrix
|
||||
*/
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
_matrix[i][i] = 0;
|
||||
}
|
||||
|
||||
ale_real get_matrix(unsigned int i, unsigned int j) {
|
||||
assert (i < 3);
|
||||
assert (j < 3);
|
||||
|
||||
/*
|
||||
* Simplified version -- diagonal matrix
|
||||
*/
|
||||
|
||||
if (i != j)
|
||||
return 0;
|
||||
else
|
||||
return _matrix[i][j];
|
||||
}
|
||||
|
||||
void set_matrix(unsigned int i, unsigned int j, ale_real value) {
|
||||
assert (i < 3);
|
||||
assert (j < 3);
|
||||
|
||||
/*
|
||||
* Simplified version -- diagonal matrix
|
||||
*/
|
||||
|
||||
assert (i == j || value == 0);
|
||||
|
||||
_matrix[i][j] = value;
|
||||
}
|
||||
|
||||
ale_real &matrix(unsigned int i, unsigned int j) {
|
||||
assert (i < 3);
|
||||
assert (j < 3);
|
||||
|
||||
/*
|
||||
* Simplified version -- diagonal matrix
|
||||
*/
|
||||
|
||||
assert (i == j);
|
||||
|
||||
return _matrix[i][j];
|
||||
}
|
||||
|
||||
pixel operator()(pixel p) {
|
||||
|
||||
/*
|
||||
* Simplified version -- diagonal matrix
|
||||
*/
|
||||
|
||||
return pixel(_matrix[0][0] * p[0],
|
||||
_matrix[1][1] * p[1],
|
||||
_matrix[2][2] * p[2]);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Weights associated with the result
|
||||
*/
|
||||
pixel weight() {
|
||||
|
||||
/*
|
||||
* Simplified version -- diagonal matrix
|
||||
*/
|
||||
|
||||
return pixel(
|
||||
_matrix[0][0],
|
||||
_matrix[1][1],
|
||||
_matrix[2][2]);
|
||||
}
|
||||
|
||||
void operator*=(ale_real scale) {
|
||||
/*
|
||||
* Simplified version -- diagonal matrix
|
||||
*/
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
_matrix[i][i] *= scale;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* The following four functions indicate filter boundaries. Filter
|
||||
* support may include everything up to and including the boundaries
|
||||
* specified here.
|
||||
*/
|
||||
virtual ale_real min_i() const = 0;
|
||||
virtual ale_real max_i() const = 0;
|
||||
virtual ale_real min_j() const = 0;
|
||||
virtual ale_real max_j() const = 0;
|
||||
|
||||
/*
|
||||
* Get the number of varieties supported by this PSF. These usually
|
||||
* correspond to different points in the sensor array.
|
||||
*/
|
||||
virtual unsigned int varieties() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select the variety appropriate for a given position in the sensor
|
||||
* array.
|
||||
*/
|
||||
virtual unsigned int select(unsigned int i, unsigned int j) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the response to the rectangle bounded by (top, bot, lef, rig).
|
||||
* This function must correctly handle points which fall outside of the
|
||||
* filter support. One of several varieties can be selected, usually
|
||||
* based on position (e.g. some sensor arrays stagger red, green, and
|
||||
* blue sensors).
|
||||
*/
|
||||
virtual psf_result operator()(ale_real top, ale_real bot, ale_real lef, ale_real
|
||||
rig, unsigned int variety) const = 0;
|
||||
|
||||
virtual psf_result operator()(ale_real top, ale_real bot, ale_real lef, ale_real
|
||||
rig, unsigned int variety, char channels) const {
|
||||
return operator()(top, bot, lef, rig, variety);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Get the average pixel response. This function should be overloaded
|
||||
* for PSFs that support multiple varieties.
|
||||
*/
|
||||
virtual psf_result operator()(ale_real top, ale_real bot, ale_real lef, ale_real rig) const {
|
||||
return operator()(top, bot, lef, rig, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual ~psf() {
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
333
d2/render/psf/psf_calibrate.h
Normal file
333
d2/render/psf/psf_calibrate.h
Normal file
@@ -0,0 +1,333 @@
|
||||
// Copyright 2003 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
|
||||
*/
|
||||
|
||||
#ifndef __psf_calibrate_h__
|
||||
#define __psf_calibrate_h__
|
||||
|
||||
#include "../../image.h"
|
||||
#include "../../render.h"
|
||||
#include "../ipc.h"
|
||||
|
||||
class psf_calibrate : public ipc {
|
||||
private:
|
||||
double *psf_match_args;
|
||||
public:
|
||||
psf_calibrate(render *input, unsigned int iterations, int _inc, psf *lresponse, psf *nlresponse,
|
||||
double *psf_match_args)
|
||||
: ipc(input, iterations, _inc, lresponse, nlresponse, 1, 0, 0) {
|
||||
fprintf(stderr, "\nIPC Calibration module.\n\n");
|
||||
fprintf(stderr, "This module is designed for use with a calibration script.\n\n");
|
||||
|
||||
this->psf_match_args = psf_match_args;
|
||||
}
|
||||
|
||||
void _ip_frame(ale_accum *diff, unsigned int *count, int m) {
|
||||
|
||||
/*
|
||||
* Get alignment information for frame m.
|
||||
*/
|
||||
|
||||
transformation t = align::of(m);
|
||||
|
||||
/*
|
||||
* We create real and simulated input-frame data structures
|
||||
* REAL and SIMULATED, as well as simulated input-frame weights
|
||||
* SIM_WEIGHTS, used to track the weights of contributions to each
|
||||
* simulated input-frame pixel component.
|
||||
*/
|
||||
|
||||
const image *real = image_rw::open(m);
|
||||
image *simulated = new_image_ale_real(
|
||||
real->height(),
|
||||
real->width(), 3);
|
||||
|
||||
/*
|
||||
* Calculate the simulated input frame SIMULATED from the image
|
||||
* approximation APPROXIMATION, iterating over image
|
||||
* approximation pixels and tracking contributions to simulated
|
||||
* frame pixels in the data structure SIM_WEIGHTS.
|
||||
*/
|
||||
|
||||
image *sim_weights = new_image_ale_real(
|
||||
simulated->height(),
|
||||
simulated->width(), 3);
|
||||
|
||||
for (unsigned int i = 0; i < approximation->height(); i++)
|
||||
for (unsigned int j = 0; j < approximation->width(); j++) {
|
||||
|
||||
/*
|
||||
* Obtain the position Q and dimensions D of
|
||||
* image approximation pixel (i, j) in the coordinate
|
||||
* system of the simulated frame.
|
||||
*/
|
||||
|
||||
point p = point(i + approximation->offset()[0], j + approximation->offset()[1]);
|
||||
point q;
|
||||
ale_pos d[2];
|
||||
|
||||
t.unscaled_map_area_inverse(p, &q, d);
|
||||
|
||||
/*
|
||||
* Iterate over all simulated frame pixels influenced
|
||||
* by the scene pixel (i, j), as determined by the
|
||||
* response function.
|
||||
*/
|
||||
|
||||
for (int ii = (int) floor(q[0] - d[0] + (ale_pos) lresponse->min_i());
|
||||
ii <= ceil(q[0] + d[0] + (ale_pos) lresponse->max_i()); ii++)
|
||||
for (int jj = (int) floor(q[1] - d[1] + (ale_pos) lresponse->min_j());
|
||||
jj <= ceil(q[1] + d[1] + (ale_pos) lresponse->max_j()); jj++) {
|
||||
|
||||
ale_pos top = q[0] - d[0];
|
||||
ale_pos bot = q[0] + d[0];
|
||||
ale_pos lef = q[1] - d[1];
|
||||
ale_pos rig = q[1] + d[1];
|
||||
|
||||
if (ii >= (int) 0
|
||||
&& ii < (int) real->height()
|
||||
&& jj >= (int) 0
|
||||
&& jj < (int) real->width()) {
|
||||
|
||||
psf::psf_result r =
|
||||
(*lresponse)(top - ii, bot - ii,
|
||||
lef - jj, rig - jj,
|
||||
lresponse->select(ii, jj));
|
||||
|
||||
sim_weights->set_pixel(ii, jj,
|
||||
(pixel) sim_weights->get_pixel(ii, jj) + r.weight());
|
||||
simulated->set_pixel(ii, jj,
|
||||
(pixel) simulated->get_pixel(ii, jj) + r(approximation->get_pixel(i, j)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Normalize SIMULATED by SIM_WEIGHTS
|
||||
*/
|
||||
|
||||
for (unsigned int i = 0; i < simulated->height(); i++)
|
||||
for (unsigned int j = 0; j < simulated->width(); j++)
|
||||
simulated->set_pixel(i, j,
|
||||
(pixel) simulated->get_pixel(i, j) / (pixel) sim_weights->get_pixel(i, j));
|
||||
|
||||
delete sim_weights;
|
||||
|
||||
/*
|
||||
* If NLRESPONSE is defined, then redefine SIMULATED to account
|
||||
* for this.
|
||||
*/
|
||||
|
||||
if (nlresponse != NULL) {
|
||||
image *nlsimulated = new_image_ale_real(
|
||||
simulated->height(),
|
||||
simulated->width(), 3);
|
||||
|
||||
image *nlsim_weights = new_image_ale_real(
|
||||
simulated->height(),
|
||||
simulated->width(), 3);
|
||||
|
||||
for (unsigned int i = 0; i < simulated->height(); i++)
|
||||
for (unsigned int j = 0; j < simulated->width(); j++) {
|
||||
|
||||
for (int ii = (int) floor(i - 0.5 + nlresponse->min_i());
|
||||
ii <= ceil(i + 0.5 + nlresponse->max_i()); ii++)
|
||||
for (int jj = (int) floor(j - 0.5 + nlresponse->min_j());
|
||||
jj <= ceil(j + 0.5 + nlresponse->max_j()); jj++) {
|
||||
|
||||
ale_pos top = i - 0.5;
|
||||
ale_pos bot = i + 0.5;
|
||||
ale_pos lef = j - 0.5;
|
||||
ale_pos rig = j + 0.5;
|
||||
|
||||
if (ii >= (int) 0
|
||||
&& ii < (int) nlsimulated->height()
|
||||
&& jj >= (int) 0
|
||||
&& jj < (int) nlsimulated->width()) {
|
||||
|
||||
psf::psf_result r =
|
||||
(*nlresponse)(top - ii, bot - ii,
|
||||
lef - jj, rig - jj,
|
||||
nlresponse->select(ii, jj));
|
||||
|
||||
nlsim_weights->set_pixel(ii, jj,
|
||||
(pixel) nlsim_weights->get_pixel(ii, jj) + r.weight());
|
||||
|
||||
nlsimulated->set_pixel(ii, jj,
|
||||
(pixel) nlsimulated->get_pixel(ii, jj) + r(real->exp().unlinearize(simulated->get_pixel(i, j))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Normalize nlsimulated.
|
||||
*/
|
||||
|
||||
for (unsigned int i = 0; i < simulated->height(); i++)
|
||||
for (unsigned int j = 0; j < simulated->width(); j++)
|
||||
nlsimulated->set_pixel(i, j,
|
||||
(pixel) nlsimulated->get_pixel(i, j) / nlsim_weights->get_pixel(i, j));
|
||||
|
||||
/*
|
||||
* Linearize nlsimulated
|
||||
*/
|
||||
|
||||
for (unsigned int i = 0; i < simulated->height(); i++)
|
||||
for (unsigned int j = 0; j < simulated->width(); j++)
|
||||
nlsimulated->set_pixel(i, j,
|
||||
real->exp().linearize(nlsimulated->get_pixel(i, j)));
|
||||
|
||||
delete simulated;
|
||||
delete nlsim_weights;
|
||||
|
||||
simulated = nlsimulated;
|
||||
}
|
||||
|
||||
/*
|
||||
* For each SIMULATED pixel, calculate the difference from
|
||||
* the corresponding REAL pixel, and update the sum of squares
|
||||
* of differences.
|
||||
*/
|
||||
|
||||
ale_real margin_i1 = lresponse->min_i() + (nlresponse ? nlresponse->min_i() : ale_real_0);
|
||||
ale_real margin_i2 = lresponse->max_i() + (nlresponse ? nlresponse->max_i() : ale_real_0);
|
||||
ale_real margin_j1 = lresponse->min_j() + (nlresponse ? nlresponse->min_j() : ale_real_0);
|
||||
ale_real margin_j2 = lresponse->max_j() + (nlresponse ? nlresponse->max_j() : ale_real_0);
|
||||
|
||||
for (unsigned int i = 0; i < simulated->height(); i++)
|
||||
for (unsigned int j = 0; j < simulated->width(); j++) {
|
||||
|
||||
/*
|
||||
* Establish margins. This is designed to reduce the
|
||||
* influence of boundary conditions.
|
||||
*/
|
||||
|
||||
point p;
|
||||
|
||||
p = t.transform_unscaled(point(i + margin_i1, j + margin_j1));
|
||||
if (p[0] < 0 || p[0] > approximation->height()
|
||||
|| p[1] < 0 || p[1] > approximation->width())
|
||||
continue;
|
||||
|
||||
p = t.transform_unscaled(point(i + margin_i1, j + margin_j2));
|
||||
if (p[0] < 0 || p[0] > approximation->height()
|
||||
|| p[1] < 0 || p[1] > approximation->width())
|
||||
continue;
|
||||
|
||||
p = t.transform_unscaled(point(i + margin_i2, j + margin_j1));
|
||||
if (p[0] < 0 || p[0] > approximation->height()
|
||||
|| p[1] < 0 || p[1] > approximation->width())
|
||||
continue;
|
||||
|
||||
p = t.transform_unscaled(point(i + margin_i2, j + margin_j2));
|
||||
if (p[0] < 0 || p[0] > approximation->height()
|
||||
|| p[1] < 0 || p[1] > approximation->width())
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Real and simulated responses
|
||||
*/
|
||||
|
||||
pixel comp_real = real->get_pixel(i, j);
|
||||
pixel comp_simu = simulated->get_pixel(i, j);
|
||||
|
||||
for (unsigned int k = 0; k < simulated->depth(); k++) {
|
||||
|
||||
if (!finite(comp_simu[k]))
|
||||
continue;
|
||||
|
||||
|
||||
/*
|
||||
* Error calculation
|
||||
*/
|
||||
|
||||
if ((comp_real[k] < 1.0 || comp_simu[k] < 1.0 )
|
||||
&& (comp_real[k] > 0 || comp_simu[k] > 0)
|
||||
&& ((*count) < ULONG_MAX)) {
|
||||
|
||||
/*
|
||||
* real and simulated are distinguishable
|
||||
* within the dynamic range of the program
|
||||
* inputs, so calculate the error for this
|
||||
* channel.
|
||||
*/
|
||||
|
||||
(*diff) += pow(comp_simu[k] - comp_real[k], 2);
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
image_rw::close(m);
|
||||
delete simulated;
|
||||
|
||||
}
|
||||
|
||||
void _ip() {
|
||||
|
||||
/*
|
||||
* Input images 0 through count()-2 are frames captured with
|
||||
* the device to be calibrated, so we combine the difference
|
||||
* values for all of these frames against the calibration image
|
||||
* count()-1.
|
||||
*/
|
||||
|
||||
ale_accum diff = 0;
|
||||
unsigned int channel_count = 0;
|
||||
|
||||
approximation = image_rw::copy(image_rw::count() - 1, "PSF_CALIBRATE reference");
|
||||
|
||||
#if 0
|
||||
fprintf(stderr, "[%f %f %f %f %f %f] ", psf_match_args[0],
|
||||
psf_match_args[1],
|
||||
psf_match_args[2],
|
||||
psf_match_args[3],
|
||||
psf_match_args[4],
|
||||
psf_match_args[5]);
|
||||
#endif
|
||||
|
||||
for (unsigned int i = 0; i < approximation->height(); i++)
|
||||
for (unsigned int j = 0; j < approximation->width(); j++) {
|
||||
approximation->set_pixel(i, j, (pixel) approximation->get_pixel(i, j)
|
||||
* pixel(psf_match_args[0],
|
||||
psf_match_args[1],
|
||||
psf_match_args[2]));
|
||||
approximation->set_pixel(i, j, (pixel) approximation->get_pixel(i, j)
|
||||
+ pixel(psf_match_args[3],
|
||||
psf_match_args[4],
|
||||
psf_match_args[5]));
|
||||
}
|
||||
|
||||
for (unsigned int m = 0; m < image_rw::count() - 1; m++) {
|
||||
_ip_frame(&diff, &channel_count, m);
|
||||
}
|
||||
|
||||
diff = pow(diff / (ale_accum) channel_count, 0.5);
|
||||
|
||||
fprintf(stderr, "\n\nPSF Error:: %e\n\n", (double) diff);
|
||||
|
||||
delete approximation;
|
||||
}
|
||||
|
||||
void free_memory() {
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
197
d2/render/psf/psf_parse.h
Normal file
197
d2/render/psf/psf_parse.h
Normal file
@@ -0,0 +1,197 @@
|
||||
// Copyright 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
|
||||
*/
|
||||
|
||||
#ifndef __psf_parse_h__
|
||||
#define __psf_parse_h__
|
||||
|
||||
#include "psf.h"
|
||||
#include "box.h"
|
||||
#include "circle.h"
|
||||
#include "gauss.h"
|
||||
#include "sum.h"
|
||||
#include "convolution.h"
|
||||
#include "scalar_mult.h"
|
||||
#include "stdin.h"
|
||||
#include "stdin_vg.h"
|
||||
|
||||
/*
|
||||
* Parse strings describing point-spread functions, and return a psf object
|
||||
* satisfying the string.
|
||||
*/
|
||||
|
||||
class psf_parse {
|
||||
private:
|
||||
static int strpfix(const char *a, const char *b) {
|
||||
return strncmp(a, b, strlen(a));
|
||||
}
|
||||
|
||||
static void nomem() {
|
||||
fprintf(stderr, "\n\n*** Error: unable to allocate memory in psf_parse. ***\n\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void syntax_error(const char *explanation) {
|
||||
fprintf(stderr, "\n\n*** Error: PSF syntax: %s ***\n\n", explanation);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate a type string having no remaining binary operators.
|
||||
*/
|
||||
static psf *get_atomic(int is_linear, const char *orig_type) {
|
||||
double param;
|
||||
|
||||
if (!strcmp(orig_type, "stdin")) {
|
||||
|
||||
fprintf(stderr, "\nInitializing ");
|
||||
fprintf(stderr, is_linear ? "linear" : "non-linear");
|
||||
fprintf(stderr, " PSF.\n");
|
||||
|
||||
return new psf_stdin();
|
||||
} else if (!strcmp(orig_type, "stdin_vg")) {
|
||||
|
||||
fprintf(stderr, "\nInitializing ");
|
||||
fprintf(stderr, is_linear ? "linear" : "non-linear");
|
||||
fprintf(stderr, " PSF.\n");
|
||||
|
||||
return new psf_stdin_vg();
|
||||
} else if (!strpfix("box=", orig_type)) {
|
||||
if (sscanf(orig_type + strlen("box="), "%lf", ¶m) != 1)
|
||||
syntax_error("Unable to get box diameter.");
|
||||
return new box(param / 2);
|
||||
} else if (!strpfix("circle=", orig_type)) {
|
||||
if (sscanf(orig_type + strlen("circle="), "%lf", ¶m) != 1)
|
||||
syntax_error("Unable to get circle diameter.");
|
||||
return new circle(param / 2);
|
||||
} else if (!strpfix("gauss=", orig_type)) {
|
||||
if (sscanf(orig_type + strlen("gauss="), "%lf", ¶m) != 1)
|
||||
syntax_error("Unable to parse gauss std deviation.");
|
||||
return new gauss(param / 2);
|
||||
} else {
|
||||
fprintf(stderr, "get_atomic type %s\n", orig_type);
|
||||
syntax_error("Unable to get filter.");
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a scalar value
|
||||
*/
|
||||
static ale_real get_scalar(const char *orig_type) {
|
||||
double result;
|
||||
if (sscanf(orig_type, "%lf", &result) != 1)
|
||||
syntax_error("Unable to get scalar value.");
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Split a type string with the binary operator having
|
||||
* third-lowest precedence (i.e., scalar multiplication).
|
||||
*/
|
||||
static psf *get_scalar_mult(int is_linear, const char *orig_type) {
|
||||
char *type = strdup(orig_type);
|
||||
char *operator_index = (char *) type;
|
||||
|
||||
assert(type);
|
||||
if (!type)
|
||||
nomem();
|
||||
|
||||
while (*operator_index != '\0'
|
||||
&& *operator_index != '*')
|
||||
operator_index++;
|
||||
|
||||
if (*operator_index == '\0') {
|
||||
free(type);
|
||||
return get_atomic(is_linear, orig_type);
|
||||
}
|
||||
|
||||
*operator_index = '\0';
|
||||
psf *result = new scalar_mult(get_scalar(type), get_scalar_mult(is_linear, operator_index + 1));
|
||||
*operator_index = '*';
|
||||
|
||||
free(type);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Split a type string with the binary operator having
|
||||
* second-lowest precedence (i.e., convolution).
|
||||
*/
|
||||
static psf *get_convolution(int is_linear, const char *orig_type) {
|
||||
char *type = strdup(orig_type);
|
||||
char *operator_index = (char *) type;
|
||||
|
||||
assert(type);
|
||||
if (!type)
|
||||
nomem();
|
||||
|
||||
while (*operator_index != '\0'
|
||||
&& *operator_index != '^')
|
||||
operator_index++;
|
||||
|
||||
if (*operator_index == '\0') {
|
||||
free(type);
|
||||
return get_scalar_mult(is_linear, orig_type);
|
||||
}
|
||||
|
||||
*operator_index = '\0';
|
||||
psf *result = new convolution(get_scalar_mult(is_linear, type), get_convolution(is_linear, operator_index + 1));
|
||||
*operator_index = '^';
|
||||
|
||||
free(type);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Split the type string using the binary operator with
|
||||
* lowest precedence (addition).
|
||||
*/
|
||||
static psf *get_summation(int is_linear, const char *orig_type) {
|
||||
char *type = strdup(orig_type);
|
||||
char *plus_index = (char *) type;
|
||||
|
||||
assert(type);
|
||||
if (!type)
|
||||
nomem();
|
||||
|
||||
while (*plus_index != '\0'
|
||||
&& *plus_index != '+')
|
||||
plus_index++;
|
||||
|
||||
if (*plus_index == '\0') {
|
||||
free(type);
|
||||
return get_convolution(is_linear, orig_type);
|
||||
}
|
||||
|
||||
*plus_index = '\0';
|
||||
psf *result = new sum(get_convolution(is_linear, type), get_summation(is_linear, plus_index + 1));
|
||||
*plus_index = '+';
|
||||
|
||||
free(type);
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
static psf *get(int is_linear, const char *orig_type) {
|
||||
return get_summation(is_linear, orig_type);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
109
d2/render/psf/psf_template.h
Normal file
109
d2/render/psf/psf_template.h
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright 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
|
||||
*/
|
||||
|
||||
#ifndef __psf_template_h__
|
||||
#define __psf_template_h__
|
||||
|
||||
#include "psf.h"
|
||||
|
||||
/*
|
||||
* Point-spread function template.
|
||||
*/
|
||||
|
||||
template <unsigned int rows, unsigned int cols>
|
||||
class psf_template : public psf {
|
||||
const ale_real (&response)[rows][cols][3];
|
||||
ale_pos height, width;
|
||||
public:
|
||||
psf_template(ale_pos h, ale_pos w, const ale_real (&_response)[rows][cols][3]) : response(_response) {
|
||||
height = h / 2;
|
||||
width = w / 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following four functions indicate filter boundaries. Filter
|
||||
* support may include everything up to and including the boundaries
|
||||
* specified here.
|
||||
*/
|
||||
ale_real min_i() const { return -height; }
|
||||
ale_real max_i() const { return height; }
|
||||
ale_real min_j() const { return -width; }
|
||||
ale_real max_j() const { return width; }
|
||||
|
||||
/*
|
||||
* Response function
|
||||
*
|
||||
* Get the response to the rectangle bounded by (top, bot, lef, rig).
|
||||
* This function must correctly handle points which fall outside of the
|
||||
* filter support. The variety of the responding pixel is
|
||||
* provided, in case response is not uniform for all pixels
|
||||
* (e.g. some sensor arrays stagger red, green, and blue
|
||||
* sensors).
|
||||
*/
|
||||
psf_result operator()(ale_real top, ale_real bot, ale_real lef, ale_real rig,
|
||||
unsigned int variety) const {
|
||||
psf_result result;
|
||||
|
||||
if (top < min_i())
|
||||
top = min_i();
|
||||
if (bot > max_i())
|
||||
bot = max_i();
|
||||
if (lef < min_j())
|
||||
lef = min_j();
|
||||
if (rig > max_j())
|
||||
rig = max_j();
|
||||
|
||||
int il = (int) floor((top - min_i()) / (max_i() - min_i()) * rows);
|
||||
int ih = (int) floor((bot - min_i()) / (max_i() - min_i()) * rows);
|
||||
int jl = (int) floor((lef - min_j()) / (max_j() - min_j()) * cols);
|
||||
int jh = (int) floor((rig - min_j()) / (max_j() - min_j()) * cols);
|
||||
|
||||
for (int ii = il; ii <= ih; ii++)
|
||||
for (int jj = jl; jj <= jh; jj++) {
|
||||
|
||||
ale_real ltop = ((ale_real) ii) / rows * (max_i() - min_i()) + min_i();
|
||||
ale_real lbot = ((ale_real) ii + 1) / rows * (max_i() - min_i()) + min_i();
|
||||
ale_real llef = ((ale_real) jj) / cols * (max_j() - min_j()) + min_j();
|
||||
ale_real lrig = ((ale_real) jj + 1) / cols * (max_j() - min_j()) + min_j();
|
||||
|
||||
if (ltop < top)
|
||||
ltop = top;
|
||||
if (lbot > bot)
|
||||
lbot = bot;
|
||||
if (llef < lef)
|
||||
llef = lef;
|
||||
if (lrig > rig)
|
||||
lrig = rig;
|
||||
|
||||
assert (ii >= 0);
|
||||
assert (ii < (int) rows);
|
||||
assert (jj >= 0);
|
||||
assert (jj < (int) cols);
|
||||
|
||||
for (int k = 0; k < 3; k++)
|
||||
result.matrix(k, k) += ((lbot - ltop) * (lrig - llef)
|
||||
* response[ii][jj][k]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
309
d2/render/psf/raster.h
Normal file
309
d2/render/psf/raster.h
Normal file
@@ -0,0 +1,309 @@
|
||||
// Copyright 2003 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
|
||||
*/
|
||||
|
||||
#ifndef __raster_h__
|
||||
#define __raster_h__
|
||||
|
||||
#include "../../point.h"
|
||||
#include "psf.h"
|
||||
|
||||
/*
|
||||
* Raster point-spread function.
|
||||
*/
|
||||
|
||||
class raster : public psf {
|
||||
protected:
|
||||
ale_real _height;
|
||||
ale_real _width;
|
||||
unsigned int _filter_dim_i;
|
||||
unsigned int _filter_dim_j;
|
||||
unsigned int num_arrays;
|
||||
ale_real **response_arrays;
|
||||
ale_real **response_partials;
|
||||
#if 0
|
||||
ale_real *avg_response;
|
||||
#endif
|
||||
pixel *response_integrals;
|
||||
#if 0
|
||||
pixel avg_integral;
|
||||
#endif
|
||||
public:
|
||||
|
||||
/*
|
||||
* The following four functions indicate filter boundaries. Filter
|
||||
* support may include everything up to and including the boundaries
|
||||
* specified here.
|
||||
*/
|
||||
ale_real min_i() const { return ale_real_unexceptional_negation(_height); }
|
||||
ale_real max_i() const { return _height; }
|
||||
ale_real min_j() const { return ale_real_unexceptional_negation(_width); }
|
||||
ale_real max_j() const { return _width; }
|
||||
|
||||
/*
|
||||
* Element accessor methods.
|
||||
*/
|
||||
unsigned int max_elem_i() {
|
||||
return _filter_dim_i;
|
||||
}
|
||||
unsigned int max_elem_j() {
|
||||
return _filter_dim_j;
|
||||
}
|
||||
ale_real element(unsigned int n, unsigned int i, unsigned int j, unsigned int k) {
|
||||
|
||||
assert (n < num_arrays);
|
||||
assert (i < _filter_dim_i);
|
||||
assert (j < _filter_dim_j);
|
||||
assert (k < 3);
|
||||
|
||||
return response_arrays[n][i * _filter_dim_j * 3 + j * 3 + k];
|
||||
}
|
||||
#if 0
|
||||
ale_real element(unsigned int i, unsigned int j, unsigned int k) {
|
||||
assert (i < _filter_dim_i);
|
||||
assert (j < _filter_dim_j);
|
||||
assert (k < 3);
|
||||
|
||||
return avg_response[i * _filter_dim_j * 3 + j * 3 + k];
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Response function
|
||||
*
|
||||
* Get the response to the rectangle bounded by (top, bot, lef, rig).
|
||||
* This function must correctly handle points which fall outside of the
|
||||
* filter support.
|
||||
*
|
||||
* generic_response (private):
|
||||
*
|
||||
* A response array for this generic function is provided by the
|
||||
* calling function, and a specific or average response is returned,
|
||||
* based on this array.
|
||||
*
|
||||
* operator():
|
||||
*
|
||||
* The index of the specific response array is provided, from which the
|
||||
* specific response is determined. Alternatively, if no index is
|
||||
* specified, then the average response is returned.
|
||||
*/
|
||||
private:
|
||||
psf_result generic_response(ale_real *response_partial, ale_real top, ale_real
|
||||
bot, ale_real lef, ale_real rig, char channels) const {
|
||||
|
||||
assert (response_partial != NULL);
|
||||
|
||||
psf_result result;
|
||||
|
||||
/*
|
||||
* lrintf() can be more efficient than floor() or float-to-int
|
||||
* casts. For more details, see Erik de Castro Lopo, "Faster
|
||||
* Floating Point to Integer Conversions":
|
||||
*
|
||||
* http://mega-nerd.com/FPcast/
|
||||
*
|
||||
* In this case, lrintf() seems to be a bit faster than plain
|
||||
* casting, and much faster than floor(0.5 + ...). Casting
|
||||
* from round() seems to be an acceptable alternative to
|
||||
* lrintf().
|
||||
*
|
||||
* Early calculation of common floating-point constants in the
|
||||
* following code is based on an initial implementation by HJ
|
||||
* Hornbeck.
|
||||
*/
|
||||
|
||||
ale_real i_element_scale = (ale_real) _filter_dim_i / (max_i() - min_i());
|
||||
ale_real j_element_scale = (ale_real) _filter_dim_j / (max_j() - min_j());
|
||||
|
||||
int il = (int) lrintf(i_element_scale * (top - min_i()));
|
||||
int ih = (int) lrintf(i_element_scale * (bot - min_i()));
|
||||
int jl = (int) lrintf(j_element_scale * (lef - min_j()));
|
||||
int jh = (int) lrintf(j_element_scale * (rig - min_j()));
|
||||
|
||||
/*
|
||||
* Bounds clamping may be faster when performed in integer
|
||||
* arithmetic than in floating-point, so we do this after
|
||||
* float-to-int conversion is complete.
|
||||
*/
|
||||
|
||||
if (il < 0)
|
||||
il = 0;
|
||||
if (jl < 0)
|
||||
jl = 0;
|
||||
if (ih > (int) _filter_dim_i)
|
||||
ih = (int) _filter_dim_i;
|
||||
if (jh > (int) _filter_dim_j)
|
||||
jh = (int) _filter_dim_j;
|
||||
|
||||
if (!(il < ih) || !(jl < jh))
|
||||
return result;
|
||||
|
||||
for (int k = 0; k < 3; k++) {
|
||||
if (!((1 << k) & channels))
|
||||
continue;
|
||||
assert (ih > 0 && jh > 0);
|
||||
assert (ih <= (int) _filter_dim_i);
|
||||
assert (jh <= (int) _filter_dim_j);
|
||||
|
||||
ale_real result_k = 0;
|
||||
|
||||
if (il > 0 && jl > 0)
|
||||
result_k += response_partial[k + 3 * (jl - 1) + 3 * _filter_dim_j * (il - 1)];
|
||||
if (il > 0)
|
||||
result_k -= response_partial[k + 3 * (jh - 1) + 3 * _filter_dim_j * (il - 1)];
|
||||
if (jl > 0)
|
||||
result_k -= response_partial[k + 3 * (jl - 1) + 3 * _filter_dim_j * (ih - 1)];
|
||||
result_k += response_partial[k + 3 * (jh - 1) + 3 * _filter_dim_j * (ih - 1)];
|
||||
result.set_matrix(k, k, result_k);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
virtual unsigned int varieties() const = 0;
|
||||
|
||||
virtual unsigned int select(unsigned int i, unsigned int j) const = 0;
|
||||
|
||||
/*
|
||||
* Get a specific pixel response.
|
||||
*/
|
||||
psf_result operator()(ale_real top, ale_real bot, ale_real lef, ale_real rig, unsigned int variety,
|
||||
char channels) const {
|
||||
assert (variety < num_arrays);
|
||||
|
||||
ale_real *response_partial = response_partials[variety];
|
||||
assert (response_partial != NULL);
|
||||
|
||||
return generic_response(response_partial, top, bot, lef, rig, channels);
|
||||
}
|
||||
|
||||
psf_result operator()(ale_real top, ale_real bot, ale_real lef, ale_real rig,
|
||||
unsigned int variety) const {
|
||||
return operator()(top, bot, lef, rig, variety, 0x7);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Get the average pixel response.
|
||||
*/
|
||||
psf_result operator()(float top, float bot, float lef, float rig) const {
|
||||
return generic_response(avg_response, top, bot, lef, rig);
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
/*
|
||||
* Integrate over the whole PSF
|
||||
*/
|
||||
pixel integrate(ale_real *response_array) {
|
||||
pixel result;
|
||||
|
||||
for (unsigned int i = 0; i < _filter_dim_i; i++)
|
||||
for (unsigned int j = 0; j < _filter_dim_j; j++)
|
||||
for (unsigned int k = 0; k < 3 ; k++)
|
||||
result[k] += response_array[i * _filter_dim_j * 3 + j * 3 + k];
|
||||
|
||||
for (unsigned int k = 0; k < 3; k++)
|
||||
result[k] *= (((ale_real) 4 * _height * _width)
|
||||
/ (ale_real) (_filter_dim_i * _filter_dim_j));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void partial_integrate(ale_real *target, ale_real *source) {
|
||||
ale_real element_area = (ale_real) (max_i() - min_i())
|
||||
* (ale_real) (max_j() - min_j())
|
||||
/ (ale_real) (_filter_dim_i)
|
||||
/ (ale_real) (_filter_dim_j);
|
||||
|
||||
for (unsigned int i = 0; i < _filter_dim_i; i++)
|
||||
for (unsigned int j = 0; j < _filter_dim_j; j++)
|
||||
for (unsigned int k = 0; k < 3 ; k++) {
|
||||
unsigned int index = i * _filter_dim_j * 3 + j * 3 + k;
|
||||
target[index] = source[index] * element_area
|
||||
+ ((j > 0) ? target[index - 3] : ale_real_0)
|
||||
+ ((i > 0) ? target[index - _filter_dim_j * 3] : ale_real_0)
|
||||
- ((i > 0
|
||||
&& j > 0) ? target[index - _filter_dim_j * 3 - 3] : ale_real_0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute integrals.
|
||||
*/
|
||||
void compute_integrals() {
|
||||
response_integrals = new pixel[num_arrays];
|
||||
|
||||
for (unsigned int n = 0; n < num_arrays; n++)
|
||||
response_integrals[n] = integrate(response_arrays[n]);
|
||||
|
||||
#if 0
|
||||
avg_integral = integrate(avg_response);
|
||||
#endif
|
||||
|
||||
response_partials = (ale_real **) malloc(sizeof(ale_real *) * num_arrays);
|
||||
assert(response_partials);
|
||||
for (unsigned int n = 0; n < num_arrays; n++) {
|
||||
response_partials[n] = (ale_real *) malloc(sizeof(ale_real) * _filter_dim_i
|
||||
* _filter_dim_j
|
||||
* 3);
|
||||
assert(response_partials[n]);
|
||||
partial_integrate(response_partials[n], response_arrays[n]);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
* Return elements of given integrals
|
||||
*/
|
||||
pixel integral(unsigned int n) const {
|
||||
assert (response_integrals != NULL);
|
||||
return response_integrals[n];
|
||||
}
|
||||
#if 0
|
||||
pixel integral() const {
|
||||
return avg_integral;
|
||||
}
|
||||
#endif
|
||||
|
||||
raster () {
|
||||
response_integrals = NULL;
|
||||
}
|
||||
|
||||
virtual ~raster() {
|
||||
|
||||
/*
|
||||
* Deallocate data structures.
|
||||
*/
|
||||
|
||||
for (unsigned int n = 0; n < num_arrays; n++)
|
||||
free(response_arrays[n]);
|
||||
free(response_arrays);
|
||||
#if 0
|
||||
free(avg_response);
|
||||
#endif
|
||||
|
||||
if (response_integrals)
|
||||
delete response_integrals;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
192
d2/render/psf/rasterizer.h
Normal file
192
d2/render/psf/rasterizer.h
Normal file
@@ -0,0 +1,192 @@
|
||||
// Copyright 2003 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
|
||||
*/
|
||||
|
||||
#ifndef __psf_rasterize_h__
|
||||
#define __psf_rasterize_h__
|
||||
|
||||
#include "../../point.h"
|
||||
#include "raster.h"
|
||||
#include "psf.h"
|
||||
|
||||
/*
|
||||
* Point-spread function rasterizer.
|
||||
*
|
||||
* These operations rasterize a PSF to a multiple of the resolution of the
|
||||
* rendering grid for a given frame.
|
||||
*/
|
||||
|
||||
class rasterizer : public raster {
|
||||
psf *input;
|
||||
|
||||
public:
|
||||
unsigned int varieties() const {
|
||||
return input->varieties();
|
||||
}
|
||||
|
||||
unsigned int select(unsigned int i, unsigned int j) const {
|
||||
return input->select(i, j);
|
||||
}
|
||||
|
||||
rasterizer (psf *input, transformation t) {
|
||||
this->input = input;
|
||||
|
||||
_height = -input->min_i();
|
||||
|
||||
if (input->max_i() > _height)
|
||||
_height = input->max_i();
|
||||
|
||||
_width = -input->min_j();
|
||||
|
||||
if (input->max_j() > _width)
|
||||
_width = input->max_j();
|
||||
|
||||
/*
|
||||
* Approximate the desired resolution.
|
||||
*
|
||||
* Assume that maximum resolution is reached at (at least) one
|
||||
* of the corners of the image. (This should be true for
|
||||
* projective, Euclidean, and translational transformations,
|
||||
* but it would be worthwhile to check/prove this for the
|
||||
* projective case at some point, since it's a bit less
|
||||
* obvious.)
|
||||
*/
|
||||
|
||||
point min_diff;
|
||||
|
||||
/*
|
||||
* XXX: this loop breaks when height <= 1 or width <= 1.
|
||||
*/
|
||||
|
||||
for (unsigned int i = 0; i < t.unscaled_height(); i += (t.unscaled_height() - 1))
|
||||
for (unsigned int j = 0; j < t.unscaled_width(); j += (t.unscaled_width() - 1)) {
|
||||
point corner = point(i, j);
|
||||
point delta1 = corner - t.scaled_inverse_transform(t.transform_scaled(corner) + point(1, 0));
|
||||
point delta2 = corner - t.scaled_inverse_transform(t.transform_scaled(corner) + point(0, 1));
|
||||
|
||||
for (int index = 0; index < 2; index++) {
|
||||
ale_pos d1 = fabs(delta1[index]);
|
||||
ale_pos d2 = fabs(delta2[index]);
|
||||
|
||||
/*
|
||||
* Take the largest change in each direction.
|
||||
*/
|
||||
|
||||
ale_pos delta = (d1 > d2) ? d1 : d2;
|
||||
|
||||
if ((i == 0 && j == 0) || delta < min_diff[index])
|
||||
min_diff[index] = delta;
|
||||
}
|
||||
}
|
||||
|
||||
ale_real resolution_multiplier = 20; /* Arbitrary */
|
||||
|
||||
_filter_dim_i = (int) ceil((ale_real) 2 * _height * resolution_multiplier / (ale_real) min_diff[0]);
|
||||
_filter_dim_j = (int) ceil((ale_real) 2 * _width * resolution_multiplier / (ale_real) min_diff[1]);
|
||||
|
||||
/*
|
||||
* Ensure that the array has an odd number of elements in each
|
||||
* direction. This allows us to move the center to the right
|
||||
* place when using FFTW.
|
||||
*/
|
||||
|
||||
if (_filter_dim_i % 2 == 0)
|
||||
_filter_dim_i++;
|
||||
if (_filter_dim_j % 2 == 0)
|
||||
_filter_dim_j++;
|
||||
|
||||
/*
|
||||
* Determine the number of arrays to create.
|
||||
*/
|
||||
|
||||
num_arrays = input->varieties();
|
||||
|
||||
/*
|
||||
* Create arrays
|
||||
*/
|
||||
|
||||
response_arrays = (ale_real **)malloc(num_arrays * sizeof(ale_real *));
|
||||
|
||||
if (!response_arrays) {
|
||||
fprintf(stderr, "Could not allocate in rasterizer.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ale_real stepsize_i = (2 * _height) / _filter_dim_i;
|
||||
ale_real stepsize_j = (2 * _width) / _filter_dim_j;
|
||||
ale_real divisor = stepsize_i * stepsize_j;
|
||||
|
||||
for (unsigned int n = 0; n < num_arrays; n++) {
|
||||
response_arrays[n] = (ale_real *)malloc(_filter_dim_i * _filter_dim_j * 3
|
||||
* sizeof(ale_real));
|
||||
|
||||
if (!response_arrays[n]) {
|
||||
fprintf(stderr, "Could not allocate in rasterizer.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < _filter_dim_i; i++)
|
||||
for (unsigned int j = 0; j < _filter_dim_j; j++) {
|
||||
psf_result r
|
||||
= (*input)(-_height + stepsize_i * (ale_real) i,
|
||||
-_height + stepsize_i * (ale_real) (i + 1),
|
||||
-_width + stepsize_j * (ale_real) j,
|
||||
-_width + stepsize_j * (ale_real) (j + 1), n);
|
||||
|
||||
for (unsigned int k = 0; k < 3; k++) {
|
||||
response_arrays[n][i * _filter_dim_j * 3 + j * 3 + k]
|
||||
= r.matrix(k, k) / divisor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
avg_response = (ale_real *)malloc(_filter_dim_i * _filter_dim_j * 3
|
||||
* sizeof(ale_real));
|
||||
|
||||
if (!avg_response) {
|
||||
fprintf(stderr, "Could not allocate in rasterizer.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < _filter_dim_i; i++)
|
||||
for (unsigned int j = 0; j < _filter_dim_j; j++) {
|
||||
psf::psf_result r
|
||||
= (*input)(-_height + stepsize_i * i,
|
||||
-_height + stepsize_i * (i + 1),
|
||||
-_width + stepsize_j * j,
|
||||
-_width + stepsize_j * (j + 1));
|
||||
|
||||
for (unsigned int k = 0; k < 3; k++)
|
||||
avg_response[i * _filter_dim_j * 3 + j * 3 + k]
|
||||
= r.matrix(k, k) / divisor;
|
||||
}
|
||||
#endif
|
||||
|
||||
compute_integrals();
|
||||
|
||||
// fprintf(stderr, "(w=%f h=%f we=%d he=%d [", _width, _height, _filter_dim_j, _filter_dim_i);
|
||||
// for (unsigned int i = 0; i < _filter_dim_i; i++)
|
||||
// for (unsigned int j = 0; j < _filter_dim_j; j++)
|
||||
// fprintf(stderr, "%f ", response_arrays[0][i * _filter_dim_j * 3 + j * 3 + 0]);
|
||||
// fprintf(stderr, "])");
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
101
d2/render/psf/scalar_mult.h
Normal file
101
d2/render/psf/scalar_mult.h
Normal file
@@ -0,0 +1,101 @@
|
||||
// Copyright 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
|
||||
*/
|
||||
|
||||
#ifndef __psf_scalar_mult_h__
|
||||
#define __psf_scalar_mult_h__
|
||||
|
||||
#include "../../point.h"
|
||||
#include "psf.h"
|
||||
|
||||
/*
|
||||
* Point-spread function module.
|
||||
*
|
||||
* This module implements the scalar_mult (f1 * f2) of point-spread functions f1 and
|
||||
* f2.
|
||||
*/
|
||||
|
||||
class scalar_mult : public psf {
|
||||
ale_pos _radius;
|
||||
psf *f;
|
||||
ale_real scalar;
|
||||
ale_real _min_i, _max_i, _min_j, _max_j;
|
||||
|
||||
public:
|
||||
/*
|
||||
* The following four functions indicate filter boundaries. Filter
|
||||
* support may include everything up to and including the boundaries
|
||||
* specified here.
|
||||
*/
|
||||
ale_real min_i() const { return _min_i; }
|
||||
ale_real max_i() const { return _max_i; }
|
||||
ale_real min_j() const { return _min_j; }
|
||||
ale_real max_j() const { return _max_j; }
|
||||
|
||||
/*
|
||||
* Get the number of varieties supported by this PSF. These usually
|
||||
* correspond to different points in the sensor array.
|
||||
*/
|
||||
virtual unsigned int varieties() {
|
||||
return f->varieties();
|
||||
}
|
||||
|
||||
/*
|
||||
* Select the variety appropriate for a given position in the sensor
|
||||
* array.
|
||||
*/
|
||||
virtual unsigned int select(unsigned int i, unsigned int j) {
|
||||
return f->select(i, j);
|
||||
}
|
||||
|
||||
/*
|
||||
* Response function
|
||||
*
|
||||
* Get the response to the rectangle bounded by (top, bot, lef, rig).
|
||||
* This function must correctly handle points which fall outside of the
|
||||
* filter support. The variety of the responding pixel is provided, in
|
||||
* case response is not uniform for all pixels (e.g. some sensor arrays
|
||||
* stagger red, green, and blue sensors).
|
||||
*/
|
||||
psf_result operator()(ale_real top, ale_real bot, ale_real lef, ale_real rig,
|
||||
unsigned int variety) const {
|
||||
psf_result result;
|
||||
psf_result r;
|
||||
|
||||
r = (*f)(top, bot, lef, rig, variety);
|
||||
|
||||
for (int k1 = 0; k1 < 3; k1++)
|
||||
for (int k2 = 0; k2 < 3; k2++)
|
||||
result.set_matrix(k1, k2, scalar * r.get_matrix(k1, k2));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
scalar_mult(ale_real s, psf *f) {
|
||||
this->scalar = s;
|
||||
this->f = f;
|
||||
|
||||
_min_i = f->min_i();
|
||||
_min_j = f->min_j();
|
||||
_max_i = f->max_i();
|
||||
_max_j = f->max_j();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
186
d2/render/psf/stdin.h
Normal file
186
d2/render/psf/stdin.h
Normal file
@@ -0,0 +1,186 @@
|
||||
// Copyright 2003 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
|
||||
*/
|
||||
|
||||
#ifndef __psf_stdin_h__
|
||||
#define __psf_stdin_h__
|
||||
|
||||
#include "../../point.h"
|
||||
#include "psf.h"
|
||||
|
||||
/*
|
||||
* Point-spread function module.
|
||||
*
|
||||
* This response function is configured by input from stdin. A series of
|
||||
* prompts indicates the information required.
|
||||
*/
|
||||
|
||||
class psf_stdin : public psf {
|
||||
ale_real _height;
|
||||
ale_real _width;
|
||||
int _filter_dim_i;
|
||||
int _filter_dim_j;
|
||||
ale_real *response_array;
|
||||
public:
|
||||
/*
|
||||
* The following four functions indicate filter boundaries. Filter
|
||||
* support may include everything up to and including the boundaries
|
||||
* specified here.
|
||||
*/
|
||||
ale_real min_i() const { return -_height; }
|
||||
ale_real max_i() const { return _height; }
|
||||
ale_real min_j() const { return -_width; }
|
||||
ale_real max_j() const { return _width; }
|
||||
|
||||
/*
|
||||
* Response functions
|
||||
*
|
||||
* response_generic() and operator()()
|
||||
*
|
||||
* Get the response to the rectangle bounded by (top, bot, lef, rig).
|
||||
* This function must correctly handle points which fall outside of the
|
||||
* filter support. The variety of the responding pixel is provided, in
|
||||
* case response is not uniform for all pixels (e.g. some sensor arrays
|
||||
* stagger red, green, and blue sensors).
|
||||
*/
|
||||
psf_result response_generic(ale_real *response_array, ale_real top, ale_real bot,
|
||||
ale_real lef, ale_real rig) const {
|
||||
|
||||
assert (response_array != NULL);
|
||||
|
||||
psf_result result;
|
||||
|
||||
if (top < min_i())
|
||||
top = min_i();
|
||||
if (bot > max_i())
|
||||
bot = max_i();
|
||||
if (lef < min_j())
|
||||
lef = min_j();
|
||||
if (rig > max_j())
|
||||
rig = max_j();
|
||||
|
||||
int il = (int) floor((top - min_i()) / (max_i() - min_i()) * _filter_dim_i);
|
||||
int ih = (int) floor((bot - min_i()) / (max_i() - min_i()) * _filter_dim_i);
|
||||
int jl = (int) floor((lef - min_j()) / (max_j() - min_j()) * _filter_dim_j);
|
||||
int jh = (int) floor((rig - min_j()) / (max_j() - min_j()) * _filter_dim_j);
|
||||
|
||||
// fprintf(stderr, "(il, ih, jl, jh) = (%d, %d, %d, %d)\n", il, ih, jl, jh);
|
||||
|
||||
for (int ii = il; ii <= ih; ii++)
|
||||
for (int jj = jl; jj <= jh; jj++) {
|
||||
|
||||
ale_real ltop = ((ale_real) ii) / _filter_dim_i * (max_i() - min_i()) + min_i();
|
||||
ale_real lbot = ((ale_real) ii + 1) / _filter_dim_i * (max_i() - min_i()) + min_i();
|
||||
ale_real llef = ((ale_real) jj) / _filter_dim_j * (max_j() - min_j()) + min_j();
|
||||
ale_real lrig = ((ale_real) jj + 1) / _filter_dim_j * (max_j() - min_j()) + min_j();
|
||||
|
||||
if (ltop < top)
|
||||
ltop = top;
|
||||
if (lbot > bot)
|
||||
lbot = bot;
|
||||
if (llef < lef)
|
||||
llef = lef;
|
||||
if (lrig > rig)
|
||||
lrig = rig;
|
||||
|
||||
for (int k = 0; k < 3; k++) {
|
||||
result.matrix(k, k) += (ale_real) ((lbot - ltop) * (lrig - llef)
|
||||
* response_array[3 * _filter_dim_j * ii + 3 * jj + k]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
psf_result operator()(ale_real top, ale_real bot, ale_real lef, ale_real
|
||||
rig, unsigned int variety) const {
|
||||
return response_generic(response_array, top, bot, lef, rig);
|
||||
}
|
||||
|
||||
void class_error() {
|
||||
fprintf(stderr, "\n\nALE Panic: Error acquiring input. Exiting.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
psf_stdin () {
|
||||
|
||||
printf("\nEnter filter support height, in units of pixels (e.g. 2.5): ");
|
||||
fflush(stdout);
|
||||
double dheight;
|
||||
if (scanf("%lf", &dheight) != 1) {
|
||||
class_error();
|
||||
}
|
||||
_height = dheight / 2;
|
||||
|
||||
printf("\nEnter filter support width, in units of pixels (e.g. 2.5): ");
|
||||
fflush(stdout);
|
||||
double dwidth;
|
||||
if (scanf("%lf", &dwidth) != 1) {
|
||||
class_error();
|
||||
}
|
||||
_width = dwidth / 2;
|
||||
|
||||
printf("\nEnter the number of rows in the filter (e.g. 3): ");
|
||||
fflush(stdout);
|
||||
if (scanf("%d", &_filter_dim_i) != 1 || _filter_dim_i < 1) {
|
||||
class_error();
|
||||
}
|
||||
|
||||
printf("\nEnter the number of columns in the filter (e.g. 3): ");
|
||||
fflush(stdout);
|
||||
if (scanf("%d", &_filter_dim_j) != 1 || _filter_dim_j < 1) {
|
||||
class_error();
|
||||
}
|
||||
|
||||
response_array = (ale_real *) malloc(_filter_dim_i * _filter_dim_j * 3
|
||||
* sizeof(ale_real));
|
||||
|
||||
if (response_array == NULL) {
|
||||
fprintf(stderr, "\n\nCould not allocate filter.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("\nFilter elements are labeled as (row, column, channel). The red channel of\n");
|
||||
printf("the top-left element is (0, 0, 0), and the blue channel of the bottom-right\n");
|
||||
printf("element is (%d, %d, 2).\n\n", _filter_dim_i - 1, _filter_dim_j - 1);
|
||||
|
||||
for (int i = 0; i < _filter_dim_i; i++)
|
||||
for (int j = 0; j < _filter_dim_j; j++)
|
||||
for (int k = 0; k < 3; k++) {
|
||||
printf("Enter value for element (%d, %d, %d) (e.g. 2.5): ",
|
||||
i, j, k);
|
||||
fflush(stdout);
|
||||
double delem;
|
||||
if (scanf("%lf", &delem) != 1)
|
||||
class_error();
|
||||
response_array[i * _filter_dim_j * 3 + j * 3 + k] = delem;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~psf_stdin() {
|
||||
|
||||
/*
|
||||
* Don't free this without creating a copy constructor.
|
||||
*/
|
||||
|
||||
free(response_array);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
224
d2/render/psf/stdin_vg.h
Normal file
224
d2/render/psf/stdin_vg.h
Normal file
@@ -0,0 +1,224 @@
|
||||
// Copyright 2003 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
|
||||
*/
|
||||
|
||||
#ifndef __psf_stdin_vg_h__
|
||||
#define __psf_stdin_vg_h__
|
||||
|
||||
#include "../../point.h"
|
||||
#include "psf.h"
|
||||
|
||||
/*
|
||||
* Point-spread function module.
|
||||
*
|
||||
* This response function is configured by input from stdin. A series of
|
||||
* prompts indicates the information required.
|
||||
*/
|
||||
|
||||
class psf_stdin_vg : public psf {
|
||||
ale_real _height;
|
||||
ale_real _width;
|
||||
ale_real gap_width;
|
||||
int _filter_dim_i;
|
||||
int _filter_dim_j;
|
||||
ale_real *response_array;
|
||||
public:
|
||||
/*
|
||||
* The following four functions indicate filter boundaries. Filter
|
||||
* support may include everything up to and including the boundaries
|
||||
* specified here.
|
||||
*/
|
||||
ale_real min_i() const { return -_height; }
|
||||
ale_real max_i() const { return _height; }
|
||||
ale_real min_j() const { return -_width - fabs(gap_width); }
|
||||
ale_real max_j() const { return _width + fabs(gap_width); }
|
||||
|
||||
/*
|
||||
* Get the number of varieties supported by this PSF. These usually
|
||||
* correspond to different points in the sensor array.
|
||||
*/
|
||||
virtual unsigned int varieties() const {
|
||||
return 8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select the variety appropriate for a given position in the sensor
|
||||
* array.
|
||||
*/
|
||||
virtual unsigned int select(unsigned int i, unsigned int j) {
|
||||
return (j % 8);
|
||||
}
|
||||
|
||||
/*
|
||||
* Response functions
|
||||
*
|
||||
* response_generic() and operator()()
|
||||
*
|
||||
* Get the response to the rectangle bounded by (top, bot, lef, rig).
|
||||
* This function must correctly handle points which fall outside of the
|
||||
* filter support. The variety of the responding pixel is provided, in
|
||||
* case response is not uniform for all pixels (e.g. some sensor arrays
|
||||
* stagger red, green, and blue sensors).
|
||||
*/
|
||||
psf_result response_generic(ale_real *response_array, ale_real top, ale_real bot,
|
||||
ale_real lef, ale_real rig, unsigned int variety) const {
|
||||
|
||||
assert (response_array != NULL);
|
||||
assert (variety < varieties());
|
||||
|
||||
psf_result result;
|
||||
|
||||
ale_pos offset = (gap_width / 2)
|
||||
- (gap_width / 7) * variety;
|
||||
|
||||
lef -= offset;
|
||||
rig -= offset;
|
||||
|
||||
if (top < min_i())
|
||||
top = min_i();
|
||||
if (bot > max_i())
|
||||
bot = max_i();
|
||||
if (lef < -_width)
|
||||
lef = -_width;
|
||||
if (rig > _width)
|
||||
rig = _width;
|
||||
|
||||
int il = (int) floor((top - min_i()) / (max_i() - min_i()) * _filter_dim_i);
|
||||
int ih = (int) floor((bot - min_i()) / (max_i() - min_i()) * _filter_dim_i);
|
||||
int jl = (int) floor((lef + _width) / (_width * 2) * _filter_dim_j);
|
||||
int jh = (int) floor((rig + _width) / (_width * 2) * _filter_dim_j);
|
||||
|
||||
// fprintf(stderr, "(il, ih, jl, jh) = (%d, %d, %d, %d)\n", il, ih, jl, jh);
|
||||
|
||||
for (int ii = il; ii <= ih; ii++)
|
||||
for (int jj = jl; jj <= jh; jj++) {
|
||||
|
||||
ale_real ltop = ((ale_real) ii) / (ale_real) _filter_dim_i * (max_i() - min_i()) + min_i();
|
||||
ale_real lbot = ((ale_real) ii + 1) / (ale_real) _filter_dim_i * (max_i() - min_i()) + min_i();
|
||||
ale_real llef = ((ale_real) jj) / (ale_real) _filter_dim_j * ((ale_real) _width * (ale_real) 2) - _width;
|
||||
ale_real lrig = ((ale_real) jj + 1) / (ale_real) _filter_dim_j * (_width * (ale_real) 2) - _width;
|
||||
|
||||
if (ltop < top)
|
||||
ltop = top;
|
||||
if (lbot > bot)
|
||||
lbot = bot;
|
||||
if (llef < lef)
|
||||
llef = lef;
|
||||
if (lrig > rig)
|
||||
lrig = rig;
|
||||
|
||||
for (int k = 0; k < 3; k++) {
|
||||
result.matrix(k, k) += (ale_real) ((lbot - ltop) * (lrig - llef)
|
||||
* response_array[3 * _filter_dim_j * ii + 3 * jj + k]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
psf_result operator()(ale_real top, ale_real bot, ale_real lef, ale_real
|
||||
rig, unsigned int variety) const {
|
||||
return response_generic(response_array, top, bot, lef, rig, variety);
|
||||
}
|
||||
|
||||
#if 0
|
||||
psf_result operator()(ale_real top, ale_real bot, ale_real lef, ale_real rig) const {
|
||||
return response_generic(response_array, top, bot, lef, rig, 4);
|
||||
}
|
||||
#endif
|
||||
|
||||
void class_error() {
|
||||
fprintf(stderr, "\n\nALE Panic: Error acquiring input. Exiting.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
psf_stdin_vg () {
|
||||
|
||||
printf("\nEnter vertical gap width, in units of pixels (e.g. 1.0): ");
|
||||
fflush(stdout);
|
||||
double dgap_width;
|
||||
if (scanf("%lf", &dgap_width) != 1) {
|
||||
class_error();
|
||||
}
|
||||
gap_width = dgap_width;
|
||||
|
||||
printf("\nEnter filter support height, in units of pixels (e.g. 2.5): ");
|
||||
fflush(stdout);
|
||||
double dheight;
|
||||
if (scanf("%lf", &dheight) != 1) {
|
||||
class_error();
|
||||
}
|
||||
_height = dheight / 2;
|
||||
|
||||
printf("\nEnter filter support width, in units of pixels (e.g. 2.5): ");
|
||||
fflush(stdout);
|
||||
double dwidth;
|
||||
if (scanf("%lf", &dwidth) != 1) {
|
||||
class_error();
|
||||
}
|
||||
_width = dwidth / 2;
|
||||
|
||||
printf("\nEnter the number of rows in the filter (e.g. 3): ");
|
||||
fflush(stdout);
|
||||
if (scanf("%d", &_filter_dim_i) != 1 || _filter_dim_i < 1) {
|
||||
class_error();
|
||||
}
|
||||
|
||||
printf("\nEnter the number of columns in the filter (e.g. 3): ");
|
||||
fflush(stdout);
|
||||
if (scanf("%d", &_filter_dim_j) != 1 || _filter_dim_j < 1) {
|
||||
class_error();
|
||||
}
|
||||
|
||||
response_array = (ale_real *) malloc(_filter_dim_i * _filter_dim_j * 3
|
||||
* sizeof(ale_real));
|
||||
|
||||
if (response_array == NULL) {
|
||||
fprintf(stderr, "\n\nCould not allocate filter.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("\nFilter elements are labeled as (row, column, channel). The red channel of\n");
|
||||
printf("the top-left element is (0, 0, 0), and the blue channel of the bottom-right\n");
|
||||
printf("element is (%d, %d, 2).\n\n", _filter_dim_i - 1, _filter_dim_j - 1);
|
||||
|
||||
for (int i = 0; i < _filter_dim_i; i++)
|
||||
for (int j = 0; j < _filter_dim_j; j++)
|
||||
for (int k = 0; k < 3; k++) {
|
||||
printf("Enter value for element (%d, %d, %d) (e.g. 2.5): ",
|
||||
i, j, k);
|
||||
fflush(stdout);
|
||||
double delem;
|
||||
if (scanf("%lf", &delem) != 1)
|
||||
class_error();
|
||||
response_array[i * _filter_dim_j * 3 + j * 3 + k] = delem;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~psf_stdin_vg() {
|
||||
|
||||
/*
|
||||
* Don't free this without creating a copy constructor.
|
||||
*/
|
||||
|
||||
free(response_array);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
131
d2/render/psf/sum.h
Normal file
131
d2/render/psf/sum.h
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright 2003 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
|
||||
*/
|
||||
|
||||
#ifndef __psf_sum_h__
|
||||
#define __psf_sum_h__
|
||||
|
||||
#include "../../point.h"
|
||||
#include "psf.h"
|
||||
|
||||
/*
|
||||
* Point-spread function module.
|
||||
*
|
||||
* This module implements the sum (f1 + f2) of point-spread functions f1 and
|
||||
* f2. This is not a convolution.
|
||||
*/
|
||||
|
||||
class sum : public psf {
|
||||
ale_pos _radius;
|
||||
psf *f1, *f2;
|
||||
ale_real _min_i, _max_i, _min_j, _max_j;
|
||||
|
||||
public:
|
||||
/*
|
||||
* The following four functions indicate filter boundaries. Filter
|
||||
* support may include everything up to and including the boundaries
|
||||
* specified here.
|
||||
*/
|
||||
ale_real min_i() const { return _min_i; }
|
||||
ale_real max_i() const { return _max_i; }
|
||||
ale_real min_j() const { return _min_j; }
|
||||
ale_real max_j() const { return _max_j; }
|
||||
|
||||
/*
|
||||
* Get the number of varieties supported by this PSF. These usually
|
||||
* correspond to different points in the sensor array.
|
||||
*/
|
||||
virtual unsigned int varieties() {
|
||||
return f1->varieties() * f2->varieties();
|
||||
}
|
||||
|
||||
/*
|
||||
* Select the variety appropriate for a given position in the sensor
|
||||
* array.
|
||||
*/
|
||||
virtual unsigned int select(unsigned int i, unsigned int j) {
|
||||
return (f1->select(i, j) * f2->varieties() + f2->select(i, j));
|
||||
}
|
||||
|
||||
/*
|
||||
* Response function
|
||||
*
|
||||
* Get the response to the rectangle bounded by (top, bot, lef, rig).
|
||||
* This function must correctly handle points which fall outside of the
|
||||
* filter support. The variety of the responding pixel is provided, in
|
||||
* case response is not uniform for all pixels (e.g. some sensor arrays
|
||||
* stagger red, green, and blue sensors).
|
||||
*/
|
||||
psf_result operator()(ale_real top, ale_real bot, ale_real lef, ale_real rig,
|
||||
unsigned int variety) const {
|
||||
psf_result result;
|
||||
psf_result r1, r2;
|
||||
|
||||
r1 = (*f1)(top, bot, lef, rig, variety / f2->varieties());
|
||||
r2 = (*f2)(top, bot, lef, rig, variety % f2->varieties());
|
||||
|
||||
for (int k1 = 0; k1 < 3; k1++)
|
||||
for (int k2 = 0; k2 < 3; k2++)
|
||||
result.set_matrix(k1, k2, r1.get_matrix(k1, k2)
|
||||
+ r2.get_matrix(k1, k2));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Get the average pixel response.
|
||||
*/
|
||||
psf_result operator()(ale_real top, ale_real bot, ale_real lef, ale_real rig) {
|
||||
psf_result result;
|
||||
psf_result r1, r2;
|
||||
|
||||
r1 = (*f1)(top, bot, lef, rig);
|
||||
r2 = (*f2)(top, bot, lef, rig);
|
||||
|
||||
for (int k1 = 0; k1 < 3; k1++)
|
||||
for (int k2 = 0; k2 < 3; k2++)
|
||||
result.set_matrix(k1, k2, r1.get_matrix(k1, k2)
|
||||
+ r2.get_matrix(k1, k2));
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
sum(psf *f1, psf *f2) {
|
||||
this->f1 = f1;
|
||||
this->f2 = f2;
|
||||
|
||||
_min_i = f1->min_i();
|
||||
_min_j = f1->min_j();
|
||||
_max_i = f1->max_i();
|
||||
_max_j = f1->max_j();
|
||||
|
||||
if (_min_i > f2->min_i())
|
||||
_min_i = f2->min_i();
|
||||
if (_min_j > f2->min_j())
|
||||
_min_j = f2->min_j();
|
||||
if (_max_i < f2->max_i())
|
||||
_max_i = f2->max_i();
|
||||
if (_max_j < f2->max_j())
|
||||
_max_j = f2->max_j();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
218
d2/render/usm.h
Normal file
218
d2/render/usm.h
Normal file
@@ -0,0 +1,218 @@
|
||||
// Copyright 2002, 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* usm.h: A render subclass that implements an unsharp mask
|
||||
* postprocessing algorithm.
|
||||
*/
|
||||
|
||||
#ifndef __usm_h__
|
||||
#define __usm_h__
|
||||
|
||||
#include "../image.h"
|
||||
#include "../render.h"
|
||||
#include "psf/psf.h"
|
||||
|
||||
class usm : public render {
|
||||
|
||||
int done;
|
||||
int inc;
|
||||
image *done_image;
|
||||
render *input;
|
||||
const image *input_image;
|
||||
const image *input_defined;
|
||||
ale_real scale_factor;
|
||||
ale_real usm_multiplier;
|
||||
psf *lresponse, *nlresponse;
|
||||
const exposure *exp;
|
||||
|
||||
/*
|
||||
* USM value for point (i, j).
|
||||
*/
|
||||
pixel _usm(int i, int j, const image *im) {
|
||||
|
||||
pixel result;
|
||||
|
||||
ale_real d = scale_factor / 2;
|
||||
|
||||
pixel weight;
|
||||
|
||||
/*
|
||||
* Convolve with the linear filter, iterating over pixels
|
||||
* according to the filter support, and tracking contribution
|
||||
* weights in the variable WEIGHT.
|
||||
*/
|
||||
|
||||
for (int ii = (int) floor(i - d + lresponse->min_i());
|
||||
ii <= ceil(i + d + lresponse->max_i()); ii++)
|
||||
for (int jj = (int) floor(j - d + lresponse->min_j());
|
||||
jj <= ceil(j + d + lresponse->max_j()); jj++) {
|
||||
|
||||
ale_real top = ii - d;
|
||||
ale_real bot = ii + d;
|
||||
ale_real lef = jj - d;
|
||||
ale_real rig = jj + d;
|
||||
|
||||
if (ii >= (int) 0
|
||||
&& ii < (int) im->height()
|
||||
&& jj >= (int) 0
|
||||
&& jj < (int) im->width()
|
||||
&& input_defined->get_pixel(ii, jj)[0]) {
|
||||
|
||||
class psf::psf_result r = (*lresponse)((top - i) / scale_factor,
|
||||
(bot - i) / scale_factor,
|
||||
(lef - j) / scale_factor,
|
||||
(rig - j) / scale_factor);
|
||||
|
||||
if (nlresponse) {
|
||||
|
||||
/*
|
||||
* Convolve with the non-linear filter,
|
||||
* iterating over pixels according to the
|
||||
* filter support, and tracking contribution
|
||||
* weights in the variable WWEIGHT.
|
||||
*
|
||||
* Note: This approach is efficient
|
||||
* space-wise, but inefficient timewise. There
|
||||
* is probably a better approach to this.
|
||||
*/
|
||||
|
||||
pixel rresult(0, 0, 0), wweight(0, 0, 0);
|
||||
|
||||
for (int iii = (int) floor(ii - d + nlresponse->min_i());
|
||||
iii <= ceil(ii + d + lresponse->max_i()); iii++)
|
||||
for (int jjj = (int) floor(jj - d + nlresponse->min_j());
|
||||
jjj <= ceil(jj + d + lresponse->max_j()); jjj++) {
|
||||
|
||||
ale_real top = iii - d;
|
||||
ale_real bot = iii + d;
|
||||
ale_real lef = jjj - d;
|
||||
ale_real rig = jjj + d;
|
||||
|
||||
if (iii >= (int) 0
|
||||
&& iii < (int) im->height()
|
||||
&& jjj >= (int) 0
|
||||
&& jjj < (int) im->width()
|
||||
&& input_defined->get_pixel(iii, jjj)[0]) {
|
||||
|
||||
class psf::psf_result r = (*nlresponse)((top - ii) / scale_factor,
|
||||
(bot - ii) / scale_factor,
|
||||
(lef - jj) / scale_factor,
|
||||
(rig - jj) / scale_factor);
|
||||
|
||||
wweight += r.weight();
|
||||
rresult += r(exp->unlinearize(im->get_pixel(iii, jjj)));
|
||||
}
|
||||
}
|
||||
|
||||
result += r(exp->linearize(rresult / wweight));
|
||||
} else {
|
||||
result += r(im->get_pixel(ii, jj));
|
||||
}
|
||||
|
||||
weight += r.weight();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
result /= weight;
|
||||
result = im->get_pixel(i, j) - result;
|
||||
|
||||
if (finite(result[0])
|
||||
&& finite(result[1])
|
||||
&& finite(result[2]))
|
||||
return result;
|
||||
else
|
||||
return pixel(0, 0, 0);
|
||||
}
|
||||
|
||||
void _filter() {
|
||||
assert (done_image->height() == input_image->height());
|
||||
assert (done_image->width() == input_image->width());
|
||||
assert (done_image->depth() == input_image->depth());
|
||||
|
||||
for (unsigned int i = 0; i < done_image->height(); i++)
|
||||
for (unsigned int j = 0; j < done_image->width(); j++) {
|
||||
|
||||
if (!input_defined->get_pixel(i, j)[0])
|
||||
continue;
|
||||
|
||||
done_image->set_pixel(i, j,
|
||||
input_image->get_pixel(i, j)
|
||||
+ usm_multiplier
|
||||
* _usm(i, j, input_image));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
usm(render *input, ale_real scale_factor, ale_real usm_multiplier, int _inc,
|
||||
psf *lresponse, psf *nlresponse, exposure *exp) {
|
||||
this->input = input;
|
||||
done = 0;
|
||||
inc = _inc;
|
||||
this->scale_factor = scale_factor;
|
||||
this->usm_multiplier = usm_multiplier;
|
||||
this->lresponse = lresponse;
|
||||
this->nlresponse = nlresponse;
|
||||
this->exp = exp;
|
||||
}
|
||||
|
||||
const image *get_image() {
|
||||
if (done)
|
||||
return done_image;
|
||||
else
|
||||
return input->get_image();
|
||||
}
|
||||
|
||||
const image *get_defined() {
|
||||
return input->get_defined();
|
||||
}
|
||||
|
||||
void sync(int n) {
|
||||
render::sync(n);
|
||||
input->sync(n);
|
||||
}
|
||||
|
||||
void step() {
|
||||
}
|
||||
|
||||
int sync() {
|
||||
input->sync();
|
||||
fprintf(stderr, "Applying USM");
|
||||
done = 1;
|
||||
done_image = input->get_image()->clone("USM done_image");
|
||||
input_image = input->get_image();
|
||||
input_defined = input->get_defined();
|
||||
_filter();
|
||||
|
||||
if (inc)
|
||||
image_rw::output(done_image);
|
||||
|
||||
fprintf(stderr, ".\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual ~usm() {
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
74
d2/render/zero.h
Normal file
74
d2/render/zero.h
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* zero.h: A renderer for the zero filter.
|
||||
*/
|
||||
|
||||
#ifndef __render_zero_h__
|
||||
#define __render_zero_h__
|
||||
|
||||
#include "incremental.h"
|
||||
#include "../image_zero.h"
|
||||
|
||||
class zero : public incremental {
|
||||
public:
|
||||
zero(invariant *inv) : incremental(inv) {
|
||||
assert (typeid(*inv->ssfe()->get_scaled_filter()->get_filter()) == typeid(filter::zero));
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the current rendering step.
|
||||
*/
|
||||
virtual void step() {
|
||||
assert (get_step() >= -1);
|
||||
if (get_step() == 0) {
|
||||
transformation t = align::of(0);
|
||||
|
||||
const image *im = image_rw::open(0);
|
||||
|
||||
/*
|
||||
* XXX: This approach to trimming pixels is probably a
|
||||
* bit too aggressive. If it is changed, be sure to
|
||||
* also change the corresponding lines in
|
||||
* incremental.h.
|
||||
*/
|
||||
|
||||
unsigned int trim_size = (int) ceil(get_scale_factor()) - 1;
|
||||
|
||||
accum_image = new image_zero((int) floor(im->height() * get_scale_factor()) - trim_size,
|
||||
(int) floor(im->width() * get_scale_factor()) - trim_size, 3);
|
||||
|
||||
set_extents_by_map(0, t);
|
||||
|
||||
image_rw::close(0);
|
||||
} else if (align::match(get_step())) {
|
||||
transformation t = align::of(get_step());
|
||||
if (is_extend())
|
||||
increase_extents_by_map(get_step(), t);
|
||||
}
|
||||
}
|
||||
|
||||
void free_memory() {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user