/src/LibRaw/src/demosaic/xtrans_demosaic.cpp
Line | Count | Source |
1 | | /* -*- C++ -*- |
2 | | * Copyright 2019-2025 LibRaw LLC (info@libraw.org) |
3 | | * |
4 | | LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, |
5 | | dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. |
6 | | LibRaw do not use RESTRICTED code from dcraw.c |
7 | | |
8 | | LibRaw is free software; you can redistribute it and/or modify |
9 | | it under the terms of the one of two licenses as you choose: |
10 | | |
11 | | 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 |
12 | | (See file LICENSE.LGPL provided in LibRaw distribution archive for details). |
13 | | |
14 | | 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 |
15 | | (See file LICENSE.CDDL provided in LibRaw distribution archive for details). |
16 | | |
17 | | */ |
18 | | |
19 | | #include "../../internal/dcraw_defs.h" |
20 | | |
21 | 472M | #define fcol(row, col) xtrans[(row + 6) % 6][(col + 6) % 6] |
22 | | /* |
23 | | Frank Markesteijn's algorithm for Fuji X-Trans sensors |
24 | | */ |
25 | | void LibRaw::xtrans_interpolate(int passes) |
26 | 84 | { |
27 | 84 | int cstat[4] = {0, 0, 0, 0}; |
28 | 84 | int ndir; |
29 | 84 | static const short orth[12] = {1, 0, 0, 1, -1, 0, 0, -1, 1, 0, 0, 1}, |
30 | 84 | patt[2][16] = {{0, 1, 0, -1, 2, 0, -1, 0, 1, 1, 1, -1, 0, |
31 | 84 | 0, 0, 0}, |
32 | 84 | {0, 1, 0, -2, 1, 0, -2, 0, 1, 1, -2, -2, 1, |
33 | 84 | -1, -1, 1}}, |
34 | 84 | dir[4] = {1, LIBRAW_AHD_TILE, LIBRAW_AHD_TILE + 1, |
35 | 84 | LIBRAW_AHD_TILE - 1}; |
36 | 84 | short allhex[3][3][2][8]; |
37 | 84 | ushort sgrow = 0, sgcol = 0; |
38 | | |
39 | 84 | if (width < LIBRAW_AHD_TILE || height < LIBRAW_AHD_TILE || filters != 9) |
40 | 10 | throw LIBRAW_EXCEPTION_IO_CORRUPT; // too small image |
41 | | /* Check against right pattern */ |
42 | 518 | for (int row = 0; row < 6; row++) |
43 | 3.10k | for (int col = 0; col < 6; col++) |
44 | 2.66k | cstat[(unsigned)fcol(row, col)]++; |
45 | | |
46 | 74 | if (cstat[0] < 6 || cstat[0] > 10 || cstat[1] < 16 || cstat[1] > 24 || |
47 | 69 | cstat[2] < 6 || cstat[2] > 10 || cstat[3]) |
48 | 8 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
49 | | |
50 | | // Init allhex table to unreasonable values |
51 | 264 | for (int i = 0; i < 3; i++) |
52 | 792 | for (int j = 0; j < 3; j++) |
53 | 1.78k | for (int k = 0; k < 2; k++) |
54 | 10.6k | for (int l = 0; l < 8; l++) |
55 | 9.50k | allhex[i][j][k][l] = 32700; |
56 | | |
57 | 66 | cielab(0, 0); |
58 | 66 | ndir = 4 << int(passes > 1); |
59 | | |
60 | 66 | int minv = 0, maxv = 0, minh = 0, maxh = 0; |
61 | | /* Map a green hexagon around each non-green pixel and vice versa: */ |
62 | 264 | for (int row = 0; row < 3; row++) |
63 | 792 | for (int col = 0; col < 3; col++) |
64 | 3.56k | for (int ng = 0, d = 0; d < 10; d += 2) |
65 | 2.97k | { |
66 | 2.97k | int g = fcol(row, col) == 1; |
67 | 2.97k | if (fcol(row + orth[d], col + orth[d + 2]) == 1) |
68 | 1.94k | ng = 0; |
69 | 1.02k | else |
70 | 1.02k | ng++; |
71 | 2.97k | if (ng == 4) |
72 | 35 | { |
73 | 35 | sgrow = row; |
74 | 35 | sgcol = col; |
75 | 35 | } |
76 | 2.97k | if (ng == g + 1) |
77 | 374 | { |
78 | 374 | int c; |
79 | 374 | FORC(8) |
80 | 2.99k | { |
81 | 2.99k | int v = orth[d] * patt[g][c * 2] + orth[d + 1] * patt[g][c * 2 + 1]; |
82 | 2.99k | int h = orth[d + 2] * patt[g][c * 2] + orth[d + 3] * patt[g][c * 2 + 1]; |
83 | 2.99k | minv = MIN(v, minv); |
84 | 2.99k | maxv = MAX(v, maxv); |
85 | 2.99k | minh = MIN(h, minh); |
86 | 2.99k | maxh = MAX(h, maxh); |
87 | 2.99k | allhex[row][col][0][c ^ (g * 2 & d)] = h + v * width; |
88 | 2.99k | allhex[row][col][1][c ^ (g * 2 & d)] = h + v * LIBRAW_AHD_TILE; |
89 | 2.99k | } |
90 | 374 | } |
91 | 2.97k | } |
92 | | |
93 | | // Check allhex table initialization |
94 | 233 | for (int i = 0; i < 3; i++) |
95 | 684 | for (int j = 0; j < 3; j++) |
96 | 1.52k | for (int k = 0; k < 2; k++) |
97 | 9.12k | for (int l = 0; l < 8; l++) |
98 | 8.11k | if (allhex[i][j][k][l] > maxh + maxv * width + 1 || |
99 | 8.10k | allhex[i][j][k][l] < minh + minv * width - 1) |
100 | 11 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
101 | 55 | int retrycount = 0; |
102 | | |
103 | | /* Set green1 and green3 to the minimum and maximum allowed values: */ |
104 | 31.3k | for (int row = 2; row < height - 2; row++) |
105 | 31.2k | { |
106 | 31.2k | int col; |
107 | 31.2k | ushort min, max; |
108 | 472M | for (col = 2, max = 0u, min = 0xffffu; col < int(width) - 2; col++) |
109 | 472M | { |
110 | 472M | if (fcol(row, col) == 1 && (min = ~(max = 0))) |
111 | 306M | continue; |
112 | 165M | ushort(*pix)[4]; |
113 | 165M | pix = image + row * width + col; |
114 | 165M | short* hex = allhex[row % 3][col % 3][0]; |
115 | 165M | if (!max) |
116 | 113M | { |
117 | 113M | int c; |
118 | 113M | FORC(6) |
119 | 679M | { |
120 | 679M | int val = pix[hex[c]][1]; |
121 | 679M | if (min > val) |
122 | 172M | min = val; |
123 | 679M | if (max < val) |
124 | 114M | max = val; |
125 | 679M | } |
126 | 113M | } |
127 | 165M | pix[0][1] = min; |
128 | 165M | pix[0][3] = max; |
129 | 165M | switch ((row - sgrow) % 3) |
130 | 165M | { |
131 | 52.5M | case 1: |
132 | 52.5M | if (row < height - 3) |
133 | 52.2M | { |
134 | 52.2M | row++; |
135 | 52.2M | col--; |
136 | 52.2M | } |
137 | 52.5M | break; |
138 | 52.2M | case 2: |
139 | 52.2M | if ((min = ~(max = 0)) && (col += 2) < width - 3 && row > 2) |
140 | 52.2M | { |
141 | 52.2M | row--; |
142 | 52.2M | if (retrycount++ > width * height) |
143 | 2 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
144 | 52.2M | } |
145 | 165M | } |
146 | 165M | } |
147 | 31.2k | } |
148 | | |
149 | 76 | for (int row = 3; row < 9 && row < height - 3; row++) |
150 | 305 | for (int col = 3; col < 9 && col < width - 3; col++) |
151 | 282 | { |
152 | 282 | if ((fcol(row, col)) == 1) |
153 | 120 | continue; |
154 | 162 | short* hex = allhex[row % 3][col % 3][0]; |
155 | 162 | int c; |
156 | 162 | FORC(2) |
157 | 293 | { |
158 | 293 | int idx3 = 3 * hex[4 + c] + row * width + col; |
159 | 293 | int idx4 = -3 * hex[4 + c] + row * width + col; |
160 | 293 | int maxidx = width * height; |
161 | 293 | if (idx3 < 0 || idx3 >= maxidx) |
162 | 20 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
163 | 273 | if (idx4 < 0 || idx4 >= maxidx) |
164 | 33 | throw LIBRAW_EXCEPTION_IO_CORRUPT; |
165 | 273 | } |
166 | 162 | } |
167 | | |
168 | | #if defined(LIBRAW_USE_OPENMP) |
169 | | int buffer_count = omp_get_max_threads(); |
170 | | #else |
171 | 0 | int buffer_count = 1; |
172 | 0 | #endif |
173 | |
|
174 | 0 | size_t buffer_size = LIBRAW_AHD_TILE * LIBRAW_AHD_TILE * (ndir * 11 + 6); |
175 | 0 | char** buffers = malloc_omp_buffers(buffer_count, buffer_size); |
176 | 0 | INT64 allocate_sz = (INT64(iheight) + 6) * (INT64(iwidth) + 6) * sizeof(ushort)*4LL; |
177 | 0 | ushort (*destimage)[4] = (ushort(*)[4])calloc(allocate_sz, 1); |
178 | | // For border interpolate: keep original pixels |
179 | 0 | memmove(destimage,image,allocate_sz); |
180 | |
|
181 | | #if defined(LIBRAW_USE_OPENMP) |
182 | | # pragma omp parallel for schedule(dynamic) default(none) firstprivate(buffers, allhex, passes, sgrow, sgcol, ndir) shared(dir, destimage) |
183 | | #endif |
184 | 0 | for (int top = 3; top < height - 19; top += LIBRAW_AHD_TILE - 16) |
185 | 0 | { |
186 | | #if defined(LIBRAW_USE_OPENMP) |
187 | | char* buffer = buffers[omp_get_thread_num()]; |
188 | | #else |
189 | 0 | char* buffer = buffers[0]; |
190 | 0 | #endif |
191 | |
|
192 | 0 | ushort(*rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3], (*rix)[3]; |
193 | 0 | short(*lab)[LIBRAW_AHD_TILE][3], (*lix)[3]; |
194 | 0 | float(*drv)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE]; |
195 | 0 | char(*homo)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE]; |
196 | |
|
197 | 0 | rgb = (ushort(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])buffer; |
198 | 0 | lab = (short(*)[LIBRAW_AHD_TILE][3])( |
199 | 0 | buffer + LIBRAW_AHD_TILE * LIBRAW_AHD_TILE * (ndir * 6)); |
200 | 0 | drv = (float(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE])( |
201 | 0 | buffer + LIBRAW_AHD_TILE * LIBRAW_AHD_TILE * (ndir * 6 + 6)); |
202 | 0 | homo = (char(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE])( |
203 | 0 | buffer + LIBRAW_AHD_TILE * LIBRAW_AHD_TILE * (ndir * 10 + 6)); |
204 | |
|
205 | 0 | for (int left = 3; left < width - 19; left += LIBRAW_AHD_TILE - 16) |
206 | 0 | { |
207 | 0 | int mrow = MIN(top + LIBRAW_AHD_TILE, height - 3); |
208 | 0 | int mcol = MIN(left + LIBRAW_AHD_TILE, width - 3); |
209 | 0 | for (int row = top; row < mrow; row++) |
210 | 0 | for (int col = left; col < mcol; col++) |
211 | 0 | memcpy(rgb[0][row - top][col - left], image[row * width + col], 6); |
212 | 0 | int c; |
213 | 0 | FORC3 memcpy(rgb[c + 1], rgb[0], sizeof * rgb); |
214 | | |
215 | | /* Interpolate green horizontally, vertically, and along both diagonals: |
216 | | */ |
217 | 0 | int color[3][8]; |
218 | 0 | for (int row = top; row < mrow; row++) |
219 | 0 | for (int col = left; col < mcol; col++) |
220 | 0 | { |
221 | 0 | int f; |
222 | 0 | if ((f = fcol(row, col)) == 1) |
223 | 0 | continue; |
224 | 0 | ushort (*pix)[4] = image + row * width + col; |
225 | 0 | short* hex = allhex[row % 3][col % 3][0]; |
226 | 0 | color[1][0] = 174 * (pix[hex[1]][1] + pix[hex[0]][1]) - |
227 | 0 | 46 * (pix[2 * hex[1]][1] + pix[2 * hex[0]][1]); |
228 | 0 | color[1][1] = 223 * pix[hex[3]][1] + pix[hex[2]][1] * 33 + |
229 | 0 | 92 * (pix[0][f] - pix[-hex[2]][f]); |
230 | 0 | FORC(2) |
231 | 0 | color[1][2 + c] = 164 * pix[hex[4 + c]][1] + |
232 | 0 | 92 * pix[-2 * hex[4 + c]][1] + |
233 | 0 | 33 * (2 * pix[0][f] - pix[3 * hex[4 + c]][f] - |
234 | 0 | pix[-3 * hex[4 + c]][f]); |
235 | 0 | FORC4 rgb[c ^ !((row - sgrow) % 3)][row - top][col - left][1] = |
236 | 0 | LIM(color[1][c] >> 8, pix[0][1], pix[0][3]); |
237 | 0 | } |
238 | |
|
239 | 0 | for (int pass = 0; pass < passes; pass++) |
240 | 0 | { |
241 | 0 | if (pass == 1) |
242 | 0 | memcpy(rgb += 4, buffer, 4 * sizeof * rgb); |
243 | | |
244 | | /* Recalculate green from interpolated values of closer pixels: */ |
245 | 0 | if (pass) |
246 | 0 | { |
247 | 0 | for (int row = top + 2; row < mrow - 2; row++) |
248 | 0 | for (int col = left + 2; col < mcol - 2; col++) |
249 | 0 | { |
250 | 0 | int f; |
251 | 0 | if ((f = fcol(row, col)) == 1) |
252 | 0 | continue; |
253 | 0 | ushort(*pix)[4] = image + row * width + col; |
254 | 0 | short* hex = allhex[row % 3][col % 3][1]; |
255 | 0 | for (int d = 3; d < 6; d++) |
256 | 0 | { |
257 | 0 | rix = |
258 | 0 | &rgb[(d - 2) ^ !((row - sgrow) % 3)][row - top][col - left]; |
259 | 0 | int val = rix[-2 * hex[d]][1] + 2 * rix[hex[d]][1] - |
260 | 0 | rix[-2 * hex[d]][f] - 2 * rix[hex[d]][f] + 3 * rix[0][f]; |
261 | 0 | rix[0][1] = LIM(val / 3, pix[0][1], pix[0][3]); |
262 | 0 | } |
263 | 0 | } |
264 | 0 | } |
265 | | |
266 | | /* Interpolate red and blue values for solitary green pixels: */ |
267 | 0 | for (int row = (top - sgrow + 4) / 3 * 3 + sgrow; row < mrow - 2; row += 3) |
268 | 0 | for (int col = (left - sgcol + 4) / 3 * 3 + sgcol; col < mcol - 2; col += 3) |
269 | 0 | { |
270 | 0 | rix = &rgb[0][row - top][col - left]; |
271 | 0 | int h = fcol(row, col + 1); |
272 | |
|
273 | 0 | if (h == 1) // Incorrect pattern |
274 | 0 | break; |
275 | | |
276 | 0 | float diff[6]; |
277 | 0 | memset(diff, 0, sizeof diff); |
278 | 0 | for (int i = 1, d = 0; d < 6; d++, i ^= LIBRAW_AHD_TILE ^ 1, h ^= 2) |
279 | 0 | { |
280 | 0 | for (c = 0; c < 2; c++, h ^= 2) |
281 | 0 | { |
282 | 0 | int g = 2 * rix[0][1] - rix[i << c][1] - rix[-i << c][1]; |
283 | 0 | color[h][d] = g + rix[i << c][h] + rix[-i << c][h]; |
284 | 0 | if (d > 1) |
285 | 0 | diff[d] += SQR((float)rix[i << c][1] - (float)rix[-i << c][1] - |
286 | 0 | (float)rix[i << c][h] + (float)rix[-i << c][h]) + SQR((float)g); |
287 | 0 | } |
288 | 0 | if (d > 1 && (d & 1)) |
289 | 0 | if (diff[d - 1] < diff[d]) |
290 | 0 | FORC(2) color[c * 2][d] = color[c * 2][d - 1]; |
291 | 0 | if (d < 2 || (d & 1)) |
292 | 0 | { |
293 | 0 | FORC(2) rix[0][c * 2] = CLIP(color[c * 2][d] / 2); |
294 | 0 | rix += LIBRAW_AHD_TILE * LIBRAW_AHD_TILE; |
295 | 0 | } |
296 | 0 | } |
297 | 0 | } |
298 | | |
299 | | /* Interpolate red for blue pixels and vice versa: */ |
300 | 0 | for (int row = top + 3; row < mrow - 3; row++) |
301 | 0 | for (int col = left + 3; col < mcol - 3; col++) |
302 | 0 | { |
303 | 0 | int f; |
304 | 0 | if ((f = 2 - fcol(row, col)) == 1) |
305 | 0 | continue; |
306 | 0 | rix = &rgb[0][row - top][col - left]; |
307 | 0 | c = (row - sgrow) % 3 ? LIBRAW_AHD_TILE : 1; |
308 | 0 | int h = 3 * (c ^ LIBRAW_AHD_TILE ^ 1); |
309 | 0 | for (int d = 0; d < 4; d++, rix += LIBRAW_AHD_TILE * LIBRAW_AHD_TILE) |
310 | 0 | { |
311 | 0 | int i = d > 1 || ((d ^ c) & 1) || |
312 | 0 | ((ABS(rix[0][1] - rix[c][1]) + |
313 | 0 | ABS(rix[0][1] - rix[-c][1])) < |
314 | 0 | 2 * (ABS(rix[0][1] - rix[h][1]) + |
315 | 0 | ABS(rix[0][1] - rix[-h][1]))) |
316 | 0 | ? c |
317 | 0 | : h; |
318 | 0 | rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + 2 * rix[0][1] - |
319 | 0 | rix[i][1] - rix[-i][1]) / |
320 | 0 | 2); |
321 | 0 | } |
322 | 0 | } |
323 | | |
324 | | /* Fill in red and blue for 2x2 blocks of green: */ |
325 | 0 | for (int row = top + 2; row < mrow - 2; row++) |
326 | 0 | if ((row - sgrow) % 3) |
327 | 0 | for (int col = left + 2; col < mcol - 2; col++) |
328 | 0 | if ((col - sgcol) % 3) |
329 | 0 | { |
330 | 0 | rix = &rgb[0][row - top][col - left]; |
331 | 0 | short* hex = allhex[row % 3][col % 3][1]; |
332 | 0 | for (int d = 0; d < 8; |
333 | 0 | d += 2, rix += LIBRAW_AHD_TILE * LIBRAW_AHD_TILE) |
334 | 0 | if (hex[d] + hex[d + 1]) |
335 | 0 | { |
336 | 0 | int g = 3 * rix[0][1] - 2 * rix[hex[d]][1] - rix[hex[d + 1]][1]; |
337 | 0 | for (c = 0; c < 4; c += 2) |
338 | 0 | rix[0][c] = CLIP( |
339 | 0 | (g + 2 * rix[hex[d]][c] + rix[hex[d + 1]][c]) / 3); |
340 | 0 | } |
341 | 0 | else |
342 | 0 | { |
343 | 0 | int g = 2 * rix[0][1] - rix[hex[d]][1] - rix[hex[d + 1]][1]; |
344 | 0 | for (c = 0; c < 4; c += 2) |
345 | 0 | rix[0][c] = |
346 | 0 | CLIP((g + rix[hex[d]][c] + rix[hex[d + 1]][c]) / 2); |
347 | 0 | } |
348 | 0 | } |
349 | 0 | } |
350 | 0 | rgb = (ushort(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])buffer; |
351 | 0 | mrow -= top; |
352 | 0 | mcol -= left; |
353 | | |
354 | | /* Convert to CIELab and differentiate in all directions: */ |
355 | | // no effect |
356 | 0 | for (int d = 0; d < ndir; d++) |
357 | 0 | { |
358 | 0 | for (int row = 2; row < mrow - 2; row++) |
359 | 0 | for (int col = 2; col < mcol - 2; col++) |
360 | 0 | cielab(rgb[d][row][col], lab[row][col]); |
361 | 0 | for (int f = dir[d & 3], row = 3; row < mrow - 3; row++) |
362 | 0 | for (int col = 3; col < mcol - 3; col++) |
363 | 0 | { |
364 | 0 | lix = &lab[row][col]; |
365 | 0 | int g = 2 * lix[0][0] - lix[f][0] - lix[-f][0]; |
366 | 0 | drv[d][row][col] = |
367 | 0 | float( |
368 | 0 | SQR(g) + |
369 | 0 | SQR((2 * lix[0][1] - lix[f][1] - lix[-f][1] + g * 500 / 232)) + |
370 | 0 | SQR((2 * lix[0][2] - lix[f][2] - lix[-f][2] - g * 500 / 580)) |
371 | 0 | ); |
372 | 0 | } |
373 | 0 | } |
374 | | |
375 | | /* Build homogeneity maps from the derivatives: */ |
376 | 0 | memset(homo, 0, ndir * LIBRAW_AHD_TILE * LIBRAW_AHD_TILE); |
377 | 0 | for (int row = 4; row < mrow - 4; row++) |
378 | 0 | for (int col = 4; col < mcol - 4; col++) |
379 | 0 | { |
380 | 0 | int d; |
381 | 0 | float tr; |
382 | 0 | for (tr = FLT_MAX, d = 0; d < ndir; d++) |
383 | 0 | if (tr > drv[d][row][col]) |
384 | 0 | tr = drv[d][row][col]; |
385 | 0 | tr *= 8; |
386 | 0 | for (int dd = 0; dd < ndir; dd++) |
387 | 0 | for (int v = -1; v <= 1; v++) |
388 | 0 | for (int h = -1; h <= 1; h++) |
389 | 0 | if (drv[dd][row + v][col + h] <= tr) |
390 | 0 | homo[dd][row][col]++; |
391 | 0 | } |
392 | | |
393 | | /* Average the most homogeneous pixels for the final result: */ |
394 | 0 | if (height - top < LIBRAW_AHD_TILE + 4) |
395 | 0 | mrow = height - top + 2; |
396 | 0 | if (width - left < LIBRAW_AHD_TILE + 4) |
397 | 0 | mcol = width - left + 2; |
398 | 0 | for (int row = MIN(top, 8); row < mrow - 8; row++) |
399 | 0 | for (int col = MIN(left, 8); col < mcol - 8; col++) |
400 | 0 | { |
401 | 0 | int v; |
402 | 0 | int hm[8]; |
403 | 0 | for (int d = 0; d < ndir; d++) |
404 | 0 | for (v = -2, hm[d] = 0; v <= 2; v++) |
405 | 0 | for (int h = -2; h <= 2; h++) |
406 | 0 | hm[d] += homo[d][row + v][col + h]; |
407 | 0 | for (int d = 0; d < ndir - 4; d++) |
408 | 0 | if (hm[d] < hm[d + 4]) |
409 | 0 | hm[d] = 0; |
410 | 0 | else if (hm[d] > hm[d + 4]) |
411 | 0 | hm[d + 4] = 0; |
412 | 0 | ushort max; |
413 | 0 | int d; |
414 | 0 | for (d = 1, max = hm[0]; d < ndir; d++) |
415 | 0 | if (max < hm[d]) |
416 | 0 | max = hm[d]; |
417 | 0 | max -= max >> 3; |
418 | |
|
419 | 0 | int avg[4]; |
420 | 0 | memset(avg, 0, sizeof avg); |
421 | 0 | for (int dd = 0; dd < ndir; dd++) |
422 | 0 | if (hm[dd] >= max) |
423 | 0 | { |
424 | 0 | FORC3 avg[c] += rgb[dd][row][col][c]; |
425 | 0 | avg[3]++; |
426 | 0 | } |
427 | 0 | FORC3 destimage[(row + top) * width + col + left][c] = avg[c] / avg[3]; |
428 | 0 | } |
429 | 0 | } |
430 | 0 | } |
431 | | |
432 | | #ifdef LIBRAW_USE_OPENMP |
433 | | #pragma omp barrier |
434 | | #endif |
435 | |
|
436 | 0 | free_omp_buffers(buffers, buffer_count); |
437 | 0 | free(image); |
438 | 0 | image = destimage; |
439 | |
|
440 | 0 | border_interpolate(8); |
441 | 0 | } |
442 | | #undef fcol |