Line 0
Link Here
|
|
|
1 |
--- src/filter/pfswb.cpp.orig 2014-02-20 19:04:01.556587853 +0000 |
2 |
+++ src/filter/pfswb.cpp 2014-02-20 19:06:49.706586923 +0000 |
3 |
@@ -0,0 +1,297 @@ |
4 |
+/** |
5 |
+ * @file pfswb.cpp |
6 |
+ * @brief Adjust white balance in RGB color space |
7 |
+ * |
8 |
+ * This file is a part of PFSTOOLS package. |
9 |
+ * ---------------------------------------------------------------------- |
10 |
+ * Copyright (C) 2008 Iouri V. Ivliev |
11 |
+ * |
12 |
+ * This program is free software; you can redistribute it and/or modify |
13 |
+ * it under the terms of the GNU General Public License as published by |
14 |
+ * the Free Software Foundation; either version 2 of the License, or |
15 |
+ * (at your option) any later version. |
16 |
+ * |
17 |
+ * This program is distributed in the hope that it will be useful, |
18 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 |
+ * GNU General Public License for more details. |
21 |
+ * |
22 |
+ * You should have received a copy of the GNU General Public License |
23 |
+ * along with this program; if not, write to the Free Software |
24 |
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
25 |
+ * ---------------------------------------------------------------------- |
26 |
+ * |
27 |
+ * @author Iouri V. Ivliev <ii@any.com.ru> |
28 |
+ * |
29 |
+ * $Id: $ |
30 |
+ */ |
31 |
+ |
32 |
+#include <config.h> |
33 |
+ |
34 |
+#include <exception> |
35 |
+#include <iostream> |
36 |
+#include <sys/limits.h> |
37 |
+#include <stdlib.h> |
38 |
+#include <getopt.h> |
39 |
+ |
40 |
+#include <pfs.h> |
41 |
+ |
42 |
+#define PROG_NAME "pfswb" |
43 |
+ |
44 |
+class QuietException |
45 |
+{ |
46 |
+}; |
47 |
+ |
48 |
+static void printHelp() |
49 |
+{ |
50 |
+ std::cerr << PROG_NAME " (" PACKAGE_STRING ") :\n" |
51 |
+ "\t[--red <val>] [--green <val>] [--blue <val>]\n" |
52 |
+ "\t[--auto] [--x <val>] [--y <val>] [--width <val>] [--height <val>]\n" |
53 |
+ "\t[--keep-lum]\n" |
54 |
+ "\t[--verbose] [--help]\n" |
55 |
+ "See man page for more information.\n"; |
56 |
+} |
57 |
+ |
58 |
+// verbose mode |
59 |
+static bool verbose = false; |
60 |
+ |
61 |
+// auto WB |
62 |
+static bool autowb = false; |
63 |
+// default gray box bounds |
64 |
+static int x = 0; |
65 |
+static int y = 0; |
66 |
+static int width = INT_MAX/2; |
67 |
+static int height = INT_MAX/2; |
68 |
+ |
69 |
+// keep original luminance |
70 |
+static bool keep = false; |
71 |
+ |
72 |
+// default WB multipliers |
73 |
+static float red = 1.f; |
74 |
+static float green = 1.f; |
75 |
+static float blue = 1.f; |
76 |
+ |
77 |
+static void multipliers( |
78 |
+ const pfs::Array2D &R, const pfs::Array2D &G, const pfs::Array2D &B, |
79 |
+ float &r, float &g, float &b) |
80 |
+{ |
81 |
+ r = red; |
82 |
+ g = green; |
83 |
+ b = blue; |
84 |
+ if (!autowb) return; |
85 |
+ // auto WB gray box |
86 |
+ int w = R.getCols(); |
87 |
+ int h = R.getRows(); |
88 |
+ if (x>=w || y>=h) |
89 |
+ throw pfs::Exception("gray box is out of frame bounds"); |
90 |
+ int x1 = width+x; |
91 |
+ if (x1>w) x1 = w; |
92 |
+ int y1 = height+y; |
93 |
+ if (y1>h) y1 = h; |
94 |
+ VERBOSE_STR |
95 |
+ << "auto WB gray box: " |
96 |
+ << (x1-x) << "x" << (y1-y) << "+" << x << "+" << y << std::endl; |
97 |
+ // auto WB multipliers |
98 |
+ double ar = 0.; |
99 |
+ double ag = 0.; |
100 |
+ double ab = 0.; |
101 |
+ for (int y0=y; y0<y1; ++y0) |
102 |
+ { |
103 |
+ for (int x0=x; x0<x1; ++x0) |
104 |
+ { |
105 |
+ ar += R(x0,y0); |
106 |
+ ag += G(x0,y0); |
107 |
+ ab += B(x0,y0); |
108 |
+ } |
109 |
+ } |
110 |
+ int n = (x1-x)*(y1-y); |
111 |
+ ar /= n; |
112 |
+ ag /= n; |
113 |
+ ab /= n; |
114 |
+ VERBOSE_STR << "average red value: " << ar << std::endl; |
115 |
+ VERBOSE_STR << "average green value: " << ag << std::endl; |
116 |
+ VERBOSE_STR << "average blue value: " << ab << std::endl; |
117 |
+ float a = (float)((ar+ag+ab)/3.); |
118 |
+ r *= a/ar; |
119 |
+ g *= a/ag; |
120 |
+ b *= a/ab; |
121 |
+} |
122 |
+ |
123 |
+static void pfswb() |
124 |
+{ |
125 |
+ pfs::DOMIO pfsio; |
126 |
+ VERBOSE_STR << "auto WB: " << (autowb ? "yes" : "no" ) << std::endl; |
127 |
+ VERBOSE_STR << "base red multiplier value: " << red << std::endl; |
128 |
+ VERBOSE_STR << "base green multiplier value: " << green << std::endl; |
129 |
+ VERBOSE_STR << "base blue multiplier value: " << blue << std::endl; |
130 |
+ VERBOSE_STR << "keep original luminance: " << (keep ? "yes" : "no" ) << std::endl; |
131 |
+ while (true) |
132 |
+ { |
133 |
+ // Read frame |
134 |
+ pfs::Frame *frame = pfsio.readFrame( stdin ); |
135 |
+ if (!frame) |
136 |
+ { |
137 |
+ break; // No more frames |
138 |
+ } |
139 |
+ // Get channels |
140 |
+ pfs::Channel *X, *Y, *Z; |
141 |
+ frame->getXYZChannels(X, Y, Z); |
142 |
+ if (!(Y && X && Z)) |
143 |
+ { |
144 |
+ throw pfs::Exception( "Missing X, Y, Z channels in the PFS stream" ); |
145 |
+ } |
146 |
+ int w = Y->getCols(); |
147 |
+ int h = Y->getRows(); |
148 |
+ int s = w*h; |
149 |
+ float min = 1e20, max = -1e20; |
150 |
+ for (int i=s; i--; ) |
151 |
+ { |
152 |
+ float const &l = (*Y)(i); |
153 |
+ if (min > l) min = l; |
154 |
+ if (max < l) max = l; |
155 |
+ } |
156 |
+ VERBOSE_STR << "luminance range of original frame: " << min << ":" << max << std::endl; |
157 |
+ // Convert from XYZ to RGB |
158 |
+ pfs::transformColorSpace(pfs::CS_XYZ, X, Y, Z, pfs::CS_RGB, X, Y, Z); |
159 |
+ // WB adjustment |
160 |
+ float r, g, b; |
161 |
+ multipliers(*X,*Y,*Z,r,g,b); |
162 |
+ VERBOSE_STR << "red multiplier value: " << r << std::endl; |
163 |
+ VERBOSE_STR << "green multiplier value: " << g << std::endl; |
164 |
+ VERBOSE_STR << "blue multiplier value: " << b << std::endl; |
165 |
+ for (int i=s; i--; ) |
166 |
+ { |
167 |
+ (*X)(i) *= r; |
168 |
+ (*Y)(i) *= g; |
169 |
+ (*Z)(i) *= b; |
170 |
+ } |
171 |
+ // Convert back to XYZ |
172 |
+ pfs::transformColorSpace(pfs::CS_RGB, X, Y, Z, pfs::CS_XYZ, X, Y, Z); |
173 |
+ float amin = 1e20, amax = -1e20; |
174 |
+ for (int i=s; i--; ) |
175 |
+ { |
176 |
+ float const &l = (*Y)(i); |
177 |
+ if (amin > l) amin = l; |
178 |
+ if (amax < l) amax = l; |
179 |
+ } |
180 |
+ VERBOSE_STR << "luminance range of adjusted frame: " << amin << ":" << amax << std::endl; |
181 |
+ if (keep) |
182 |
+ { |
183 |
+ float k = (max-min)/(amax-amin); |
184 |
+ float nmin = 1e20, nmax = -1e20; |
185 |
+ for (int i=s; i--; ) |
186 |
+ { |
187 |
+ float const &l = ((*Y)(i)-amin)*k+min; |
188 |
+ if (nmin > l) nmin = l; |
189 |
+ if (nmax < l) nmax = l; |
190 |
+ (*Y)(i) = l; |
191 |
+ } |
192 |
+ VERBOSE_STR << "restored luminance range: " << nmin << ":" << nmax << std::endl; |
193 |
+ } |
194 |
+ // Write frame |
195 |
+ pfsio.writeFrame(frame, stdout); |
196 |
+ pfsio.freeFrame(frame); |
197 |
+ } |
198 |
+} |
199 |
+ |
200 |
+int main(int argc, char *const argv[]) |
201 |
+{ |
202 |
+ static const struct option cmdLineOptions[] = { |
203 |
+ { "help", no_argument, NULL, 'h' }, |
204 |
+ { "verbose", no_argument, NULL, 'v' }, |
205 |
+ { "auto", no_argument, NULL, 'A' }, |
206 |
+ { "x", required_argument, NULL, 'X' }, |
207 |
+ { "y", required_argument, NULL, 'Y' }, |
208 |
+ { "width", required_argument, NULL, 'W' }, |
209 |
+ { "height", required_argument, NULL, 'H' }, |
210 |
+ { "keep-lum", no_argument, NULL, 'k' }, |
211 |
+ { "red", required_argument, NULL, 'r' }, |
212 |
+ { "green", required_argument, NULL, 'g' }, |
213 |
+ { "blue", required_argument, NULL, 'b' }, |
214 |
+ { NULL, 0, NULL, 0 } |
215 |
+ }; |
216 |
+ |
217 |
+ try |
218 |
+ { |
219 |
+ int optionIndex = 0; |
220 |
+ while (true) |
221 |
+ { |
222 |
+ int c = getopt_long(argc, argv, "hvAX:Y:W:H:kr:g:b:", cmdLineOptions, &optionIndex); |
223 |
+ if (c == -1) |
224 |
+ { |
225 |
+ break; |
226 |
+ } |
227 |
+ switch (c) |
228 |
+ { |
229 |
+ case 'h': |
230 |
+ printHelp(); |
231 |
+ throw QuietException(); |
232 |
+ case 'v': |
233 |
+ verbose = true; |
234 |
+ break; |
235 |
+ case 'A': |
236 |
+ autowb = true; |
237 |
+ break; |
238 |
+ case 'X': |
239 |
+ x = (int)strtol(optarg, NULL, 10); |
240 |
+ if (x<=0) |
241 |
+ throw pfs::Exception("gray box x value out of range, should be >0"); |
242 |
+ break; |
243 |
+ case 'Y': |
244 |
+ y = (int)strtol(optarg, NULL, 10); |
245 |
+ if (y<=0) |
246 |
+ throw pfs::Exception("gray box y value out of range, should be >0"); |
247 |
+ break; |
248 |
+ case 'W': |
249 |
+ width = (int)strtol(optarg, NULL, 10); |
250 |
+ if (width<=0) |
251 |
+ throw pfs::Exception("gray box width value out of range, should be >0"); |
252 |
+ break; |
253 |
+ case 'H': |
254 |
+ height = (int)strtol(optarg, NULL, 10); |
255 |
+ if (height<=0) |
256 |
+ throw pfs::Exception("gray box height value out of range, should be >0"); |
257 |
+ break; |
258 |
+ case 'k': |
259 |
+ keep = true; |
260 |
+ break; |
261 |
+ case 'r': |
262 |
+ red = strtof(optarg, NULL); |
263 |
+ if (red<=0.0f) |
264 |
+ throw pfs::Exception("red multiplier value out of range, should be >0"); |
265 |
+ break; |
266 |
+ case 'g': |
267 |
+ green = strtof(optarg, NULL); |
268 |
+ if (green<=0.0f) |
269 |
+ throw pfs::Exception("green multiplier value out of range, should be >0"); |
270 |
+ break; |
271 |
+ case 'b': |
272 |
+ blue = strtof(optarg, NULL); |
273 |
+ if (blue<=0.0f) |
274 |
+ throw pfs::Exception("blue multiplier value out of range, should be >0"); |
275 |
+ break; |
276 |
+ case '?': |
277 |
+ throw QuietException(); |
278 |
+ case ':': |
279 |
+ throw QuietException(); |
280 |
+ } |
281 |
+ } |
282 |
+ |
283 |
+ pfswb(); |
284 |
+ } |
285 |
+ catch (std::exception ex) |
286 |
+ { |
287 |
+ std::cerr << PROG_NAME" std error: " << ex.what() << std::endl; |
288 |
+ return EXIT_FAILURE; |
289 |
+ } |
290 |
+ catch (pfs::Exception ex) |
291 |
+ { |
292 |
+ std::cerr << PROG_NAME" error: " << ex.getMessage() << std::endl; |
293 |
+ return EXIT_FAILURE; |
294 |
+ } |
295 |
+ catch (QuietException ex) |
296 |
+ { |
297 |
+ return EXIT_FAILURE; |
298 |
+ } |
299 |
+ return EXIT_SUCCESS; |
300 |
+} |