TODO: add entries for centralizing licensing and authorship information and incorpora...
[Ale.git] / d2 / render / usm.h
blob25df0366987e2b4bb3840d0d65bcb81860ccf646
1 // Copyright 2002, 2004 David Hilvert <dhilvert@auricle.dyndns.org>,
2 // <dhilvert@ugcs.caltech.edu>
4 /* This file is part of the Anti-Lamenessing Engine.
6 The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with the Anti-Lamenessing Engine; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * usm.h: A render subclass that implements an unsharp mask
23 * postprocessing algorithm.
26 #ifndef __usm_h__
27 #define __usm_h__
29 #include "../image.h"
30 #include "../render.h"
31 #include "psf/psf.h"
33 class usm : public render {
35 int done;
36 int inc;
37 image *done_image;
38 render *input;
39 const image *input_image;
40 const image *input_defined;
41 ale_real scale_factor;
42 ale_real usm_multiplier;
43 psf *lresponse, *nlresponse;
44 const exposure *exp;
46 /*
47 * USM value for point (i, j).
49 pixel _usm(int i, int j, const image *im) {
51 pixel result;
53 ale_real d = scale_factor / 2;
55 pixel weight;
58 * Convolve with the linear filter, iterating over pixels
59 * according to the filter support, and tracking contribution
60 * weights in the variable WEIGHT.
63 for (int ii = (int) floor(i - d + lresponse->min_i());
64 ii <= ceil(i + d + lresponse->max_i()); ii++)
65 for (int jj = (int) floor(j - d + lresponse->min_j());
66 jj <= ceil(j + d + lresponse->max_j()); jj++) {
68 ale_real top = ii - d;
69 ale_real bot = ii + d;
70 ale_real lef = jj - d;
71 ale_real rig = jj + d;
73 if (ii >= (int) 0
74 && ii < (int) im->height()
75 && jj >= (int) 0
76 && jj < (int) im->width()
77 && input_defined->get_pixel(ii, jj)[0]) {
79 class psf::psf_result r = (*lresponse)((top - i) / scale_factor,
80 (bot - i) / scale_factor,
81 (lef - j) / scale_factor,
82 (rig - j) / scale_factor);
84 if (nlresponse) {
87 * Convolve with the non-linear filter,
88 * iterating over pixels according to the
89 * filter support, and tracking contribution
90 * weights in the variable WWEIGHT.
92 * Note: This approach is efficient
93 * space-wise, but inefficient timewise. There
94 * is probably a better approach to this.
97 pixel rresult(0, 0, 0), wweight(0, 0, 0);
99 for (int iii = (int) floor(ii - d + nlresponse->min_i());
100 iii <= ceil(ii + d + lresponse->max_i()); iii++)
101 for (int jjj = (int) floor(jj - d + nlresponse->min_j());
102 jjj <= ceil(jj + d + lresponse->max_j()); jjj++) {
104 ale_real top = iii - d;
105 ale_real bot = iii + d;
106 ale_real lef = jjj - d;
107 ale_real rig = jjj + d;
109 if (iii >= (int) 0
110 && iii < (int) im->height()
111 && jjj >= (int) 0
112 && jjj < (int) im->width()
113 && input_defined->get_pixel(iii, jjj)[0]) {
115 class psf::psf_result r = (*nlresponse)((top - ii) / scale_factor,
116 (bot - ii) / scale_factor,
117 (lef - jj) / scale_factor,
118 (rig - jj) / scale_factor);
120 wweight += r.weight();
121 rresult += r(exp->unlinearize(im->get_pixel(iii, jjj)));
125 result += r(exp->linearize(rresult / wweight));
126 } else {
127 result += r(im->get_pixel(ii, jj));
130 weight += r.weight();
135 result /= weight;
136 result = im->get_pixel(i, j) - result;
138 if (finite(result[0])
139 && finite(result[1])
140 && finite(result[2]))
141 return result;
142 else
143 return pixel(0, 0, 0);
146 void _filter() {
147 assert (done_image->height() == input_image->height());
148 assert (done_image->width() == input_image->width());
149 assert (done_image->depth() == input_image->depth());
151 for (unsigned int i = 0; i < done_image->height(); i++)
152 for (unsigned int j = 0; j < done_image->width(); j++) {
154 if (!input_defined->get_pixel(i, j)[0])
155 continue;
157 done_image->set_pixel(i, j,
158 input_image->get_pixel(i, j)
159 + usm_multiplier
160 * _usm(i, j, input_image));
164 public:
166 usm(render *input, ale_real scale_factor, ale_real usm_multiplier, int _inc,
167 psf *lresponse, psf *nlresponse, exposure *exp) {
168 this->input = input;
169 done = 0;
170 inc = _inc;
171 this->scale_factor = scale_factor;
172 this->usm_multiplier = usm_multiplier;
173 this->lresponse = lresponse;
174 this->nlresponse = nlresponse;
175 this->exp = exp;
178 const image *get_image() {
179 if (done)
180 return done_image;
181 else
182 return input->get_image();
185 const image *get_defined() {
186 return input->get_defined();
189 void sync(int n) {
190 render::sync(n);
191 input->sync(n);
194 void step() {
197 int sync() {
198 input->sync();
199 fprintf(stderr, "Applying USM");
200 done = 1;
201 done_image = input->get_image()->clone("USM done_image");
202 input_image = input->get_image();
203 input_defined = input->get_defined();
204 _filter();
206 if (inc)
207 image_rw::output(done_image);
209 fprintf(stderr, ".\n");
211 return 0;
214 virtual ~usm() {
218 #endif