// Copyright 2002, 2004 David Hilvert , // /* 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