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

219 lines
5.3 KiB
C++

// 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