/src/LibRaw/src/demosaic/dht_demosaic.cpp
Line | Count | Source |
1 | | /* -*- C++ -*- |
2 | | * File: dht_demosaic.cpp |
3 | | * Copyright 2013 Anton Petrusevich |
4 | | * Created: Tue Apr 9, 2013 |
5 | | * |
6 | | * This code is licensed under one of two licenses as you choose: |
7 | | * |
8 | | * 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 |
9 | | * (See file LICENSE.LGPL provided in LibRaw distribution archive for |
10 | | * details). |
11 | | * |
12 | | * 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 |
13 | | * (See file LICENSE.CDDL provided in LibRaw distribution archive for |
14 | | * details). |
15 | | * |
16 | | */ |
17 | | |
18 | | /* |
19 | | * функция вычисляет яркостную дистанцию. |
20 | | * если две яркости отличаются в два раза, например 10 и 20, то они имеют такой |
21 | | * же вес при принятии решения об интерполировании, как и 100 и 200 -- |
22 | | * фотографическая яркость между ними 1 стоп. дистанция всегда >=1 |
23 | | */ |
24 | | |
25 | | #include "../../internal/dmp_include.h" |
26 | | |
27 | | static inline float calc_dist(float c1, float c2) |
28 | 0 | { |
29 | 0 | return c1 > c2 ? c1 / c2 : c2 / c1; |
30 | 0 | } |
31 | | |
32 | | struct DHT |
33 | | { |
34 | | int nr_height, nr_width; |
35 | | static const int nr_topmargin = 4, nr_leftmargin = 4; |
36 | | float (*nraw)[3]; |
37 | | ushort channel_maximum[3]; |
38 | | float channel_minimum[3]; |
39 | | LibRaw &libraw; |
40 | | enum |
41 | | { |
42 | | HVSH = 1, |
43 | | HOR = 2, |
44 | | VER = 4, |
45 | | HORSH = HOR | HVSH, |
46 | | VERSH = VER | HVSH, |
47 | | DIASH = 8, |
48 | | LURD = 16, |
49 | | RULD = 32, |
50 | | LURDSH = LURD | DIASH, |
51 | | RULDSH = RULD | DIASH, |
52 | | HOT = 64 |
53 | | }; |
54 | 0 | static inline float Thot(void) throw() { return 64.0f; } |
55 | 0 | static inline float Tg(void) throw() { return 256.0f; } |
56 | 0 | static inline float T(void) throw() { return 1.4f; } |
57 | | char *ndir; |
58 | | inline int nr_offset(int row, int col) throw() |
59 | 0 | { |
60 | 0 | return (row * nr_width + col); |
61 | 0 | } |
62 | | int get_hv_grb(int x, int y, int kc) |
63 | 0 | { |
64 | 0 | float hv1 = 2 * nraw[nr_offset(y - 1, x)][1] / |
65 | 0 | (nraw[nr_offset(y - 2, x)][kc] + nraw[nr_offset(y, x)][kc]); |
66 | 0 | float hv2 = 2 * nraw[nr_offset(y + 1, x)][1] / |
67 | 0 | (nraw[nr_offset(y + 2, x)][kc] + nraw[nr_offset(y, x)][kc]); |
68 | 0 | float kv = calc_dist(hv1, hv2) * |
69 | 0 | calc_dist(nraw[nr_offset(y, x)][kc] * nraw[nr_offset(y, x)][kc], |
70 | 0 | (nraw[nr_offset(y - 2, x)][kc] * |
71 | 0 | nraw[nr_offset(y + 2, x)][kc])); |
72 | 0 | kv *= kv; |
73 | 0 | kv *= kv; |
74 | 0 | kv *= kv; |
75 | 0 | float dv = |
76 | 0 | kv * |
77 | 0 | calc_dist(nraw[nr_offset(y - 3, x)][1] * nraw[nr_offset(y + 3, x)][1], |
78 | 0 | nraw[nr_offset(y - 1, x)][1] * nraw[nr_offset(y + 1, x)][1]); |
79 | 0 | float hh1 = 2 * nraw[nr_offset(y, x - 1)][1] / |
80 | 0 | (nraw[nr_offset(y, x - 2)][kc] + nraw[nr_offset(y, x)][kc]); |
81 | 0 | float hh2 = 2 * nraw[nr_offset(y, x + 1)][1] / |
82 | 0 | (nraw[nr_offset(y, x + 2)][kc] + nraw[nr_offset(y, x)][kc]); |
83 | 0 | float kh = calc_dist(hh1, hh2) * |
84 | 0 | calc_dist(nraw[nr_offset(y, x)][kc] * nraw[nr_offset(y, x)][kc], |
85 | 0 | (nraw[nr_offset(y, x - 2)][kc] * |
86 | 0 | nraw[nr_offset(y, x + 2)][kc])); |
87 | 0 | kh *= kh; |
88 | 0 | kh *= kh; |
89 | 0 | kh *= kh; |
90 | 0 | float dh = |
91 | 0 | kh * |
92 | 0 | calc_dist(nraw[nr_offset(y, x - 3)][1] * nraw[nr_offset(y, x + 3)][1], |
93 | 0 | nraw[nr_offset(y, x - 1)][1] * nraw[nr_offset(y, x + 1)][1]); |
94 | 0 | float e = calc_dist(dh, dv); |
95 | 0 | char d = dh < dv ? (e > Tg() ? HORSH : HOR) : (e > Tg() ? VERSH : VER); |
96 | 0 | return d; |
97 | 0 | } |
98 | | int get_hv_rbg(int x, int y, int hc) |
99 | 0 | { |
100 | 0 | float hv1 = 2 * nraw[nr_offset(y - 1, x)][hc ^ 2] / |
101 | 0 | (nraw[nr_offset(y - 2, x)][1] + nraw[nr_offset(y, x)][1]); |
102 | 0 | float hv2 = 2 * nraw[nr_offset(y + 1, x)][hc ^ 2] / |
103 | 0 | (nraw[nr_offset(y + 2, x)][1] + nraw[nr_offset(y, x)][1]); |
104 | 0 | float kv = calc_dist(hv1, hv2) * |
105 | 0 | calc_dist(nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1], |
106 | 0 | (nraw[nr_offset(y - 2, x)][1] * |
107 | 0 | nraw[nr_offset(y + 2, x)][1])); |
108 | 0 | kv *= kv; |
109 | 0 | kv *= kv; |
110 | 0 | kv *= kv; |
111 | 0 | float dv = kv * calc_dist(nraw[nr_offset(y - 3, x)][hc ^ 2] * |
112 | 0 | nraw[nr_offset(y + 3, x)][hc ^ 2], |
113 | 0 | nraw[nr_offset(y - 1, x)][hc ^ 2] * |
114 | 0 | nraw[nr_offset(y + 1, x)][hc ^ 2]); |
115 | 0 | float hh1 = 2 * nraw[nr_offset(y, x - 1)][hc] / |
116 | 0 | (nraw[nr_offset(y, x - 2)][1] + nraw[nr_offset(y, x)][1]); |
117 | 0 | float hh2 = 2 * nraw[nr_offset(y, x + 1)][hc] / |
118 | 0 | (nraw[nr_offset(y, x + 2)][1] + nraw[nr_offset(y, x)][1]); |
119 | 0 | float kh = calc_dist(hh1, hh2) * |
120 | 0 | calc_dist(nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1], |
121 | 0 | (nraw[nr_offset(y, x - 2)][1] * |
122 | 0 | nraw[nr_offset(y, x + 2)][1])); |
123 | 0 | kh *= kh; |
124 | 0 | kh *= kh; |
125 | 0 | kh *= kh; |
126 | 0 | float dh = |
127 | 0 | kh * calc_dist( |
128 | 0 | nraw[nr_offset(y, x - 3)][hc] * nraw[nr_offset(y, x + 3)][hc], |
129 | 0 | nraw[nr_offset(y, x - 1)][hc] * nraw[nr_offset(y, x + 1)][hc]); |
130 | 0 | float e = calc_dist(dh, dv); |
131 | 0 | char d = dh < dv ? (e > Tg() ? HORSH : HOR) : (e > Tg() ? VERSH : VER); |
132 | 0 | return d; |
133 | 0 | } |
134 | | int get_diag_grb(int x, int y, int kc) |
135 | 0 | { |
136 | 0 | float hlu = |
137 | 0 | nraw[nr_offset(y - 1, x - 1)][1] / nraw[nr_offset(y - 1, x - 1)][kc]; |
138 | 0 | float hrd = |
139 | 0 | nraw[nr_offset(y + 1, x + 1)][1] / nraw[nr_offset(y + 1, x + 1)][kc]; |
140 | 0 | float dlurd = |
141 | 0 | calc_dist(hlu, hrd) * |
142 | 0 | calc_dist(nraw[nr_offset(y - 1, x - 1)][1] * |
143 | 0 | nraw[nr_offset(y + 1, x + 1)][1], |
144 | 0 | nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1]); |
145 | 0 | float druld = |
146 | 0 | calc_dist(hlu, hrd) * |
147 | 0 | calc_dist(nraw[nr_offset(y - 1, x + 1)][1] * |
148 | 0 | nraw[nr_offset(y + 1, x - 1)][1], |
149 | 0 | nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1]); |
150 | 0 | float e = calc_dist(dlurd, druld); |
151 | 0 | char d = |
152 | 0 | druld < dlurd ? (e > T() ? RULDSH : RULD) : (e > T() ? LURDSH : LURD); |
153 | 0 | return d; |
154 | 0 | } |
155 | | int get_diag_rbg(int x, int y, int /* hc */) |
156 | 0 | { |
157 | 0 | float dlurd = calc_dist( |
158 | 0 | nraw[nr_offset(y - 1, x - 1)][1] * nraw[nr_offset(y + 1, x + 1)][1], |
159 | 0 | nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1]); |
160 | 0 | float druld = calc_dist( |
161 | 0 | nraw[nr_offset(y - 1, x + 1)][1] * nraw[nr_offset(y + 1, x - 1)][1], |
162 | 0 | nraw[nr_offset(y, x)][1] * nraw[nr_offset(y, x)][1]); |
163 | 0 | float e = calc_dist(dlurd, druld); |
164 | 0 | char d = |
165 | 0 | druld < dlurd ? (e > T() ? RULDSH : RULD) : (e > T() ? LURDSH : LURD); |
166 | 0 | return d; |
167 | 0 | } |
168 | | static inline float scale_over(float ec, float base) |
169 | 0 | { |
170 | 0 | float s = base * .4f; |
171 | 0 | float o = ec - base; |
172 | 0 | return base + sqrt(s * (o + s)) - s; |
173 | 0 | } |
174 | | static inline float scale_under(float ec, float base) |
175 | 0 | { |
176 | 0 | float s = base * .6f; |
177 | 0 | float o = base - ec; |
178 | 0 | return base - sqrt(s * (o + s)) + s; |
179 | 0 | } |
180 | | ~DHT(); |
181 | | DHT(LibRaw &_libraw); |
182 | | void copy_to_image(); |
183 | | void make_greens(); |
184 | | void make_diag_dirs(); |
185 | | void make_hv_dirs(); |
186 | | void refine_hv_dirs(int i, int js); |
187 | | void refine_diag_dirs(int i, int js); |
188 | | void refine_ihv_dirs(int i); |
189 | | void refine_idiag_dirs(int i); |
190 | | void illustrate_dirs(); |
191 | | void illustrate_dline(int i); |
192 | | void make_hv_dline(int i); |
193 | | void make_diag_dline(int i); |
194 | | void make_gline(int i); |
195 | | void make_rbdiag(int i); |
196 | | void make_rbhv(int i); |
197 | | void make_rb(); |
198 | | void hide_hots(); |
199 | | void restore_hots(); |
200 | | }; |
201 | | |
202 | | typedef float float3[3]; |
203 | | |
204 | | /* |
205 | | * информация о цветах копируется во float в общем то с одной целью -- чтобы |
206 | | * вместо 0 можно было писать 0.5, что больше подходит для вычисления яркостной |
207 | | * разницы. причина: в целых числах разница в 1 стоп составляет ряд 8,4,2,1,0 -- |
208 | | * последнее число должно быть 0.5, которое непредствамио в целых числах. так же |
209 | | * это изменение позволяет не думать о специальных случаях деления на ноль. |
210 | | * |
211 | | * альтернативное решение: умножить все данные на 2 и в младший бит внести 1. |
212 | | * правда, всё равно придётся следить, чтобы при интерпретации зелёного цвета не |
213 | | * получился 0 при округлении, иначе проблема при интерпретации синих и красных. |
214 | | * |
215 | | */ |
216 | 0 | DHT::DHT(LibRaw &_libraw) : libraw(_libraw) |
217 | 0 | { |
218 | 0 | nr_height = libraw.imgdata.sizes.iheight + nr_topmargin * 2; |
219 | 0 | nr_width = libraw.imgdata.sizes.iwidth + nr_leftmargin * 2; |
220 | 0 | nraw = (float3 *)malloc(nr_height * nr_width * sizeof(float3)); |
221 | 0 | int iwidth = libraw.imgdata.sizes.iwidth; |
222 | 0 | ndir = (char *)calloc(nr_height * nr_width, 1); |
223 | 0 | channel_maximum[0] = channel_maximum[1] = channel_maximum[2] = 0; |
224 | 0 | channel_minimum[0] = libraw.imgdata.image[0][0]; |
225 | 0 | channel_minimum[1] = libraw.imgdata.image[0][1]; |
226 | 0 | channel_minimum[2] = libraw.imgdata.image[0][2]; |
227 | 0 | for (int i = 0; i < nr_height * nr_width; ++i) |
228 | 0 | nraw[i][0] = nraw[i][1] = nraw[i][2] = 0.5; |
229 | 0 | for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) |
230 | 0 | { |
231 | 0 | int col_cache[48]; |
232 | 0 | for (int j = 0; j < 48; ++j) |
233 | 0 | { |
234 | 0 | int l = libraw.COLOR(i, j); |
235 | 0 | if (l == 3) |
236 | 0 | l = 1; |
237 | 0 | col_cache[j] = l; |
238 | 0 | } |
239 | 0 | for (int j = 0; j < iwidth; ++j) |
240 | 0 | { |
241 | 0 | int l = col_cache[j % 48]; |
242 | 0 | unsigned short c = libraw.imgdata.image[i * iwidth + j][l]; |
243 | 0 | if (c != 0) |
244 | 0 | { |
245 | 0 | if (channel_maximum[l] < c) |
246 | 0 | channel_maximum[l] = c; |
247 | 0 | if (channel_minimum[l] > c) |
248 | 0 | channel_minimum[l] = c; |
249 | 0 | nraw[nr_offset(i + nr_topmargin, j + nr_leftmargin)][l] = (float)c; |
250 | 0 | } |
251 | 0 | } |
252 | 0 | } |
253 | 0 | channel_minimum[0] += .5; |
254 | 0 | channel_minimum[1] += .5; |
255 | 0 | channel_minimum[2] += .5; |
256 | 0 | } |
257 | | |
258 | | void DHT::hide_hots() |
259 | 0 | { |
260 | 0 | int iwidth = libraw.imgdata.sizes.iwidth; |
261 | | #if defined(LIBRAW_USE_OPENMP) |
262 | | #pragma omp parallel for schedule(guided) firstprivate(iwidth) |
263 | | #endif |
264 | 0 | for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) |
265 | 0 | { |
266 | 0 | int js = libraw.COLOR(i, 0) & 1; |
267 | 0 | int kc = libraw.COLOR(i, js); |
268 | | /* |
269 | | * js -- начальная х-координата, которая попадает мимо известного зелёного |
270 | | * kc -- известный цвет в точке интерполирования |
271 | | */ |
272 | 0 | for (int j = js; j < iwidth; j += 2) |
273 | 0 | { |
274 | 0 | int x = j + nr_leftmargin; |
275 | 0 | int y = i + nr_topmargin; |
276 | 0 | float c = nraw[nr_offset(y, x)][kc]; |
277 | 0 | if ((c > nraw[nr_offset(y, x + 2)][kc] && |
278 | 0 | c > nraw[nr_offset(y, x - 2)][kc] && |
279 | 0 | c > nraw[nr_offset(y - 2, x)][kc] && |
280 | 0 | c > nraw[nr_offset(y + 2, x)][kc] && |
281 | 0 | c > nraw[nr_offset(y, x + 1)][1] && |
282 | 0 | c > nraw[nr_offset(y, x - 1)][1] && |
283 | 0 | c > nraw[nr_offset(y - 1, x)][1] && |
284 | 0 | c > nraw[nr_offset(y + 1, x)][1]) || |
285 | 0 | (c < nraw[nr_offset(y, x + 2)][kc] && |
286 | 0 | c < nraw[nr_offset(y, x - 2)][kc] && |
287 | 0 | c < nraw[nr_offset(y - 2, x)][kc] && |
288 | 0 | c < nraw[nr_offset(y + 2, x)][kc] && |
289 | 0 | c < nraw[nr_offset(y, x + 1)][1] && |
290 | 0 | c < nraw[nr_offset(y, x - 1)][1] && |
291 | 0 | c < nraw[nr_offset(y - 1, x)][1] && |
292 | 0 | c < nraw[nr_offset(y + 1, x)][1])) |
293 | 0 | { |
294 | 0 | float avg = 0; |
295 | 0 | for (int k = -2; k < 3; k += 2) |
296 | 0 | for (int m = -2; m < 3; m += 2) |
297 | 0 | if (m == 0 && k == 0) |
298 | 0 | continue; |
299 | 0 | else |
300 | 0 | avg += nraw[nr_offset(y + k, x + m)][kc]; |
301 | 0 | avg /= 8; |
302 | | // float dev = 0; |
303 | | // for (int k = -2; k < 3; k += 2) |
304 | | // for (int l = -2; l < 3; l += 2) |
305 | | // if (k == 0 && l == 0) |
306 | | // continue; |
307 | | // else { |
308 | | // float t = nraw[nr_offset(y + k, x + l)][kc] - |
309 | | //avg; dev += t * t; |
310 | | // } |
311 | | // dev /= 8; |
312 | | // dev = sqrt(dev); |
313 | 0 | if (calc_dist(c, avg) > Thot()) |
314 | 0 | { |
315 | 0 | ndir[nr_offset(y, x)] |= HOT; |
316 | 0 | float dv = calc_dist( |
317 | 0 | nraw[nr_offset(y - 2, x)][kc] * nraw[nr_offset(y - 1, x)][1], |
318 | 0 | nraw[nr_offset(y + 2, x)][kc] * nraw[nr_offset(y + 1, x)][1]); |
319 | 0 | float dh = calc_dist( |
320 | 0 | nraw[nr_offset(y, x - 2)][kc] * nraw[nr_offset(y, x - 1)][1], |
321 | 0 | nraw[nr_offset(y, x + 2)][kc] * nraw[nr_offset(y, x + 1)][1]); |
322 | 0 | if (dv > dh) |
323 | 0 | nraw[nr_offset(y, x)][kc] = (nraw[nr_offset(y, x + 2)][kc] + |
324 | 0 | nraw[nr_offset(y, x - 2)][kc]) / |
325 | 0 | 2; |
326 | 0 | else |
327 | 0 | nraw[nr_offset(y, x)][kc] = (nraw[nr_offset(y - 2, x)][kc] + |
328 | 0 | nraw[nr_offset(y + 2, x)][kc]) / |
329 | 0 | 2; |
330 | 0 | } |
331 | 0 | } |
332 | 0 | } |
333 | 0 | for (int j = js ^ 1; j < iwidth; j += 2) |
334 | 0 | { |
335 | 0 | int x = j + nr_leftmargin; |
336 | 0 | int y = i + nr_topmargin; |
337 | 0 | float c = nraw[nr_offset(y, x)][1]; |
338 | 0 | if ((c > nraw[nr_offset(y, x + 2)][1] && |
339 | 0 | c > nraw[nr_offset(y, x - 2)][1] && |
340 | 0 | c > nraw[nr_offset(y - 2, x)][1] && |
341 | 0 | c > nraw[nr_offset(y + 2, x)][1] && |
342 | 0 | c > nraw[nr_offset(y, x + 1)][kc] && |
343 | 0 | c > nraw[nr_offset(y, x - 1)][kc] && |
344 | 0 | c > nraw[nr_offset(y - 1, x)][kc ^ 2] && |
345 | 0 | c > nraw[nr_offset(y + 1, x)][kc ^ 2]) || |
346 | 0 | (c < nraw[nr_offset(y, x + 2)][1] && |
347 | 0 | c < nraw[nr_offset(y, x - 2)][1] && |
348 | 0 | c < nraw[nr_offset(y - 2, x)][1] && |
349 | 0 | c < nraw[nr_offset(y + 2, x)][1] && |
350 | 0 | c < nraw[nr_offset(y, x + 1)][kc] && |
351 | 0 | c < nraw[nr_offset(y, x - 1)][kc] && |
352 | 0 | c < nraw[nr_offset(y - 1, x)][kc ^ 2] && |
353 | 0 | c < nraw[nr_offset(y + 1, x)][kc ^ 2])) |
354 | 0 | { |
355 | 0 | float avg = 0; |
356 | 0 | for (int k = -2; k < 3; k += 2) |
357 | 0 | for (int m = -2; m < 3; m += 2) |
358 | 0 | if (k == 0 && m == 0) |
359 | 0 | continue; |
360 | 0 | else |
361 | 0 | avg += nraw[nr_offset(y + k, x + m)][1]; |
362 | 0 | avg /= 8; |
363 | | // float dev = 0; |
364 | | // for (int k = -2; k < 3; k += 2) |
365 | | // for (int l = -2; l < 3; l += 2) |
366 | | // if (k == 0 && l == 0) |
367 | | // continue; |
368 | | // else { |
369 | | // float t = nraw[nr_offset(y + k, x + l)][1] - |
370 | | //avg; dev += t * t; |
371 | | // } |
372 | | // dev /= 8; |
373 | | // dev = sqrt(dev); |
374 | 0 | if (calc_dist(c, avg) > Thot()) |
375 | 0 | { |
376 | 0 | ndir[nr_offset(y, x)] |= HOT; |
377 | 0 | float dv = calc_dist( |
378 | 0 | nraw[nr_offset(y - 2, x)][1] * nraw[nr_offset(y - 1, x)][kc ^ 2], |
379 | 0 | nraw[nr_offset(y + 2, x)][1] * nraw[nr_offset(y + 1, x)][kc ^ 2]); |
380 | 0 | float dh = calc_dist( |
381 | 0 | nraw[nr_offset(y, x - 2)][1] * nraw[nr_offset(y, x - 1)][kc], |
382 | 0 | nraw[nr_offset(y, x + 2)][1] * nraw[nr_offset(y, x + 1)][kc]); |
383 | 0 | if (dv > dh) |
384 | 0 | nraw[nr_offset(y, x)][1] = |
385 | 0 | (nraw[nr_offset(y, x + 2)][1] + nraw[nr_offset(y, x - 2)][1]) / |
386 | 0 | 2; |
387 | 0 | else |
388 | 0 | nraw[nr_offset(y, x)][1] = |
389 | 0 | (nraw[nr_offset(y - 2, x)][1] + nraw[nr_offset(y + 2, x)][1]) / |
390 | 0 | 2; |
391 | 0 | } |
392 | 0 | } |
393 | 0 | } |
394 | 0 | } |
395 | 0 | } |
396 | | |
397 | | void DHT::restore_hots() |
398 | 0 | { |
399 | 0 | int iwidth = libraw.imgdata.sizes.iwidth; |
400 | | #if defined(LIBRAW_USE_OPENMP) |
401 | | #ifdef _MSC_VER |
402 | | #pragma omp parallel for firstprivate(iwidth) |
403 | | #else |
404 | | #pragma omp parallel for schedule(guided) firstprivate(iwidth) collapse(2) |
405 | | #endif |
406 | | #endif |
407 | 0 | for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) |
408 | 0 | { |
409 | 0 | for (int j = 0; j < iwidth; ++j) |
410 | 0 | { |
411 | 0 | int x = j + nr_leftmargin; |
412 | 0 | int y = i + nr_topmargin; |
413 | 0 | if (ndir[nr_offset(y, x)] & HOT) |
414 | 0 | { |
415 | 0 | int l = libraw.COLOR(i, j); |
416 | 0 | nraw[nr_offset(i + nr_topmargin, j + nr_leftmargin)][l] = |
417 | 0 | libraw.imgdata.image[i * iwidth + j][l]; |
418 | 0 | } |
419 | 0 | } |
420 | 0 | } |
421 | 0 | } |
422 | | |
423 | | void DHT::make_diag_dirs() |
424 | 0 | { |
425 | | #if defined(LIBRAW_USE_OPENMP) |
426 | | #pragma omp parallel for schedule(guided) |
427 | | #endif |
428 | 0 | for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) |
429 | 0 | { |
430 | 0 | make_diag_dline(i); |
431 | 0 | } |
432 | | //#if defined(LIBRAW_USE_OPENMP) |
433 | | //#pragma omp parallel for schedule(guided) |
434 | | //#endif |
435 | | // for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { |
436 | | // refine_diag_dirs(i, i & 1); |
437 | | // } |
438 | | //#if defined(LIBRAW_USE_OPENMP) |
439 | | //#pragma omp parallel for schedule(guided) |
440 | | //#endif |
441 | | // for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) { |
442 | | // refine_diag_dirs(i, (i & 1) ^ 1); |
443 | | // } |
444 | | #if defined(LIBRAW_USE_OPENMP) |
445 | | #pragma omp parallel for schedule(guided) |
446 | | #endif |
447 | 0 | for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) |
448 | 0 | { |
449 | 0 | refine_idiag_dirs(i); |
450 | 0 | } |
451 | 0 | } |
452 | | |
453 | | void DHT::make_hv_dirs() |
454 | 0 | { |
455 | | #if defined(LIBRAW_USE_OPENMP) |
456 | | #pragma omp parallel for schedule(guided) |
457 | | #endif |
458 | 0 | for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) |
459 | 0 | { |
460 | 0 | make_hv_dline(i); |
461 | 0 | } |
462 | | #if defined(LIBRAW_USE_OPENMP) |
463 | | #pragma omp parallel for schedule(guided) |
464 | | #endif |
465 | 0 | for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) |
466 | 0 | { |
467 | 0 | refine_hv_dirs(i, i & 1); |
468 | 0 | } |
469 | | #if defined(LIBRAW_USE_OPENMP) |
470 | | #pragma omp parallel for schedule(guided) |
471 | | #endif |
472 | 0 | for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) |
473 | 0 | { |
474 | 0 | refine_hv_dirs(i, (i & 1) ^ 1); |
475 | 0 | } |
476 | | #if defined(LIBRAW_USE_OPENMP) |
477 | | #pragma omp parallel for schedule(guided) |
478 | | #endif |
479 | 0 | for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) |
480 | 0 | { |
481 | 0 | refine_ihv_dirs(i); |
482 | 0 | } |
483 | 0 | } |
484 | | |
485 | | void DHT::refine_hv_dirs(int i, int js) |
486 | 0 | { |
487 | 0 | int iwidth = libraw.imgdata.sizes.iwidth; |
488 | 0 | for (int j = js; j < iwidth; j += 2) |
489 | 0 | { |
490 | 0 | int x = j + nr_leftmargin; |
491 | 0 | int y = i + nr_topmargin; |
492 | 0 | if (ndir[nr_offset(y, x)] & HVSH) |
493 | 0 | continue; |
494 | 0 | int nv = |
495 | 0 | (ndir[nr_offset(y - 1, x)] & VER) + (ndir[nr_offset(y + 1, x)] & VER) + |
496 | 0 | (ndir[nr_offset(y, x - 1)] & VER) + (ndir[nr_offset(y, x + 1)] & VER); |
497 | 0 | int nh = |
498 | 0 | (ndir[nr_offset(y - 1, x)] & HOR) + (ndir[nr_offset(y + 1, x)] & HOR) + |
499 | 0 | (ndir[nr_offset(y, x - 1)] & HOR) + (ndir[nr_offset(y, x + 1)] & HOR); |
500 | 0 | bool codir = (ndir[nr_offset(y, x)] & VER) |
501 | 0 | ? ((ndir[nr_offset(y - 1, x)] & VER) || |
502 | 0 | (ndir[nr_offset(y + 1, x)] & VER)) |
503 | 0 | : ((ndir[nr_offset(y, x - 1)] & HOR) || |
504 | 0 | (ndir[nr_offset(y, x + 1)] & HOR)); |
505 | 0 | nv /= VER; |
506 | 0 | nh /= HOR; |
507 | 0 | if ((ndir[nr_offset(y, x)] & VER) && (nh > 2 && !codir)) |
508 | 0 | { |
509 | 0 | ndir[nr_offset(y, x)] &= ~VER; |
510 | 0 | ndir[nr_offset(y, x)] |= HOR; |
511 | 0 | } |
512 | 0 | if ((ndir[nr_offset(y, x)] & HOR) && (nv > 2 && !codir)) |
513 | 0 | { |
514 | 0 | ndir[nr_offset(y, x)] &= ~HOR; |
515 | 0 | ndir[nr_offset(y, x)] |= VER; |
516 | 0 | } |
517 | 0 | } |
518 | 0 | } |
519 | | |
520 | | void DHT::refine_ihv_dirs(int i) |
521 | 0 | { |
522 | 0 | int iwidth = libraw.imgdata.sizes.iwidth; |
523 | 0 | for (int j = 0; j < iwidth; j++) |
524 | 0 | { |
525 | 0 | int x = j + nr_leftmargin; |
526 | 0 | int y = i + nr_topmargin; |
527 | 0 | if (ndir[nr_offset(y, x)] & HVSH) |
528 | 0 | continue; |
529 | 0 | int nv = |
530 | 0 | (ndir[nr_offset(y - 1, x)] & VER) + (ndir[nr_offset(y + 1, x)] & VER) + |
531 | 0 | (ndir[nr_offset(y, x - 1)] & VER) + (ndir[nr_offset(y, x + 1)] & VER); |
532 | 0 | int nh = |
533 | 0 | (ndir[nr_offset(y - 1, x)] & HOR) + (ndir[nr_offset(y + 1, x)] & HOR) + |
534 | 0 | (ndir[nr_offset(y, x - 1)] & HOR) + (ndir[nr_offset(y, x + 1)] & HOR); |
535 | 0 | nv /= VER; |
536 | 0 | nh /= HOR; |
537 | 0 | if ((ndir[nr_offset(y, x)] & VER) && nh > 3) |
538 | 0 | { |
539 | 0 | ndir[nr_offset(y, x)] &= ~VER; |
540 | 0 | ndir[nr_offset(y, x)] |= HOR; |
541 | 0 | } |
542 | 0 | if ((ndir[nr_offset(y, x)] & HOR) && nv > 3) |
543 | 0 | { |
544 | 0 | ndir[nr_offset(y, x)] &= ~HOR; |
545 | 0 | ndir[nr_offset(y, x)] |= VER; |
546 | 0 | } |
547 | 0 | } |
548 | 0 | } |
549 | | void DHT::make_hv_dline(int i) |
550 | 0 | { |
551 | 0 | int iwidth = libraw.imgdata.sizes.iwidth; |
552 | 0 | int js = libraw.COLOR(i, 0) & 1; |
553 | 0 | int kc = libraw.COLOR(i, js); |
554 | | /* |
555 | | * js -- начальная х-координата, которая попадает мимо известного зелёного |
556 | | * kc -- известный цвет в точке интерполирования |
557 | | */ |
558 | 0 | for (int j = 0; j < iwidth; j++) |
559 | 0 | { |
560 | 0 | int x = j + nr_leftmargin; |
561 | 0 | int y = i + nr_topmargin; |
562 | 0 | char d = 0; |
563 | 0 | if ((j & 1) == js) |
564 | 0 | { |
565 | 0 | d = get_hv_grb(x, y, kc); |
566 | 0 | } |
567 | 0 | else |
568 | 0 | { |
569 | 0 | d = get_hv_rbg(x, y, kc); |
570 | 0 | } |
571 | 0 | ndir[nr_offset(y, x)] |= d; |
572 | 0 | } |
573 | 0 | } |
574 | | |
575 | | void DHT::make_diag_dline(int i) |
576 | 0 | { |
577 | 0 | int iwidth = libraw.imgdata.sizes.iwidth; |
578 | 0 | int js = libraw.COLOR(i, 0) & 1; |
579 | 0 | int kc = libraw.COLOR(i, js); |
580 | | /* |
581 | | * js -- начальная х-координата, которая попадает мимо известного зелёного |
582 | | * kc -- известный цвет в точке интерполирования |
583 | | */ |
584 | 0 | for (int j = 0; j < iwidth; j++) |
585 | 0 | { |
586 | 0 | int x = j + nr_leftmargin; |
587 | 0 | int y = i + nr_topmargin; |
588 | 0 | char d = 0; |
589 | 0 | if ((j & 1) == js) |
590 | 0 | { |
591 | 0 | d = get_diag_grb(x, y, kc); |
592 | 0 | } |
593 | 0 | else |
594 | 0 | { |
595 | 0 | d = get_diag_rbg(x, y, kc); |
596 | 0 | } |
597 | 0 | ndir[nr_offset(y, x)] |= d; |
598 | 0 | } |
599 | 0 | } |
600 | | |
601 | | void DHT::refine_diag_dirs(int i, int js) |
602 | 0 | { |
603 | 0 | int iwidth = libraw.imgdata.sizes.iwidth; |
604 | 0 | for (int j = js; j < iwidth; j += 2) |
605 | 0 | { |
606 | 0 | int x = j + nr_leftmargin; |
607 | 0 | int y = i + nr_topmargin; |
608 | 0 | if (ndir[nr_offset(y, x)] & DIASH) |
609 | 0 | continue; |
610 | 0 | int nv = (ndir[nr_offset(y - 1, x)] & LURD) + |
611 | 0 | (ndir[nr_offset(y + 1, x)] & LURD) + |
612 | 0 | (ndir[nr_offset(y, x - 1)] & LURD) + |
613 | 0 | (ndir[nr_offset(y, x + 1)] & LURD) + |
614 | 0 | (ndir[nr_offset(y - 1, x - 1)] & LURD) + |
615 | 0 | (ndir[nr_offset(y - 1, x + 1)] & LURD) + |
616 | 0 | (ndir[nr_offset(y + 1, x - 1)] & LURD) + |
617 | 0 | (ndir[nr_offset(y + 1, x + 1)] & LURD); |
618 | 0 | int nh = (ndir[nr_offset(y - 1, x)] & RULD) + |
619 | 0 | (ndir[nr_offset(y + 1, x)] & RULD) + |
620 | 0 | (ndir[nr_offset(y, x - 1)] & RULD) + |
621 | 0 | (ndir[nr_offset(y, x + 1)] & RULD) + |
622 | 0 | (ndir[nr_offset(y - 1, x - 1)] & RULD) + |
623 | 0 | (ndir[nr_offset(y - 1, x + 1)] & RULD) + |
624 | 0 | (ndir[nr_offset(y + 1, x - 1)] & RULD) + |
625 | 0 | (ndir[nr_offset(y + 1, x + 1)] & RULD); |
626 | 0 | bool codir = (ndir[nr_offset(y, x)] & LURD) |
627 | 0 | ? ((ndir[nr_offset(y - 1, x - 1)] & LURD) || |
628 | 0 | (ndir[nr_offset(y + 1, x + 1)] & LURD)) |
629 | 0 | : ((ndir[nr_offset(y - 1, x + 1)] & RULD) || |
630 | 0 | (ndir[nr_offset(y + 1, x - 1)] & RULD)); |
631 | 0 | nv /= LURD; |
632 | 0 | nh /= RULD; |
633 | 0 | if ((ndir[nr_offset(y, x)] & LURD) && (nh > 4 && !codir)) |
634 | 0 | { |
635 | 0 | ndir[nr_offset(y, x)] &= ~LURD; |
636 | 0 | ndir[nr_offset(y, x)] |= RULD; |
637 | 0 | } |
638 | 0 | if ((ndir[nr_offset(y, x)] & RULD) && (nv > 4 && !codir)) |
639 | 0 | { |
640 | 0 | ndir[nr_offset(y, x)] &= ~RULD; |
641 | 0 | ndir[nr_offset(y, x)] |= LURD; |
642 | 0 | } |
643 | 0 | } |
644 | 0 | } |
645 | | |
646 | | void DHT::refine_idiag_dirs(int i) |
647 | 0 | { |
648 | 0 | int iwidth = libraw.imgdata.sizes.iwidth; |
649 | 0 | for (int j = 0; j < iwidth; j++) |
650 | 0 | { |
651 | 0 | int x = j + nr_leftmargin; |
652 | 0 | int y = i + nr_topmargin; |
653 | 0 | if (ndir[nr_offset(y, x)] & DIASH) |
654 | 0 | continue; |
655 | 0 | int nv = (ndir[nr_offset(y - 1, x)] & LURD) + |
656 | 0 | (ndir[nr_offset(y + 1, x)] & LURD) + |
657 | 0 | (ndir[nr_offset(y, x - 1)] & LURD) + |
658 | 0 | (ndir[nr_offset(y, x + 1)] & LURD) + |
659 | 0 | (ndir[nr_offset(y - 1, x - 1)] & LURD) + |
660 | 0 | (ndir[nr_offset(y - 1, x + 1)] & LURD) + |
661 | 0 | (ndir[nr_offset(y + 1, x - 1)] & LURD) + |
662 | 0 | (ndir[nr_offset(y + 1, x + 1)] & LURD); |
663 | 0 | int nh = (ndir[nr_offset(y - 1, x)] & RULD) + |
664 | 0 | (ndir[nr_offset(y + 1, x)] & RULD) + |
665 | 0 | (ndir[nr_offset(y, x - 1)] & RULD) + |
666 | 0 | (ndir[nr_offset(y, x + 1)] & RULD) + |
667 | 0 | (ndir[nr_offset(y - 1, x - 1)] & RULD) + |
668 | 0 | (ndir[nr_offset(y - 1, x + 1)] & RULD) + |
669 | 0 | (ndir[nr_offset(y + 1, x - 1)] & RULD) + |
670 | 0 | (ndir[nr_offset(y + 1, x + 1)] & RULD); |
671 | 0 | nv /= LURD; |
672 | 0 | nh /= RULD; |
673 | 0 | if ((ndir[nr_offset(y, x)] & LURD) && nh > 7) |
674 | 0 | { |
675 | 0 | ndir[nr_offset(y, x)] &= ~LURD; |
676 | 0 | ndir[nr_offset(y, x)] |= RULD; |
677 | 0 | } |
678 | 0 | if ((ndir[nr_offset(y, x)] & RULD) && nv > 7) |
679 | 0 | { |
680 | 0 | ndir[nr_offset(y, x)] &= ~RULD; |
681 | 0 | ndir[nr_offset(y, x)] |= LURD; |
682 | 0 | } |
683 | 0 | } |
684 | 0 | } |
685 | | |
686 | | /* |
687 | | * вычисление недостающих зелёных точек. |
688 | | */ |
689 | | void DHT::make_greens() |
690 | 0 | { |
691 | | #if defined(LIBRAW_USE_OPENMP) |
692 | | #pragma omp parallel for schedule(guided) |
693 | | #endif |
694 | 0 | for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) |
695 | 0 | { |
696 | 0 | make_gline(i); |
697 | 0 | } |
698 | 0 | } |
699 | | |
700 | | void DHT::make_gline(int i) |
701 | 0 | { |
702 | 0 | int iwidth = libraw.imgdata.sizes.iwidth; |
703 | 0 | int js = libraw.COLOR(i, 0) & 1; |
704 | 0 | int kc = libraw.COLOR(i, js); |
705 | | /* |
706 | | * js -- начальная х-координата, которая попадает мимо известного зелёного |
707 | | * kc -- известный цвет в точке интерполирования |
708 | | */ |
709 | 0 | for (int j = js; j < iwidth; j += 2) |
710 | 0 | { |
711 | 0 | int x = j + nr_leftmargin; |
712 | 0 | int y = i + nr_topmargin; |
713 | 0 | int dx, dy, dx2, dy2; |
714 | 0 | float h1, h2; |
715 | 0 | if (ndir[nr_offset(y, x)] & VER) |
716 | 0 | { |
717 | 0 | dx = dx2 = 0; |
718 | 0 | dy = -1; |
719 | 0 | dy2 = 1; |
720 | 0 | h1 = 2 * nraw[nr_offset(y - 1, x)][1] / |
721 | 0 | (nraw[nr_offset(y - 2, x)][kc] + nraw[nr_offset(y, x)][kc]); |
722 | 0 | h2 = 2 * nraw[nr_offset(y + 1, x)][1] / |
723 | 0 | (nraw[nr_offset(y + 2, x)][kc] + nraw[nr_offset(y, x)][kc]); |
724 | 0 | } |
725 | 0 | else |
726 | 0 | { |
727 | 0 | dy = dy2 = 0; |
728 | 0 | dx = 1; |
729 | 0 | dx2 = -1; |
730 | 0 | h1 = 2 * nraw[nr_offset(y, x + 1)][1] / |
731 | 0 | (nraw[nr_offset(y, x + 2)][kc] + nraw[nr_offset(y, x)][kc]); |
732 | 0 | h2 = 2 * nraw[nr_offset(y, x - 1)][1] / |
733 | 0 | (nraw[nr_offset(y, x - 2)][kc] + nraw[nr_offset(y, x)][kc]); |
734 | 0 | } |
735 | 0 | float b1 = 1 / calc_dist(nraw[nr_offset(y, x)][kc], |
736 | 0 | nraw[nr_offset(y + dy * 2, x + dx * 2)][kc]); |
737 | 0 | float b2 = 1 / calc_dist(nraw[nr_offset(y, x)][kc], |
738 | 0 | nraw[nr_offset(y + dy2 * 2, x + dx2 * 2)][kc]); |
739 | 0 | b1 *= b1; |
740 | 0 | b2 *= b2; |
741 | 0 | float eg = nraw[nr_offset(y, x)][kc] * (b1 * h1 + b2 * h2) / (b1 + b2); |
742 | 0 | float min, max; |
743 | 0 | min = MIN(nraw[nr_offset(y + dy, x + dx)][1], |
744 | 0 | nraw[nr_offset(y + dy2, x + dx2)][1]); |
745 | 0 | max = MAX(nraw[nr_offset(y + dy, x + dx)][1], |
746 | 0 | nraw[nr_offset(y + dy2, x + dx2)][1]); |
747 | 0 | min /= 1.2f; |
748 | 0 | max *= 1.2f; |
749 | 0 | if (eg < min) |
750 | 0 | eg = scale_under(eg, min); |
751 | 0 | else if (eg > max) |
752 | 0 | eg = scale_over(eg, max); |
753 | 0 | if (eg > channel_maximum[1]) |
754 | 0 | eg = channel_maximum[1]; |
755 | 0 | else if (eg < channel_minimum[1]) |
756 | 0 | eg = channel_minimum[1]; |
757 | 0 | nraw[nr_offset(y, x)][1] = eg; |
758 | 0 | } |
759 | 0 | } |
760 | | |
761 | | /* |
762 | | * отладочная функция |
763 | | */ |
764 | | |
765 | | void DHT::illustrate_dirs() |
766 | 0 | { |
767 | | #if defined(LIBRAW_USE_OPENMP) |
768 | | #pragma omp parallel for schedule(guided) |
769 | | #endif |
770 | 0 | for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) |
771 | 0 | { |
772 | 0 | illustrate_dline(i); |
773 | 0 | } |
774 | 0 | } |
775 | | |
776 | | void DHT::illustrate_dline(int i) |
777 | 0 | { |
778 | 0 | int iwidth = libraw.imgdata.sizes.iwidth; |
779 | 0 | for (int j = 0; j < iwidth; j++) |
780 | 0 | { |
781 | 0 | int x = j + nr_leftmargin; |
782 | 0 | int y = i + nr_topmargin; |
783 | 0 | nraw[nr_offset(y, x)][0] = nraw[nr_offset(y, x)][1] = |
784 | 0 | nraw[nr_offset(y, x)][2] = 0.5; |
785 | 0 | int l = ndir[nr_offset(y, x)] & 8; |
786 | | // l >>= 3; // WTF? |
787 | 0 | l = 1; |
788 | 0 | if (ndir[nr_offset(y, x)] & HOT) |
789 | 0 | nraw[nr_offset(y, x)][0] = |
790 | 0 | l * channel_maximum[0] / 4.f + channel_maximum[0] / 4.f; |
791 | 0 | else |
792 | 0 | nraw[nr_offset(y, x)][2] = |
793 | 0 | l * channel_maximum[2] / 4.f + channel_maximum[2] / 4.f; |
794 | 0 | } |
795 | 0 | } |
796 | | |
797 | | /* |
798 | | * интерполяция красных и синих. |
799 | | * |
800 | | * сначала интерполируются недостающие цвета, по диагональным направлениям от |
801 | | * которых находятся известные, затем ситуация сводится к тому как |
802 | | * интерполировались зелёные. |
803 | | */ |
804 | | |
805 | | void DHT::make_rbdiag(int i) |
806 | 0 | { |
807 | 0 | int iwidth = libraw.imgdata.sizes.iwidth; |
808 | 0 | int js = libraw.COLOR(i, 0) & 1; |
809 | 0 | int uc = libraw.COLOR(i, js); |
810 | 0 | int cl = uc ^ 2; |
811 | | /* |
812 | | * js -- начальная х-координата, которая попадает на уже интерполированный |
813 | | * зелёный al -- известный цвет (кроме зелёного) в точке интерполирования cl |
814 | | * -- неизвестный цвет |
815 | | */ |
816 | 0 | for (int j = js; j < iwidth; j += 2) |
817 | 0 | { |
818 | 0 | int x = j + nr_leftmargin; |
819 | 0 | int y = i + nr_topmargin; |
820 | 0 | int dx, dy, dx2, dy2; |
821 | 0 | if (ndir[nr_offset(y, x)] & LURD) |
822 | 0 | { |
823 | 0 | dx = -1; |
824 | 0 | dx2 = 1; |
825 | 0 | dy = -1; |
826 | 0 | dy2 = 1; |
827 | 0 | } |
828 | 0 | else |
829 | 0 | { |
830 | 0 | dx = -1; |
831 | 0 | dx2 = 1; |
832 | 0 | dy = 1; |
833 | 0 | dy2 = -1; |
834 | 0 | } |
835 | 0 | float g1 = 1 / calc_dist(nraw[nr_offset(y, x)][1], |
836 | 0 | nraw[nr_offset(y + dy, x + dx)][1]); |
837 | 0 | float g2 = 1 / calc_dist(nraw[nr_offset(y, x)][1], |
838 | 0 | nraw[nr_offset(y + dy2, x + dx2)][1]); |
839 | 0 | g1 *= g1 * g1; |
840 | 0 | g2 *= g2 * g2; |
841 | |
|
842 | 0 | float eg; |
843 | 0 | eg = nraw[nr_offset(y, x)][1] * |
844 | 0 | (g1 * nraw[nr_offset(y + dy, x + dx)][cl] / |
845 | 0 | nraw[nr_offset(y + dy, x + dx)][1] + |
846 | 0 | g2 * nraw[nr_offset(y + dy2, x + dx2)][cl] / |
847 | 0 | nraw[nr_offset(y + dy2, x + dx2)][1]) / |
848 | 0 | (g1 + g2); |
849 | 0 | float min, max; |
850 | 0 | min = MIN(nraw[nr_offset(y + dy, x + dx)][cl], |
851 | 0 | nraw[nr_offset(y + dy2, x + dx2)][cl]); |
852 | 0 | max = MAX(nraw[nr_offset(y + dy, x + dx)][cl], |
853 | 0 | nraw[nr_offset(y + dy2, x + dx2)][cl]); |
854 | 0 | min /= 1.2f; |
855 | 0 | max *= 1.2f; |
856 | 0 | if (eg < min) |
857 | 0 | eg = scale_under(eg, min); |
858 | 0 | else if (eg > max) |
859 | 0 | eg = scale_over(eg, max); |
860 | 0 | if (eg > channel_maximum[cl]) |
861 | 0 | eg = channel_maximum[cl]; |
862 | 0 | else if (eg < channel_minimum[cl]) |
863 | 0 | eg = channel_minimum[cl]; |
864 | 0 | nraw[nr_offset(y, x)][cl] = eg; |
865 | 0 | } |
866 | 0 | } |
867 | | |
868 | | /* |
869 | | * интерполяция красных и синих в точках где был известен только зелёный, |
870 | | * направления горизонтальные или вертикальные |
871 | | */ |
872 | | |
873 | | void DHT::make_rbhv(int i) |
874 | 0 | { |
875 | 0 | int iwidth = libraw.imgdata.sizes.iwidth; |
876 | 0 | int js = (libraw.COLOR(i, 0) & 1) ^ 1; |
877 | 0 | for (int j = js; j < iwidth; j += 2) |
878 | 0 | { |
879 | 0 | int x = j + nr_leftmargin; |
880 | 0 | int y = i + nr_topmargin; |
881 | | /* |
882 | | * поскольку сверху-снизу и справа-слева уже есть все необходимые красные и |
883 | | * синие, то можно выбрать наилучшее направление исходя из информации по |
884 | | * обоим цветам. |
885 | | */ |
886 | 0 | int dx, dy, dx2, dy2; |
887 | 0 | if (ndir[nr_offset(y, x)] & VER) |
888 | 0 | { |
889 | 0 | dx = dx2 = 0; |
890 | 0 | dy = -1; |
891 | 0 | dy2 = 1; |
892 | 0 | } |
893 | 0 | else |
894 | 0 | { |
895 | 0 | dy = dy2 = 0; |
896 | 0 | dx = 1; |
897 | 0 | dx2 = -1; |
898 | 0 | } |
899 | 0 | float g1 = 1 / calc_dist(nraw[nr_offset(y, x)][1], |
900 | 0 | nraw[nr_offset(y + dy, x + dx)][1]); |
901 | 0 | float g2 = 1 / calc_dist(nraw[nr_offset(y, x)][1], |
902 | 0 | nraw[nr_offset(y + dy2, x + dx2)][1]); |
903 | 0 | g1 *= g1; |
904 | 0 | g2 *= g2; |
905 | 0 | float eg_r, eg_b; |
906 | 0 | eg_r = nraw[nr_offset(y, x)][1] * |
907 | 0 | (g1 * nraw[nr_offset(y + dy, x + dx)][0] / |
908 | 0 | nraw[nr_offset(y + dy, x + dx)][1] + |
909 | 0 | g2 * nraw[nr_offset(y + dy2, x + dx2)][0] / |
910 | 0 | nraw[nr_offset(y + dy2, x + dx2)][1]) / |
911 | 0 | (g1 + g2); |
912 | 0 | eg_b = nraw[nr_offset(y, x)][1] * |
913 | 0 | (g1 * nraw[nr_offset(y + dy, x + dx)][2] / |
914 | 0 | nraw[nr_offset(y + dy, x + dx)][1] + |
915 | 0 | g2 * nraw[nr_offset(y + dy2, x + dx2)][2] / |
916 | 0 | nraw[nr_offset(y + dy2, x + dx2)][1]) / |
917 | 0 | (g1 + g2); |
918 | 0 | float min_r, max_r; |
919 | 0 | min_r = MIN(nraw[nr_offset(y + dy, x + dx)][0], |
920 | 0 | nraw[nr_offset(y + dy2, x + dx2)][0]); |
921 | 0 | max_r = MAX(nraw[nr_offset(y + dy, x + dx)][0], |
922 | 0 | nraw[nr_offset(y + dy2, x + dx2)][0]); |
923 | 0 | float min_b, max_b; |
924 | 0 | min_b = MIN(nraw[nr_offset(y + dy, x + dx)][2], |
925 | 0 | nraw[nr_offset(y + dy2, x + dx2)][2]); |
926 | 0 | max_b = MAX(nraw[nr_offset(y + dy, x + dx)][2], |
927 | 0 | nraw[nr_offset(y + dy2, x + dx2)][2]); |
928 | 0 | min_r /= 1.2f; |
929 | 0 | max_r *= 1.2f; |
930 | 0 | min_b /= 1.2f; |
931 | 0 | max_b *= 1.2f; |
932 | |
|
933 | 0 | if (eg_r < min_r) |
934 | 0 | eg_r = scale_under(eg_r, min_r); |
935 | 0 | else if (eg_r > max_r) |
936 | 0 | eg_r = scale_over(eg_r, max_r); |
937 | 0 | if (eg_b < min_b) |
938 | 0 | eg_b = scale_under(eg_b, min_b); |
939 | 0 | else if (eg_b > max_b) |
940 | 0 | eg_b = scale_over(eg_b, max_b); |
941 | |
|
942 | 0 | if (eg_r > channel_maximum[0]) |
943 | 0 | eg_r = channel_maximum[0]; |
944 | 0 | else if (eg_r < channel_minimum[0]) |
945 | 0 | eg_r = channel_minimum[0]; |
946 | 0 | if (eg_b > channel_maximum[2]) |
947 | 0 | eg_b = channel_maximum[2]; |
948 | 0 | else if (eg_b < channel_minimum[2]) |
949 | 0 | eg_b = channel_minimum[2]; |
950 | 0 | nraw[nr_offset(y, x)][0] = eg_r; |
951 | 0 | nraw[nr_offset(y, x)][2] = eg_b; |
952 | 0 | } |
953 | 0 | } |
954 | | |
955 | | void DHT::make_rb() |
956 | 0 | { |
957 | | #if defined(LIBRAW_USE_OPENMP) |
958 | | #pragma omp barrier |
959 | | #pragma omp parallel for schedule(guided) |
960 | | #endif |
961 | 0 | for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) |
962 | 0 | { |
963 | 0 | make_rbdiag(i); |
964 | 0 | } |
965 | | #if defined(LIBRAW_USE_OPENMP) |
966 | | #pragma omp barrier |
967 | | #pragma omp parallel for schedule(guided) |
968 | | #endif |
969 | 0 | for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) |
970 | 0 | { |
971 | 0 | make_rbhv(i); |
972 | 0 | } |
973 | 0 | } |
974 | | |
975 | | /* |
976 | | * перенос изображения в выходной массив |
977 | | */ |
978 | | void DHT::copy_to_image() |
979 | 0 | { |
980 | 0 | int iwidth = libraw.imgdata.sizes.iwidth; |
981 | | #if defined(LIBRAW_USE_OPENMP) |
982 | | #ifdef _MSC_VER |
983 | | #pragma omp parallel for |
984 | | #else |
985 | | #pragma omp parallel for schedule(guided) collapse(2) |
986 | | #endif |
987 | | #endif |
988 | 0 | for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) |
989 | 0 | { |
990 | 0 | for (int j = 0; j < iwidth; ++j) |
991 | 0 | { |
992 | 0 | libraw.imgdata.image[i * iwidth + j][0] = |
993 | 0 | (unsigned short)(nraw[nr_offset(i + nr_topmargin, j + nr_leftmargin)] |
994 | 0 | [0]); |
995 | 0 | libraw.imgdata.image[i * iwidth + j][2] = |
996 | 0 | (unsigned short)(nraw[nr_offset(i + nr_topmargin, j + nr_leftmargin)] |
997 | 0 | [2]); |
998 | 0 | libraw.imgdata.image[i * iwidth + j][1] = |
999 | 0 | libraw.imgdata.image[i * iwidth + j][3] = |
1000 | 0 | (unsigned short)(nraw[nr_offset(i + nr_topmargin, |
1001 | 0 | j + nr_leftmargin)][1]); |
1002 | 0 | } |
1003 | 0 | } |
1004 | 0 | } |
1005 | | |
1006 | | DHT::~DHT() |
1007 | 0 | { |
1008 | 0 | free(nraw); |
1009 | 0 | free(ndir); |
1010 | 0 | } |
1011 | | |
1012 | | void LibRaw::dht_interpolate() |
1013 | 0 | { |
1014 | 0 | if (imgdata.idata.filters != 0x16161616 |
1015 | 0 | && imgdata.idata.filters != 0x61616161 |
1016 | 0 | && imgdata.idata.filters != 0x49494949 |
1017 | 0 | && imgdata.idata.filters != 0x94949494 |
1018 | 0 | ) |
1019 | 0 | { |
1020 | 0 | ahd_interpolate(); |
1021 | 0 | return; |
1022 | 0 | } |
1023 | 0 | DHT dht(*this); |
1024 | 0 | dht.hide_hots(); |
1025 | 0 | dht.make_hv_dirs(); |
1026 | | // dht.illustrate_dirs(); |
1027 | 0 | dht.make_greens(); |
1028 | 0 | dht.make_diag_dirs(); |
1029 | | // dht.illustrate_dirs(); |
1030 | 0 | dht.make_rb(); |
1031 | 0 | dht.restore_hots(); |
1032 | 0 | dht.copy_to_image(); |
1033 | 0 | } |