/src/dng_sdk/source/dng_mosaic_info.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /*****************************************************************************/ |
2 | | // Copyright 2006-2009 Adobe Systems Incorporated |
3 | | // All Rights Reserved. |
4 | | // |
5 | | // NOTICE: Adobe permits you to use, modify, and distribute this file in |
6 | | // accordance with the terms of the Adobe license agreement accompanying it. |
7 | | /*****************************************************************************/ |
8 | | |
9 | | /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_mosaic_info.cpp#1 $ */ |
10 | | /* $DateTime: 2012/05/30 13:28:51 $ */ |
11 | | /* $Change: 832332 $ */ |
12 | | /* $Author: tknoll $ */ |
13 | | |
14 | | /*****************************************************************************/ |
15 | | |
16 | | #include "dng_mosaic_info.h" |
17 | | |
18 | | #include "dng_area_task.h" |
19 | | #include "dng_assertions.h" |
20 | | #include "dng_bottlenecks.h" |
21 | | #include "dng_exceptions.h" |
22 | | #include "dng_filter_task.h" |
23 | | #include "dng_host.h" |
24 | | #include "dng_ifd.h" |
25 | | #include "dng_image.h" |
26 | | #include "dng_info.h" |
27 | | #include "dng_negative.h" |
28 | | #include "dng_pixel_buffer.h" |
29 | | #include "dng_tag_types.h" |
30 | | #include "dng_tag_values.h" |
31 | | #include "dng_tile_iterator.h" |
32 | | #include "dng_utils.h" |
33 | | |
34 | | /*****************************************************************************/ |
35 | | |
36 | | // A interpolation kernel for a single pixel of a single plane. |
37 | | |
38 | | class dng_bilinear_kernel |
39 | | { |
40 | | |
41 | | public: |
42 | | |
43 | | enum |
44 | | { |
45 | | kMaxCount = 8 |
46 | | }; |
47 | | |
48 | | uint32 fCount; |
49 | | |
50 | | dng_point fDelta [kMaxCount]; |
51 | | |
52 | | real32 fWeight32 [kMaxCount]; |
53 | | uint16 fWeight16 [kMaxCount]; |
54 | | |
55 | | int32 fOffset [kMaxCount]; |
56 | | |
57 | | public: |
58 | | |
59 | | dng_bilinear_kernel () |
60 | 132k | : fCount (0) |
61 | 132k | { |
62 | 132k | } |
63 | | |
64 | | void Add (const dng_point &delta, |
65 | | real32 weight); |
66 | | |
67 | | void Finalize (const dng_point &scale, |
68 | | uint32 patRow, |
69 | | uint32 patCol, |
70 | | int32 rowStep, |
71 | | int32 colStep); |
72 | | |
73 | | }; |
74 | | |
75 | | /*****************************************************************************/ |
76 | | |
77 | | void dng_bilinear_kernel::Add (const dng_point &delta, |
78 | | real32 weight) |
79 | 4.10k | { |
80 | | |
81 | | // Don't add zero weight elements. |
82 | | |
83 | 4.10k | if (weight <= 0.0f) |
84 | 822 | { |
85 | 822 | return; |
86 | 822 | } |
87 | | |
88 | | // If the delta already matches an existing element, just combine the |
89 | | // weights. |
90 | | |
91 | 5.99k | for (uint32 j = 0; j < fCount; j++) |
92 | 3.28k | { |
93 | | |
94 | 3.28k | if (fDelta [j] == delta) |
95 | 570 | { |
96 | | |
97 | 570 | fWeight32 [j] += weight; |
98 | | |
99 | 570 | return; |
100 | | |
101 | 570 | } |
102 | | |
103 | 3.28k | } |
104 | | |
105 | | // Add element to list. |
106 | | |
107 | 2.71k | DNG_ASSERT (fCount < kMaxCount, "Too many kernel entries"); |
108 | | |
109 | 2.71k | fDelta [fCount] = delta; |
110 | 2.71k | fWeight32 [fCount] = weight; |
111 | | |
112 | 2.71k | fCount++; |
113 | | |
114 | 2.71k | } |
115 | | |
116 | | /*****************************************************************************/ |
117 | | |
118 | | void dng_bilinear_kernel::Finalize (const dng_point &scale, |
119 | | uint32 patRow, |
120 | | uint32 patCol, |
121 | | int32 rowStep, |
122 | | int32 colStep) |
123 | 1.33k | { |
124 | | |
125 | 1.33k | uint32 j; |
126 | | |
127 | | // Adjust deltas to compensate for interpolation upscaling. |
128 | | |
129 | 4.04k | for (j = 0; j < fCount; j++) |
130 | 2.71k | { |
131 | | |
132 | 2.71k | dng_point &delta = fDelta [j]; |
133 | | |
134 | 2.71k | if (scale.v == 2) |
135 | 372 | { |
136 | | |
137 | 372 | delta.v = (delta.v + (int32) (patRow & 1)) >> 1; |
138 | | |
139 | 372 | } |
140 | | |
141 | 2.71k | if (scale.h == 2) |
142 | 230 | { |
143 | | |
144 | 230 | delta.h = (delta.h + (int32) (patCol & 1)) >> 1; |
145 | | |
146 | 230 | } |
147 | | |
148 | 2.71k | } |
149 | | |
150 | | // Sort entries into row-column scan order. |
151 | | |
152 | 1.43k | while (true) |
153 | 1.43k | { |
154 | | |
155 | 1.43k | bool didSwap = false; |
156 | | |
157 | 3.14k | for (j = 1; j < fCount; j++) |
158 | 1.71k | { |
159 | | |
160 | 1.71k | dng_point &delta0 = fDelta [j - 1]; |
161 | 1.71k | dng_point &delta1 = fDelta [j ]; |
162 | | |
163 | 1.71k | if (delta0.v > delta1.v || |
164 | 1.71k | (delta0.v == delta1.v && |
165 | 1.64k | delta0.h > delta1.h)) |
166 | 99 | { |
167 | | |
168 | 99 | didSwap = true; |
169 | | |
170 | 99 | dng_point tempDelta = delta0; |
171 | | |
172 | 99 | delta0 = delta1; |
173 | 99 | delta1 = tempDelta; |
174 | | |
175 | 99 | real32 tempWeight = fWeight32 [j - 1]; |
176 | | |
177 | 99 | fWeight32 [j - 1] = fWeight32 [j]; |
178 | 99 | fWeight32 [j ] = tempWeight; |
179 | | |
180 | 99 | } |
181 | | |
182 | 1.71k | } |
183 | | |
184 | 1.43k | if (!didSwap) |
185 | 1.33k | { |
186 | 1.33k | break; |
187 | 1.33k | } |
188 | | |
189 | 1.43k | } |
190 | | |
191 | | // Calculate offsets. |
192 | | |
193 | 4.04k | for (j = 0; j < fCount; j++) |
194 | 2.71k | { |
195 | | |
196 | 2.71k | fOffset [j] = rowStep * fDelta [j].v + |
197 | 2.71k | colStep * fDelta [j].h; |
198 | | |
199 | 2.71k | } |
200 | | |
201 | | // Calculate 16-bit weights. |
202 | | |
203 | 1.33k | uint16 total = 0; |
204 | 1.33k | uint32 biggest = 0; |
205 | | |
206 | 4.04k | for (j = 0; j < fCount; j++) |
207 | 2.71k | { |
208 | | |
209 | | // Round weights to 8 fractional bits. |
210 | | |
211 | 2.71k | fWeight16 [j] = (uint16) Round_uint32 (fWeight32 [j] * 256.0); |
212 | | |
213 | | // Keep track of total of weights. |
214 | | |
215 | 2.71k | total += fWeight16 [j]; |
216 | | |
217 | | // Keep track of which weight is biggest. |
218 | | |
219 | 2.71k | if (fWeight16 [biggest] < fWeight16 [j]) |
220 | 134 | { |
221 | | |
222 | 134 | biggest = j; |
223 | | |
224 | 134 | } |
225 | | |
226 | 2.71k | } |
227 | | |
228 | | // Adjust largest entry so total of weights is exactly 256. |
229 | | |
230 | 1.33k | fWeight16 [biggest] += (256 - total); |
231 | | |
232 | | // Recompute the floating point weights from the rounded integer weights |
233 | | // so results match more closely. |
234 | | |
235 | 4.04k | for (j = 0; j < fCount; j++) |
236 | 2.71k | { |
237 | | |
238 | 2.71k | fWeight32 [j] = fWeight16 [j] * (1.0f / 256.0f); |
239 | | |
240 | 2.71k | } |
241 | | |
242 | 1.33k | } |
243 | | |
244 | | /*****************************************************************************/ |
245 | | |
246 | | class dng_bilinear_pattern |
247 | | { |
248 | | |
249 | | public: |
250 | | |
251 | | enum |
252 | | { |
253 | | kMaxPattern = kMaxCFAPattern * 2 |
254 | | }; |
255 | | |
256 | | dng_point fScale; |
257 | | |
258 | | uint32 fPatRows; |
259 | | uint32 fPatCols; |
260 | | |
261 | | dng_bilinear_kernel fKernel [kMaxPattern] |
262 | | [kMaxPattern]; |
263 | | |
264 | | uint32 fCounts [kMaxPattern] |
265 | | [kMaxPattern]; |
266 | | |
267 | | int32 *fOffsets [kMaxPattern] |
268 | | [kMaxPattern]; |
269 | | |
270 | | uint16 *fWeights16 [kMaxPattern] |
271 | | [kMaxPattern]; |
272 | | |
273 | | real32 *fWeights32 [kMaxPattern] |
274 | | [kMaxPattern]; |
275 | | |
276 | | public: |
277 | | |
278 | | dng_bilinear_pattern () |
279 | | |
280 | 516 | : fScale () |
281 | 516 | , fPatRows (0) |
282 | 516 | , fPatCols (0) |
283 | | |
284 | 516 | { |
285 | 516 | } |
286 | | |
287 | | private: |
288 | | |
289 | | #if defined(__clang__) && defined(__has_attribute) |
290 | | #if __has_attribute(no_sanitize) |
291 | | __attribute__((no_sanitize("unsigned-integer-overflow"))) |
292 | | #endif |
293 | | #endif |
294 | | uint32 DeltaRow (uint32 row, int32 delta) |
295 | 5.80k | { |
296 | | // Potential overflow in the conversion from delta to a uint32 as |
297 | | // well as in the subsequent addition is intentional. |
298 | 5.80k | return (SafeUint32Add(row, fPatRows) + (uint32) delta) % fPatRows; |
299 | 5.80k | } |
300 | | |
301 | | #if defined(__clang__) && defined(__has_attribute) |
302 | | #if __has_attribute(no_sanitize) |
303 | | __attribute__((no_sanitize("unsigned-integer-overflow"))) |
304 | | #endif |
305 | | #endif |
306 | | uint32 DeltaCol (uint32 col, int32 delta) |
307 | 5.71k | { |
308 | | // Potential overflow in the conversion from delta to a uint32 as |
309 | | // well as in the subsequent addition is intentional. |
310 | 5.71k | return (SafeUint32Add(col, fPatCols) + (uint32) delta) % fPatCols; |
311 | 5.71k | } |
312 | | |
313 | | real32 LinearWeight1 (int32 d1, int32 d2) |
314 | 1.59k | { |
315 | 1.59k | if (d1 == d2) |
316 | 603 | return 1.0f; |
317 | 987 | else |
318 | 987 | return d2 / (real32) (d2 - d1); |
319 | 1.59k | } |
320 | | |
321 | | real32 LinearWeight2 (int32 d1, int32 d2) |
322 | 1.59k | { |
323 | 1.59k | if (d1 == d2) |
324 | 603 | return 0.0f; |
325 | 987 | else |
326 | 987 | return -d1 / (real32) (d2 - d1); |
327 | 1.59k | } |
328 | | |
329 | | public: |
330 | | |
331 | | void Calculate (const dng_mosaic_info &info, |
332 | | uint32 dstPlane, |
333 | | int32 rowStep, |
334 | | int32 colStep); |
335 | | |
336 | | }; |
337 | | |
338 | | /*****************************************************************************/ |
339 | | |
340 | | void dng_bilinear_pattern::Calculate (const dng_mosaic_info &info, |
341 | | uint32 dstPlane, |
342 | | int32 rowStep, |
343 | | int32 colStep) |
344 | 303 | { |
345 | | |
346 | 303 | uint32 j; |
347 | 303 | uint32 k; |
348 | 303 | uint32 patRow; |
349 | 303 | uint32 patCol; |
350 | | |
351 | | // Find destination pattern size. |
352 | | |
353 | 303 | fScale = info.FullScale (); |
354 | | |
355 | 303 | fPatRows = info.fCFAPatternSize.v * fScale.v; |
356 | 303 | fPatCols = info.fCFAPatternSize.h * fScale.h; |
357 | | |
358 | | // See if we need to scale up just while computing the kernels. |
359 | | |
360 | 303 | dng_point tempScale (1, 1); |
361 | | |
362 | 303 | if (info.fCFALayout >= 6) |
363 | 23 | { |
364 | | |
365 | 23 | tempScale = dng_point (2, 2); |
366 | | |
367 | 23 | fPatRows *= tempScale.v; |
368 | 23 | fPatCols *= tempScale.h; |
369 | | |
370 | 23 | } |
371 | | |
372 | | // Find a boolean map for this plane color and layout. |
373 | | |
374 | 303 | bool map [kMaxPattern] |
375 | 303 | [kMaxPattern]; |
376 | | |
377 | 303 | uint8 planeColor = info.fCFAPlaneColor [dstPlane]; |
378 | | |
379 | 303 | switch (info.fCFALayout) |
380 | 303 | { |
381 | | |
382 | 247 | case 1: // Rectangular (or square) layout |
383 | 247 | { |
384 | | |
385 | 845 | for (j = 0; j < fPatRows; j++) |
386 | 598 | { |
387 | | |
388 | 1.58k | for (k = 0; k < fPatCols; k++) |
389 | 988 | { |
390 | | |
391 | 988 | map [j] [k] = (info.fCFAPattern [j] [k] == planeColor); |
392 | | |
393 | 988 | } |
394 | | |
395 | 598 | } |
396 | | |
397 | 247 | break; |
398 | | |
399 | 0 | } |
400 | | |
401 | | // Note that when the descriptions of the staggered patterns refer to even rows or |
402 | | // columns, this mean the second, fourth, etc. (i.e. using one-based numbering). |
403 | | // This needs to be clarified in the DNG specification. |
404 | | |
405 | 13 | case 2: // Staggered layout A: even (1-based) columns are offset down by 1/2 row |
406 | 13 | { |
407 | | |
408 | 69 | for (j = 0; j < fPatRows; j++) |
409 | 56 | { |
410 | | |
411 | 160 | for (k = 0; k < fPatCols; k++) |
412 | 104 | { |
413 | | |
414 | 104 | if ((j & 1) != (k & 1)) |
415 | 52 | { |
416 | | |
417 | 52 | map [j] [k] = false; |
418 | | |
419 | 52 | } |
420 | | |
421 | 52 | else |
422 | 52 | { |
423 | | |
424 | 52 | map [j] [k] = (info.fCFAPattern [j >> 1] [k] == planeColor); |
425 | | |
426 | 52 | } |
427 | | |
428 | 104 | } |
429 | | |
430 | 56 | } |
431 | | |
432 | 13 | break; |
433 | | |
434 | 0 | } |
435 | | |
436 | 6 | case 3: // Staggered layout B: even (1-based) columns are offset up by 1/2 row |
437 | 6 | { |
438 | | |
439 | 34 | for (j = 0; j < fPatRows; j++) |
440 | 28 | { |
441 | | |
442 | 76 | for (k = 0; k < fPatCols; k++) |
443 | 48 | { |
444 | | |
445 | 48 | if ((j & 1) == (k & 1)) |
446 | 24 | { |
447 | | |
448 | 24 | map [j] [k] = false; |
449 | | |
450 | 24 | } |
451 | | |
452 | 24 | else |
453 | 24 | { |
454 | | |
455 | 24 | map [j] [k] = (info.fCFAPattern [j >> 1] [k] == planeColor); |
456 | | |
457 | 24 | } |
458 | | |
459 | 48 | } |
460 | | |
461 | 28 | } |
462 | | |
463 | 6 | break; |
464 | | |
465 | 0 | } |
466 | | |
467 | 6 | case 4: // Staggered layout C: even (1-based) rows are offset right by 1/2 column |
468 | 6 | { |
469 | | |
470 | 16 | for (j = 0; j < fPatRows; j++) |
471 | 10 | { |
472 | | |
473 | 58 | for (k = 0; k < fPatCols; k++) |
474 | 48 | { |
475 | | |
476 | 48 | if ((j & 1) != (k & 1)) |
477 | 24 | { |
478 | | |
479 | 24 | map [j] [k] = false; |
480 | | |
481 | 24 | } |
482 | | |
483 | 24 | else |
484 | 24 | { |
485 | | |
486 | 24 | map [j] [k] = (info.fCFAPattern [j] [k >> 1] == planeColor); |
487 | | |
488 | 24 | } |
489 | | |
490 | 48 | } |
491 | | |
492 | 10 | } |
493 | | |
494 | 6 | break; |
495 | | |
496 | 0 | } |
497 | | |
498 | 8 | case 5: // Staggered layout D: even (1-based) rows are offset left by 1/2 column |
499 | 8 | { |
500 | | |
501 | 26 | for (j = 0; j < fPatRows; j++) |
502 | 18 | { |
503 | | |
504 | 74 | for (k = 0; k < fPatCols; k++) |
505 | 56 | { |
506 | | |
507 | 56 | if ((j & 1) == (k & 1)) |
508 | 28 | { |
509 | | |
510 | 28 | map [j] [k] = false; |
511 | | |
512 | 28 | } |
513 | | |
514 | 28 | else |
515 | 28 | { |
516 | | |
517 | 28 | map [j] [k] = (info.fCFAPattern [j] [k >> 1] == planeColor); |
518 | | |
519 | 28 | } |
520 | | |
521 | 56 | } |
522 | | |
523 | 18 | } |
524 | | |
525 | 8 | break; |
526 | | |
527 | 0 | } |
528 | | |
529 | 0 | case 6: // Staggered layout E: even rows are offset up by 1/2 row, even columns are offset left by 1/2 column |
530 | 16 | case 7: // Staggered layout F: even rows are offset up by 1/2 row, even columns are offset right by 1/2 column |
531 | 21 | case 8: // Staggered layout G: even rows are offset down by 1/2 row, even columns are offset left by 1/2 column |
532 | 23 | case 9: // Staggered layout H: even rows are offset down by 1/2 row, even columns are offset right by 1/2 column |
533 | 23 | { |
534 | | |
535 | 23 | uint32 eRow = (info.fCFALayout == 6 || |
536 | 23 | info.fCFALayout == 7) ? 1 : 3; |
537 | | |
538 | 23 | uint32 eCol = (info.fCFALayout == 6 || |
539 | 23 | info.fCFALayout == 8) ? 1 : 3; |
540 | | |
541 | 123 | for (j = 0; j < fPatRows; j++) |
542 | 100 | { |
543 | | |
544 | 452 | for (k = 0; k < fPatCols; k++) |
545 | 352 | { |
546 | | |
547 | 352 | uint32 jj = j & 3; |
548 | 352 | uint32 kk = k & 3; |
549 | | |
550 | 352 | if ((jj != 0 && jj != eRow) || |
551 | 352 | (kk != 0 && kk != eCol)) |
552 | 244 | { |
553 | | |
554 | 244 | map [j] [k] = false; |
555 | | |
556 | 244 | } |
557 | | |
558 | 108 | else |
559 | 108 | { |
560 | | |
561 | 108 | map [j] [k] = (info.fCFAPattern [((j >> 1) & ~1) + Min_uint32 (jj, 1)] |
562 | 108 | [((k >> 1) & ~1) + Min_uint32 (kk, 1)] == planeColor); |
563 | | |
564 | 108 | } |
565 | | |
566 | 352 | } |
567 | | |
568 | 100 | } |
569 | | |
570 | 23 | break; |
571 | | |
572 | 21 | } |
573 | | |
574 | 0 | default: |
575 | 0 | ThrowProgramError (); |
576 | | |
577 | 303 | } |
578 | | |
579 | | // Find projections of maps. |
580 | | |
581 | 303 | bool mapH [kMaxPattern]; |
582 | 303 | bool mapV [kMaxPattern]; |
583 | | |
584 | 5.15k | for (j = 0; j < kMaxPattern; j++) |
585 | 4.84k | { |
586 | | |
587 | 4.84k | mapH [j] = false; |
588 | 4.84k | mapV [j] = false; |
589 | | |
590 | 4.84k | } |
591 | | |
592 | 1.11k | for (j = 0; j < fPatRows; j++) |
593 | 810 | { |
594 | | |
595 | 2.40k | for (k = 0; k < fPatCols; k++) |
596 | 1.59k | { |
597 | | |
598 | 1.59k | if (map [j] [k]) |
599 | 519 | { |
600 | | |
601 | 519 | mapV [j] = true; |
602 | 519 | mapH [k] = true; |
603 | | |
604 | 519 | } |
605 | | |
606 | 1.59k | } |
607 | | |
608 | 810 | } |
609 | | |
610 | | // Find kernel for each patten entry. |
611 | | |
612 | 1.06k | for (patRow = 0; patRow < fPatRows; patRow += tempScale.v) |
613 | 760 | { |
614 | | |
615 | 2.09k | for (patCol = 0; patCol < fPatCols; patCol += tempScale.h) |
616 | 1.33k | { |
617 | | |
618 | 1.33k | dng_bilinear_kernel &kernel = fKernel [patRow] [patCol]; |
619 | | |
620 | | // Special case no interpolation case. |
621 | | |
622 | 1.33k | if (map [patRow] [patCol]) |
623 | 489 | { |
624 | | |
625 | 489 | kernel.Add (dng_point (0, 0), 1.0f); |
626 | | |
627 | 489 | continue; |
628 | | |
629 | 489 | } |
630 | | |
631 | | // Special case common patterns in 3 by 3 neighborhood. |
632 | | |
633 | 843 | uint32 n = DeltaRow (patRow, -1); |
634 | 843 | uint32 s = DeltaRow (patRow, 1); |
635 | 843 | uint32 w = DeltaCol (patCol, -1); |
636 | 843 | uint32 e = DeltaCol (patCol, 1); |
637 | | |
638 | 843 | bool mapNW = map [n] [w]; |
639 | 843 | bool mapN = map [n] [patCol]; |
640 | 843 | bool mapNE = map [n] [e]; |
641 | | |
642 | 843 | bool mapW = map [patRow] [w]; |
643 | 843 | bool mapE = map [patRow] [e]; |
644 | | |
645 | 843 | bool mapSW = map [s] [w]; |
646 | 843 | bool mapS = map [s] [patCol]; |
647 | 843 | bool mapSE = map [s] [e]; |
648 | | |
649 | | // All sides. |
650 | | |
651 | 843 | if (mapN && mapS && mapW && mapW) |
652 | 71 | { |
653 | | |
654 | 71 | kernel.Add (dng_point (-1, 0), 0.25f); |
655 | 71 | kernel.Add (dng_point ( 0, -1), 0.25f); |
656 | 71 | kernel.Add (dng_point ( 0, 1), 0.25f); |
657 | 71 | kernel.Add (dng_point ( 1, 0), 0.25f); |
658 | | |
659 | 71 | continue; |
660 | | |
661 | 71 | } |
662 | | |
663 | | // N & S. |
664 | | |
665 | 772 | if (mapN && mapS) |
666 | 241 | { |
667 | | |
668 | 241 | kernel.Add (dng_point (-1, 0), 0.5f); |
669 | 241 | kernel.Add (dng_point ( 1, 0), 0.5f); |
670 | | |
671 | 241 | continue; |
672 | | |
673 | 241 | } |
674 | | |
675 | | // E & W. |
676 | | |
677 | 531 | if (mapW && mapE) |
678 | 165 | { |
679 | | |
680 | 165 | kernel.Add (dng_point ( 0, -1), 0.5f); |
681 | 165 | kernel.Add (dng_point ( 0, 1), 0.5f); |
682 | | |
683 | 165 | continue; |
684 | | |
685 | 165 | } |
686 | | |
687 | | // N & SW & SE. |
688 | | |
689 | 366 | if (mapN && mapSW && mapSE) |
690 | 0 | { |
691 | | |
692 | 0 | kernel.Add (dng_point (-1, 0), 0.50f); |
693 | 0 | kernel.Add (dng_point ( 1, -1), 0.25f); |
694 | 0 | kernel.Add (dng_point ( 1, 1), 0.25f); |
695 | | |
696 | 0 | continue; |
697 | | |
698 | 0 | } |
699 | | |
700 | | // S & NW & NE. |
701 | | |
702 | 366 | if (mapS && mapNW && mapNE) |
703 | 0 | { |
704 | | |
705 | 0 | kernel.Add (dng_point (-1, -1), 0.25f); |
706 | 0 | kernel.Add (dng_point (-1, 1), 0.25f); |
707 | 0 | kernel.Add (dng_point ( 1, 0), 0.50f); |
708 | | |
709 | 0 | continue; |
710 | | |
711 | 0 | } |
712 | | |
713 | | // W & NE & SE. |
714 | | |
715 | 366 | if (mapW && mapNE && mapSE) |
716 | 0 | { |
717 | | |
718 | 0 | kernel.Add (dng_point (-1, 1), 0.25f); |
719 | 0 | kernel.Add (dng_point ( 0, -1), 0.50f); |
720 | 0 | kernel.Add (dng_point ( 1, 1), 0.25f); |
721 | | |
722 | 0 | continue; |
723 | | |
724 | 0 | } |
725 | | |
726 | | // E & NW & SW. |
727 | | |
728 | 366 | if (mapE && mapNW && mapSW) |
729 | 0 | { |
730 | | |
731 | 0 | kernel.Add (dng_point (-1, -1), 0.25f); |
732 | 0 | kernel.Add (dng_point ( 0, 1), 0.50f); |
733 | 0 | kernel.Add (dng_point ( 1, -1), 0.25f); |
734 | | |
735 | 0 | continue; |
736 | | |
737 | 0 | } |
738 | | |
739 | | // Four corners. |
740 | | |
741 | 366 | if (mapNW && mapNE && mapSE && mapSW) |
742 | 101 | { |
743 | | |
744 | 101 | kernel.Add (dng_point (-1, -1), 0.25f); |
745 | 101 | kernel.Add (dng_point (-1, 1), 0.25f); |
746 | 101 | kernel.Add (dng_point ( 1, -1), 0.25f); |
747 | 101 | kernel.Add (dng_point ( 1, 1), 0.25f); |
748 | | |
749 | 101 | continue; |
750 | | |
751 | 101 | } |
752 | | |
753 | | // NW & SE |
754 | | |
755 | 265 | if (mapNW && mapSE) |
756 | 0 | { |
757 | | |
758 | 0 | kernel.Add (dng_point (-1, -1), 0.50f); |
759 | 0 | kernel.Add (dng_point ( 1, 1), 0.50f); |
760 | | |
761 | 0 | continue; |
762 | | |
763 | 0 | } |
764 | | |
765 | | // NE & SW |
766 | | |
767 | 265 | if (mapNE && mapSW) |
768 | 0 | { |
769 | | |
770 | 0 | kernel.Add (dng_point (-1, 1), 0.50f); |
771 | 0 | kernel.Add (dng_point ( 1, -1), 0.50f); |
772 | | |
773 | 0 | continue; |
774 | | |
775 | 0 | } |
776 | | |
777 | | // Else use double-bilinear kernel. |
778 | | |
779 | 265 | int32 dv1 = 0; |
780 | 265 | int32 dv2 = 0; |
781 | | |
782 | 573 | while (!mapV [DeltaRow (patRow, dv1)]) |
783 | 308 | { |
784 | 308 | dv1--; |
785 | 308 | } |
786 | | |
787 | 576 | while (!mapV [DeltaRow (patRow, dv2)]) |
788 | 311 | { |
789 | 311 | dv2++; |
790 | 311 | } |
791 | | |
792 | 265 | real32 w1 = LinearWeight1 (dv1, dv2) * 0.5f; |
793 | 265 | real32 w2 = LinearWeight2 (dv1, dv2) * 0.5f; |
794 | | |
795 | 265 | int32 v1 = DeltaRow (patRow, dv1); |
796 | 265 | int32 v2 = DeltaRow (patRow, dv2); |
797 | | |
798 | 265 | int32 dh1 = 0; |
799 | 265 | int32 dh2 = 0; |
800 | | |
801 | 594 | while (!map [v1] [DeltaCol (patCol, dh1)]) |
802 | 329 | { |
803 | 329 | dh1--; |
804 | 329 | } |
805 | | |
806 | 596 | while (!map [v1] [DeltaCol (patCol, dh2)]) |
807 | 331 | { |
808 | 331 | dh2++; |
809 | 331 | } |
810 | | |
811 | 265 | kernel.Add (dng_point (dv1, dh1), |
812 | 265 | LinearWeight1 (dh1, dh2) * w1); |
813 | | |
814 | 265 | kernel.Add (dng_point (dv1, dh2), |
815 | 265 | LinearWeight2 (dh1, dh2) * w1); |
816 | | |
817 | 265 | dh1 = 0; |
818 | 265 | dh2 = 0; |
819 | | |
820 | 590 | while (!map [v2] [DeltaCol (patCol, dh1)]) |
821 | 325 | { |
822 | 325 | dh1--; |
823 | 325 | } |
824 | | |
825 | 590 | while (!map [v2] [DeltaCol (patCol, dh2)]) |
826 | 325 | { |
827 | 325 | dh2++; |
828 | 325 | } |
829 | | |
830 | 265 | kernel.Add (dng_point (dv2, dh1), |
831 | 265 | LinearWeight1 (dh1, dh2) * w2); |
832 | | |
833 | 265 | kernel.Add (dng_point (dv2, dh2), |
834 | 265 | LinearWeight2 (dh1, dh2) * w2); |
835 | | |
836 | 265 | dh1 = 0; |
837 | 265 | dh2 = 0; |
838 | | |
839 | 565 | while (!mapH [DeltaCol (patCol, dh1)]) |
840 | 300 | { |
841 | 300 | dh1--; |
842 | 300 | } |
843 | | |
844 | 560 | while (!mapH [DeltaCol (patCol, dh2)]) |
845 | 295 | { |
846 | 295 | dh2++; |
847 | 295 | } |
848 | | |
849 | 265 | w1 = LinearWeight1 (dh1, dh2) * 0.5f; |
850 | 265 | w2 = LinearWeight2 (dh1, dh2) * 0.5f; |
851 | | |
852 | 265 | int32 h1 = DeltaCol (patCol, dh1); |
853 | 265 | int32 h2 = DeltaCol (patCol, dh2); |
854 | | |
855 | 265 | dv1 = 0; |
856 | 265 | dv2 = 0; |
857 | | |
858 | 612 | while (!map [DeltaRow (patRow, dv1)] [h1]) |
859 | 347 | { |
860 | 347 | dv1--; |
861 | 347 | } |
862 | | |
863 | 608 | while (!map [DeltaRow (patRow, dv2)] [h1]) |
864 | 343 | { |
865 | 343 | dv2++; |
866 | 343 | } |
867 | | |
868 | 265 | kernel.Add (dng_point (dv1, dh1), |
869 | 265 | LinearWeight1 (dv1, dv2) * w1); |
870 | | |
871 | 265 | kernel.Add (dng_point (dv2, dh1), |
872 | 265 | LinearWeight2 (dv1, dv2) * w1); |
873 | | |
874 | 265 | dv1 = 0; |
875 | 265 | dv2 = 0; |
876 | | |
877 | 611 | while (!map [DeltaRow (patRow, dv1)] [h2]) |
878 | 346 | { |
879 | 346 | dv1--; |
880 | 346 | } |
881 | | |
882 | 605 | while (!map [DeltaRow (patRow, dv2)] [h2]) |
883 | 340 | { |
884 | 340 | dv2++; |
885 | 340 | } |
886 | | |
887 | 265 | kernel.Add (dng_point (dv1, dh2), |
888 | 265 | LinearWeight1 (dv1, dv2) * w2); |
889 | | |
890 | 265 | kernel.Add (dng_point (dv2, dh2), |
891 | 265 | LinearWeight2 (dv1, dv2) * w2); |
892 | | |
893 | 265 | } |
894 | | |
895 | 760 | } |
896 | | |
897 | | // Deal with temp scale case. |
898 | | |
899 | 303 | if (tempScale == dng_point (2, 2)) |
900 | 23 | { |
901 | | |
902 | 23 | fPatRows /= tempScale.v; |
903 | 23 | fPatCols /= tempScale.h; |
904 | | |
905 | 73 | for (patRow = 0; patRow < fPatRows; patRow++) |
906 | 50 | { |
907 | | |
908 | 138 | for (patCol = 0; patCol < fPatCols; patCol++) |
909 | 88 | { |
910 | | |
911 | 88 | int32 patRow2 = patRow << 1; |
912 | 88 | int32 patCol2 = patCol << 1; |
913 | | |
914 | 88 | dng_bilinear_kernel &kernel = fKernel [patRow2] [patCol2]; |
915 | | |
916 | 343 | for (j = 0; j < kernel.fCount; j++) |
917 | 255 | { |
918 | | |
919 | 255 | int32 x = patRow2 + kernel.fDelta [j].v; |
920 | | |
921 | 255 | if ((x & 3) != 0) |
922 | 136 | { |
923 | 136 | x = (x & ~3) + 2; |
924 | 136 | } |
925 | | |
926 | 255 | kernel.fDelta [j].v = ((x - patRow2) >> 1); |
927 | | |
928 | 255 | x = patCol2 + kernel.fDelta [j].h; |
929 | | |
930 | 255 | if ((x & 3) != 0) |
931 | 122 | { |
932 | 122 | x = (x & ~3) + 2; |
933 | 122 | } |
934 | | |
935 | 255 | kernel.fDelta [j].h = ((x - patCol2) >> 1); |
936 | | |
937 | 255 | } |
938 | | |
939 | 88 | kernel.Finalize (fScale, |
940 | 88 | patRow, |
941 | 88 | patCol, |
942 | 88 | rowStep, |
943 | 88 | colStep); |
944 | | |
945 | 88 | fCounts [patRow] [patCol] = kernel.fCount; |
946 | 88 | fOffsets [patRow] [patCol] = kernel.fOffset; |
947 | 88 | fWeights16 [patRow] [patCol] = kernel.fWeight16; |
948 | 88 | fWeights32 [patRow] [patCol] = kernel.fWeight32; |
949 | | |
950 | 88 | } |
951 | | |
952 | 50 | } |
953 | | |
954 | 23 | } |
955 | | |
956 | | // Non-temp scale case. |
957 | | |
958 | 280 | else |
959 | 280 | { |
960 | | |
961 | 990 | for (patRow = 0; patRow < fPatRows; patRow++) |
962 | 710 | { |
963 | | |
964 | 1.95k | for (patCol = 0; patCol < fPatCols; patCol++) |
965 | 1.24k | { |
966 | | |
967 | 1.24k | dng_bilinear_kernel &kernel = fKernel [patRow] [patCol]; |
968 | | |
969 | 1.24k | kernel.Finalize (fScale, |
970 | 1.24k | patRow, |
971 | 1.24k | patCol, |
972 | 1.24k | rowStep, |
973 | 1.24k | colStep); |
974 | | |
975 | 1.24k | fCounts [patRow] [patCol] = kernel.fCount; |
976 | 1.24k | fOffsets [patRow] [patCol] = kernel.fOffset; |
977 | 1.24k | fWeights16 [patRow] [patCol] = kernel.fWeight16; |
978 | 1.24k | fWeights32 [patRow] [patCol] = kernel.fWeight32; |
979 | | |
980 | 1.24k | } |
981 | | |
982 | 710 | } |
983 | | |
984 | 280 | } |
985 | | |
986 | 303 | } |
987 | | |
988 | | /*****************************************************************************/ |
989 | | |
990 | | class dng_bilinear_interpolator |
991 | | { |
992 | | |
993 | | private: |
994 | | |
995 | | dng_bilinear_pattern fPattern [kMaxColorPlanes]; |
996 | | |
997 | | public: |
998 | | |
999 | | dng_bilinear_interpolator (const dng_mosaic_info &info, |
1000 | | int32 rowStep, |
1001 | | int32 colStep); |
1002 | | |
1003 | | void Interpolate (dng_pixel_buffer &srcBuffer, |
1004 | | dng_pixel_buffer &dstBuffer); |
1005 | | |
1006 | | }; |
1007 | | |
1008 | | /*****************************************************************************/ |
1009 | | |
1010 | | dng_bilinear_interpolator::dng_bilinear_interpolator (const dng_mosaic_info &info, |
1011 | | int32 rowStep, |
1012 | | int32 colStep) |
1013 | 129 | { |
1014 | | |
1015 | 432 | for (uint32 dstPlane = 0; dstPlane < info.fColorPlanes; dstPlane++) |
1016 | 303 | { |
1017 | | |
1018 | 303 | fPattern [dstPlane] . Calculate (info, |
1019 | 303 | dstPlane, |
1020 | 303 | rowStep, |
1021 | 303 | colStep); |
1022 | | |
1023 | 303 | } |
1024 | | |
1025 | 129 | } |
1026 | | |
1027 | | /*****************************************************************************/ |
1028 | | |
1029 | | void dng_bilinear_interpolator::Interpolate (dng_pixel_buffer &srcBuffer, |
1030 | | dng_pixel_buffer &dstBuffer) |
1031 | 7.10k | { |
1032 | | |
1033 | 7.10k | uint32 patCols = fPattern [0] . fPatCols; |
1034 | 7.10k | uint32 patRows = fPattern [0] . fPatRows; |
1035 | | |
1036 | 7.10k | dng_point scale = fPattern [0] . fScale; |
1037 | | |
1038 | 7.10k | uint32 sRowShift = scale.v - 1; |
1039 | 7.10k | uint32 sColShift = scale.h - 1; |
1040 | | |
1041 | 7.10k | int32 dstCol = dstBuffer.fArea.l; |
1042 | | |
1043 | 7.10k | int32 srcCol = dstCol >> sColShift; |
1044 | | |
1045 | 7.10k | uint32 patPhase = dstCol % patCols; |
1046 | | |
1047 | 7.10k | for (int32 dstRow = dstBuffer.fArea.t; |
1048 | 226k | dstRow < dstBuffer.fArea.b; |
1049 | 219k | dstRow++) |
1050 | 219k | { |
1051 | | |
1052 | 219k | int32 srcRow = dstRow >> sRowShift; |
1053 | | |
1054 | 219k | uint32 patRow = dstRow % patRows; |
1055 | | |
1056 | 219k | for (uint32 dstPlane = 0; |
1057 | 751k | dstPlane < dstBuffer.fPlanes; |
1058 | 532k | dstPlane++) |
1059 | 532k | { |
1060 | | |
1061 | 532k | const void *sPtr = srcBuffer.ConstPixel (srcRow, |
1062 | 532k | srcCol, |
1063 | 532k | srcBuffer.fPlane); |
1064 | | |
1065 | 532k | void *dPtr = dstBuffer.DirtyPixel (dstRow, |
1066 | 532k | dstCol, |
1067 | 532k | dstPlane); |
1068 | | |
1069 | 532k | if (dstBuffer.fPixelType == ttShort) |
1070 | 263k | { |
1071 | | |
1072 | 263k | DoBilinearRow16 ((const uint16 *) sPtr, |
1073 | 263k | (uint16 *) dPtr, |
1074 | 263k | dstBuffer.fArea.W (), |
1075 | 263k | patPhase, |
1076 | 263k | patCols, |
1077 | 263k | fPattern [dstPlane].fCounts [patRow], |
1078 | 263k | fPattern [dstPlane].fOffsets [patRow], |
1079 | 263k | fPattern [dstPlane].fWeights16 [patRow], |
1080 | 263k | sColShift); |
1081 | | |
1082 | 263k | } |
1083 | | |
1084 | 268k | else |
1085 | 268k | { |
1086 | | |
1087 | 268k | DoBilinearRow32 ((const real32 *) sPtr, |
1088 | 268k | (real32 *) dPtr, |
1089 | 268k | dstBuffer.fArea.W (), |
1090 | 268k | patPhase, |
1091 | 268k | patCols, |
1092 | 268k | fPattern [dstPlane].fCounts [patRow], |
1093 | 268k | fPattern [dstPlane].fOffsets [patRow], |
1094 | 268k | fPattern [dstPlane].fWeights32 [patRow], |
1095 | 268k | sColShift); |
1096 | | |
1097 | 268k | } |
1098 | | |
1099 | 532k | } |
1100 | | |
1101 | 219k | } |
1102 | | |
1103 | 7.10k | } |
1104 | | |
1105 | | /*****************************************************************************/ |
1106 | | |
1107 | | class dng_fast_interpolator: public dng_filter_task |
1108 | | { |
1109 | | |
1110 | | protected: |
1111 | | |
1112 | | const dng_mosaic_info &fInfo; |
1113 | | |
1114 | | dng_point fDownScale; |
1115 | | |
1116 | | uint32 fFilterColor [kMaxCFAPattern] [kMaxCFAPattern]; |
1117 | | |
1118 | | public: |
1119 | | |
1120 | | dng_fast_interpolator (const dng_mosaic_info &info, |
1121 | | const dng_image &srcImage, |
1122 | | dng_image &dstImage, |
1123 | | const dng_point &downScale, |
1124 | | uint32 srcPlane); |
1125 | | |
1126 | | virtual dng_rect SrcArea (const dng_rect &dstArea); |
1127 | | |
1128 | | virtual void ProcessArea (uint32 threadIndex, |
1129 | | dng_pixel_buffer &srcBuffer, |
1130 | | dng_pixel_buffer &dstBuffer); |
1131 | | |
1132 | | }; |
1133 | | |
1134 | | /*****************************************************************************/ |
1135 | | |
1136 | | dng_fast_interpolator::dng_fast_interpolator (const dng_mosaic_info &info, |
1137 | | const dng_image &srcImage, |
1138 | | dng_image &dstImage, |
1139 | | const dng_point &downScale, |
1140 | | uint32 srcPlane) |
1141 | | |
1142 | 2 | : dng_filter_task (srcImage, |
1143 | 2 | dstImage) |
1144 | | |
1145 | 2 | , fInfo (info ) |
1146 | 2 | , fDownScale (downScale) |
1147 | | |
1148 | 2 | { |
1149 | | |
1150 | 2 | fSrcPlane = srcPlane; |
1151 | 2 | fSrcPlanes = 1; |
1152 | | |
1153 | 2 | fSrcPixelType = ttShort; |
1154 | 2 | fDstPixelType = ttShort; |
1155 | | |
1156 | 2 | fSrcRepeat = fInfo.fCFAPatternSize; |
1157 | | |
1158 | 2 | fUnitCell = fInfo.fCFAPatternSize; |
1159 | | |
1160 | 2 | fMaxTileSize = dng_point (256 / fDownScale.v, |
1161 | 2 | 256 / fDownScale.h); |
1162 | | |
1163 | 2 | fMaxTileSize.h = Max_int32 (fMaxTileSize.h, fUnitCell.h); |
1164 | 2 | fMaxTileSize.v = Max_int32 (fMaxTileSize.v, fUnitCell.v); |
1165 | | |
1166 | | // Find color map. |
1167 | | |
1168 | 2 | { |
1169 | | |
1170 | 6 | for (int32 r = 0; r < fInfo.fCFAPatternSize.v; r++) |
1171 | 4 | { |
1172 | | |
1173 | 12 | for (int32 c = 0; c < fInfo.fCFAPatternSize.h; c++) |
1174 | 8 | { |
1175 | | |
1176 | 8 | uint8 key = fInfo.fCFAPattern [r] [c]; |
1177 | | |
1178 | 17 | for (uint32 index = 0; index < fInfo.fColorPlanes; index++) |
1179 | 17 | { |
1180 | | |
1181 | 17 | if (key == fInfo.fCFAPlaneColor [index]) |
1182 | 8 | { |
1183 | | |
1184 | 8 | fFilterColor [r] [c] = index; |
1185 | | |
1186 | 8 | break; |
1187 | | |
1188 | 8 | } |
1189 | | |
1190 | 17 | } |
1191 | | |
1192 | 8 | } |
1193 | | |
1194 | 4 | } |
1195 | | |
1196 | 2 | } |
1197 | | |
1198 | 2 | } |
1199 | | |
1200 | | /*****************************************************************************/ |
1201 | | |
1202 | | dng_rect dng_fast_interpolator::SrcArea (const dng_rect &dstArea) |
1203 | 13 | { |
1204 | | |
1205 | 13 | return dng_rect (dstArea.t * fDownScale.v, |
1206 | 13 | dstArea.l * fDownScale.h, |
1207 | 13 | dstArea.b * fDownScale.v, |
1208 | 13 | dstArea.r * fDownScale.h); |
1209 | | |
1210 | 13 | } |
1211 | | |
1212 | | /*****************************************************************************/ |
1213 | | |
1214 | | void dng_fast_interpolator::ProcessArea (uint32 /* threadIndex */, |
1215 | | dng_pixel_buffer &srcBuffer, |
1216 | | dng_pixel_buffer &dstBuffer) |
1217 | 11 | { |
1218 | | |
1219 | 11 | dng_rect srcArea = srcBuffer.fArea; |
1220 | 11 | dng_rect dstArea = dstBuffer.fArea; |
1221 | | |
1222 | | // Downsample buffer. |
1223 | | |
1224 | 11 | int32 srcRow = srcArea.t; |
1225 | | |
1226 | 11 | uint32 srcRowPhase1 = 0; |
1227 | 11 | uint32 srcRowPhase2 = 0; |
1228 | | |
1229 | 11 | uint32 patRows = fInfo.fCFAPatternSize.v; |
1230 | 11 | uint32 patCols = fInfo.fCFAPatternSize.h; |
1231 | | |
1232 | 11 | uint32 cellRows = fDownScale.v; |
1233 | 11 | uint32 cellCols = fDownScale.h; |
1234 | | |
1235 | 11 | uint32 plane; |
1236 | 11 | uint32 planes = fInfo.fColorPlanes; |
1237 | | |
1238 | 11 | int32 dstPlaneStep = dstBuffer.fPlaneStep; |
1239 | | |
1240 | 11 | uint32 total [kMaxColorPlanes]; |
1241 | 11 | uint32 count [kMaxColorPlanes]; |
1242 | | |
1243 | 54 | for (plane = 0; plane < planes; plane++) |
1244 | 43 | { |
1245 | 43 | total [plane] = 0; |
1246 | 43 | count [plane] = 0; |
1247 | 43 | } |
1248 | | |
1249 | 25 | for (int32 dstRow = dstArea.t; dstRow < dstArea.b; dstRow++) |
1250 | 14 | { |
1251 | | |
1252 | 14 | const uint16 *sPtr = srcBuffer.ConstPixel_uint16 (srcRow, |
1253 | 14 | srcArea.l, |
1254 | 14 | fSrcPlane); |
1255 | | |
1256 | 14 | uint16 *dPtr = dstBuffer.DirtyPixel_uint16 (dstRow, |
1257 | 14 | dstArea.l, |
1258 | 14 | 0); |
1259 | | |
1260 | 14 | uint32 srcColPhase1 = 0; |
1261 | 14 | uint32 srcColPhase2 = 0; |
1262 | | |
1263 | 55 | for (int32 dstCol = dstArea.l; dstCol < dstArea.r; dstCol++) |
1264 | 41 | { |
1265 | | |
1266 | 41 | const uint16 *ssPtr = sPtr; |
1267 | | |
1268 | 41 | srcRowPhase2 = srcRowPhase1; |
1269 | | |
1270 | 2.43k | for (uint32 cellRow = 0; cellRow < cellRows; cellRow++) |
1271 | 2.39k | { |
1272 | | |
1273 | 2.39k | const uint32 *filterRow = fFilterColor [srcRowPhase2]; |
1274 | | |
1275 | 2.39k | if (++srcRowPhase2 == patRows) |
1276 | 1.19k | { |
1277 | 1.19k | srcRowPhase2 = 0; |
1278 | 1.19k | } |
1279 | | |
1280 | 2.39k | srcColPhase2 = srcColPhase1; |
1281 | | |
1282 | 154k | for (uint32 cellCol = 0; cellCol < cellCols; cellCol++) |
1283 | 151k | { |
1284 | | |
1285 | 151k | uint32 color = filterRow [srcColPhase2]; |
1286 | | |
1287 | 151k | if (++srcColPhase2 == patCols) |
1288 | 75.8k | { |
1289 | 75.8k | srcColPhase2 = 0; |
1290 | 75.8k | } |
1291 | | |
1292 | 151k | total [color] += (uint32) ssPtr [cellCol]; |
1293 | 151k | count [color] ++; |
1294 | | |
1295 | 151k | } |
1296 | | |
1297 | 2.39k | ssPtr += srcBuffer.fRowStep; |
1298 | | |
1299 | 2.39k | } |
1300 | | |
1301 | 201 | for (plane = 0; plane < planes; plane++) |
1302 | 160 | { |
1303 | | |
1304 | 160 | uint32 t = total [plane]; |
1305 | 160 | uint32 c = count [plane]; |
1306 | | |
1307 | 160 | dPtr [plane * dstPlaneStep] = (uint16) ((t + (c >> 1)) / c); |
1308 | | |
1309 | 160 | total [plane] = 0; |
1310 | 160 | count [plane] = 0; |
1311 | | |
1312 | 160 | } |
1313 | | |
1314 | 41 | srcColPhase1 = srcColPhase2; |
1315 | | |
1316 | 41 | sPtr += cellCols; |
1317 | | |
1318 | 41 | dPtr ++; |
1319 | | |
1320 | 41 | } |
1321 | | |
1322 | 14 | srcRowPhase1 = srcRowPhase2; |
1323 | | |
1324 | 14 | srcRow += cellRows; |
1325 | | |
1326 | 14 | } |
1327 | | |
1328 | 11 | } |
1329 | | |
1330 | | /*****************************************************************************/ |
1331 | | |
1332 | | dng_mosaic_info::dng_mosaic_info () |
1333 | | |
1334 | 24.7k | : fCFAPatternSize () |
1335 | 24.7k | , fColorPlanes (0) |
1336 | 24.7k | , fCFALayout (1) |
1337 | 24.7k | , fBayerGreenSplit (0) |
1338 | 24.7k | , fSrcSize () |
1339 | 24.7k | , fCroppedSize () |
1340 | 24.7k | , fAspectRatio (1.0) |
1341 | | |
1342 | 24.7k | { |
1343 | | |
1344 | 24.7k | } |
1345 | | |
1346 | | /*****************************************************************************/ |
1347 | | |
1348 | | dng_mosaic_info::~dng_mosaic_info () |
1349 | 24.7k | { |
1350 | | |
1351 | 24.7k | } |
1352 | | |
1353 | | /*****************************************************************************/ |
1354 | | |
1355 | | void dng_mosaic_info::Parse (dng_host & /* host */, |
1356 | | dng_stream & /* stream */, |
1357 | | dng_info &info) |
1358 | 218 | { |
1359 | | |
1360 | | // Find main image IFD. |
1361 | | |
1362 | 218 | dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get (); |
1363 | | |
1364 | | // This information only applies to CFA images. |
1365 | | |
1366 | 218 | if (rawIFD.fPhotometricInterpretation != piCFA) |
1367 | 0 | { |
1368 | 0 | return; |
1369 | 0 | } |
1370 | | |
1371 | | // Copy CFA pattern. |
1372 | | |
1373 | 218 | fCFAPatternSize.v = rawIFD.fCFARepeatPatternRows; |
1374 | 218 | fCFAPatternSize.h = rawIFD.fCFARepeatPatternCols; |
1375 | | |
1376 | 755 | for (int32 j = 0; j < fCFAPatternSize.v; j++) |
1377 | 537 | { |
1378 | 1.40k | for (int32 k = 0; k < fCFAPatternSize.h; k++) |
1379 | 868 | { |
1380 | 868 | fCFAPattern [j] [k] = rawIFD.fCFAPattern [j] [k]; |
1381 | 868 | } |
1382 | 537 | } |
1383 | | |
1384 | | // Copy CFA plane information. |
1385 | | |
1386 | 218 | fColorPlanes = info.fShared->fCameraProfile.fColorPlanes; |
1387 | | |
1388 | 695 | for (uint32 n = 0; n < fColorPlanes; n++) |
1389 | 477 | { |
1390 | 477 | fCFAPlaneColor [n] = rawIFD.fCFAPlaneColor [n]; |
1391 | 477 | } |
1392 | | |
1393 | | // Copy CFA layout information. |
1394 | | |
1395 | 218 | fCFALayout = rawIFD.fCFALayout; |
1396 | | |
1397 | | // Green split value for Bayer patterns. |
1398 | | |
1399 | 218 | fBayerGreenSplit = rawIFD.fBayerGreenSplit; |
1400 | | |
1401 | 218 | } |
1402 | | |
1403 | | /*****************************************************************************/ |
1404 | | |
1405 | | void dng_mosaic_info::PostParse (dng_host & /* host */, |
1406 | | dng_negative &negative) |
1407 | 9.32k | { |
1408 | | |
1409 | | // Keep track of source image size. |
1410 | | |
1411 | 9.32k | fSrcSize = negative.Stage2Image ()->Size (); |
1412 | | |
1413 | | // Default cropped size. |
1414 | | |
1415 | 9.32k | fCroppedSize.v = Round_int32 (negative.DefaultCropSizeV ().As_real64 ()); |
1416 | 9.32k | fCroppedSize.h = Round_int32 (negative.DefaultCropSizeH ().As_real64 ()); |
1417 | | |
1418 | | // Pixel aspect ratio. |
1419 | | |
1420 | 9.32k | fAspectRatio = negative.DefaultScaleH ().As_real64 () / |
1421 | 9.32k | negative.DefaultScaleV ().As_real64 (); |
1422 | | |
1423 | 9.32k | } |
1424 | | |
1425 | | /*****************************************************************************/ |
1426 | | |
1427 | | bool dng_mosaic_info::SetFourColorBayer () |
1428 | 13 | { |
1429 | | |
1430 | 13 | if (fCFAPatternSize != dng_point (2, 2)) |
1431 | 0 | { |
1432 | 0 | return false; |
1433 | 0 | } |
1434 | | |
1435 | 13 | if (fColorPlanes != 3) |
1436 | 0 | { |
1437 | 0 | return false; |
1438 | 0 | } |
1439 | | |
1440 | 13 | uint8 color0 = fCFAPlaneColor [0]; |
1441 | 13 | uint8 color1 = fCFAPlaneColor [1]; |
1442 | 13 | uint8 color2 = fCFAPlaneColor [2]; |
1443 | | |
1444 | | // Look for color 1 repeated twice in a diagonal. |
1445 | | |
1446 | 13 | if ((fCFAPattern [0] [0] == color1 && fCFAPattern [1] [1] == color1) || |
1447 | 13 | (fCFAPattern [0] [1] == color1 && fCFAPattern [1] [0] == color1)) |
1448 | 11 | { |
1449 | | |
1450 | | // OK, this looks like a Bayer pattern. |
1451 | | |
1452 | | // Find unused color code. |
1453 | | |
1454 | 11 | uint8 color3 = 0; |
1455 | | |
1456 | 44 | while (color3 == color0 || |
1457 | 44 | color3 == color1 || |
1458 | 44 | color3 == color2) |
1459 | 33 | { |
1460 | 33 | color3++; |
1461 | 33 | } |
1462 | | |
1463 | | // Switch the four color mosaic. |
1464 | | |
1465 | 11 | fColorPlanes = 4; |
1466 | | |
1467 | 11 | fCFAPlaneColor [3] = color3; |
1468 | | |
1469 | | // Replace the "green" in the "blue" rows with the new color. |
1470 | | |
1471 | 11 | if (fCFAPattern [0] [0] == color0) |
1472 | 11 | { |
1473 | 11 | fCFAPattern [1] [0] = color3; |
1474 | 11 | } |
1475 | | |
1476 | 0 | else if (fCFAPattern [0] [1] == color0) |
1477 | 0 | { |
1478 | 0 | fCFAPattern [1] [1] = color3; |
1479 | 0 | } |
1480 | | |
1481 | 0 | else if (fCFAPattern [1] [0] == color0) |
1482 | 0 | { |
1483 | 0 | fCFAPattern [0] [0] = color3; |
1484 | 0 | } |
1485 | | |
1486 | 0 | else |
1487 | 0 | { |
1488 | 0 | fCFAPattern [0] [1] = color3; |
1489 | 0 | } |
1490 | | |
1491 | 11 | return true; |
1492 | | |
1493 | 11 | } |
1494 | | |
1495 | 2 | return false; |
1496 | | |
1497 | 13 | } |
1498 | | |
1499 | | /*****************************************************************************/ |
1500 | | |
1501 | | dng_point dng_mosaic_info::FullScale () const |
1502 | 561 | { |
1503 | | |
1504 | 561 | switch (fCFALayout) |
1505 | 561 | { |
1506 | | |
1507 | | // Staggered layouts with offset columns double the row count |
1508 | | // during interpolation. |
1509 | | |
1510 | 25 | case 2: |
1511 | 37 | case 3: |
1512 | 37 | return dng_point (2, 1); |
1513 | | |
1514 | | // Staggered layouts with offset rows double the column count |
1515 | | // during interpolation. |
1516 | | |
1517 | 12 | case 4: |
1518 | 28 | case 5: |
1519 | 28 | return dng_point (1, 2); |
1520 | | |
1521 | | // Otherwise there is no size change during interpolation. |
1522 | | |
1523 | 496 | default: |
1524 | 496 | break; |
1525 | | |
1526 | 561 | } |
1527 | | |
1528 | 496 | return dng_point (1, 1); |
1529 | | |
1530 | 561 | } |
1531 | | |
1532 | | /*****************************************************************************/ |
1533 | | |
1534 | | bool dng_mosaic_info::IsSafeDownScale (const dng_point &downScale) const |
1535 | 92 | { |
1536 | | |
1537 | 92 | if (downScale.v >= fCFAPatternSize.v && |
1538 | 92 | downScale.h >= fCFAPatternSize.h) |
1539 | 80 | { |
1540 | | |
1541 | 80 | return true; |
1542 | | |
1543 | 80 | } |
1544 | | |
1545 | 12 | dng_point test; |
1546 | | |
1547 | 12 | test.v = Min_int32 (downScale.v, fCFAPatternSize.v); |
1548 | 12 | test.h = Min_int32 (downScale.h, fCFAPatternSize.h); |
1549 | | |
1550 | 13 | for (int32 phaseV = 0; phaseV <= fCFAPatternSize.v - test.v; phaseV++) |
1551 | 12 | { |
1552 | | |
1553 | 15 | for (int32 phaseH = 0; phaseH <= fCFAPatternSize.h - test.h; phaseH++) |
1554 | 14 | { |
1555 | | |
1556 | 14 | uint32 plane; |
1557 | | |
1558 | 14 | bool contains [kMaxColorPlanes]; |
1559 | | |
1560 | 55 | for (plane = 0; plane < fColorPlanes; plane++) |
1561 | 41 | { |
1562 | | |
1563 | 41 | contains [plane] = false; |
1564 | | |
1565 | 41 | } |
1566 | | |
1567 | 28 | for (int32 srcRow = 0; srcRow < test.v; srcRow++) |
1568 | 14 | { |
1569 | | |
1570 | 31 | for (int32 srcCol = 0; srcCol < test.h; srcCol++) |
1571 | 17 | { |
1572 | | |
1573 | 17 | uint8 srcKey = fCFAPattern [srcRow + phaseV] |
1574 | 17 | [srcCol + phaseH]; |
1575 | | |
1576 | 64 | for (plane = 0; plane < fColorPlanes; plane++) |
1577 | 47 | { |
1578 | | |
1579 | 47 | if (srcKey == fCFAPlaneColor [plane]) |
1580 | 17 | { |
1581 | | |
1582 | 17 | contains [plane] = true; |
1583 | | |
1584 | 17 | } |
1585 | | |
1586 | 47 | } |
1587 | | |
1588 | | |
1589 | 17 | } |
1590 | | |
1591 | 14 | } |
1592 | | |
1593 | 28 | for (plane = 0; plane < fColorPlanes; plane++) |
1594 | 25 | { |
1595 | | |
1596 | 25 | if (!contains [plane]) |
1597 | 11 | { |
1598 | | |
1599 | 11 | return false; |
1600 | | |
1601 | 11 | } |
1602 | | |
1603 | 25 | } |
1604 | | |
1605 | 14 | } |
1606 | | |
1607 | 12 | } |
1608 | | |
1609 | 1 | return true; |
1610 | | |
1611 | 12 | } |
1612 | | |
1613 | | /*****************************************************************************/ |
1614 | | |
1615 | | uint32 dng_mosaic_info::SizeForDownScale (const dng_point &downScale) const |
1616 | 162 | { |
1617 | | |
1618 | 162 | uint32 sizeV = Max_uint32 (1, (fCroppedSize.v + (downScale.v >> 1)) / downScale.v); |
1619 | 162 | uint32 sizeH = Max_uint32 (1, (fCroppedSize.h + (downScale.h >> 1)) / downScale.h); |
1620 | | |
1621 | 162 | return Max_int32 (sizeV, sizeH); |
1622 | | |
1623 | 162 | } |
1624 | | |
1625 | | /*****************************************************************************/ |
1626 | | |
1627 | | bool dng_mosaic_info::ValidSizeDownScale (const dng_point &downScale, |
1628 | | uint32 minSize) const |
1629 | 81 | { |
1630 | | |
1631 | 81 | const int32 kMaxDownScale = 64; |
1632 | | |
1633 | 81 | if (downScale.h > kMaxDownScale || |
1634 | 81 | downScale.v > kMaxDownScale) |
1635 | 1 | { |
1636 | | |
1637 | 1 | return false; |
1638 | | |
1639 | 1 | } |
1640 | | |
1641 | 80 | return SizeForDownScale (downScale) >= minSize; |
1642 | | |
1643 | 81 | } |
1644 | | |
1645 | | /*****************************************************************************/ |
1646 | | |
1647 | | dng_point dng_mosaic_info::DownScale (uint32 minSize, |
1648 | | uint32 prefSize, |
1649 | | real64 cropFactor) const |
1650 | 132 | { |
1651 | | |
1652 | 132 | dng_point bestScale (1, 1); |
1653 | | |
1654 | 132 | if (prefSize && IsColorFilterArray ()) |
1655 | 13 | { |
1656 | | |
1657 | | // Adjust sizes for crop factor. |
1658 | | |
1659 | 13 | minSize = Round_uint32 (minSize / cropFactor); |
1660 | 13 | prefSize = Round_uint32 (prefSize / cropFactor); |
1661 | | |
1662 | 13 | prefSize = Max_uint32 (prefSize, minSize); |
1663 | | |
1664 | | // Start by assuming we need the full size image. |
1665 | | |
1666 | 13 | int32 bestSize = SizeForDownScale (bestScale); |
1667 | | |
1668 | | // Find size of nearly square cell. |
1669 | | |
1670 | 13 | dng_point squareCell (1, 1); |
1671 | | |
1672 | 13 | if (fAspectRatio < 1.0 / 1.8) |
1673 | 1 | { |
1674 | | |
1675 | 1 | squareCell.h = Min_int32 (4, Round_int32 (1.0 / fAspectRatio)); |
1676 | | |
1677 | 1 | } |
1678 | | |
1679 | 13 | if (fAspectRatio > 1.8) |
1680 | 1 | { |
1681 | | |
1682 | 1 | squareCell.v = Min_int32 (4, Round_int32 (fAspectRatio)); |
1683 | | |
1684 | 1 | } |
1685 | | |
1686 | | // Find minimum safe cell size. |
1687 | | |
1688 | 13 | dng_point testScale = squareCell; |
1689 | | |
1690 | 24 | while (!IsSafeDownScale (testScale)) |
1691 | 11 | { |
1692 | | |
1693 | 11 | testScale.v += squareCell.v; |
1694 | 11 | testScale.h += squareCell.h; |
1695 | | |
1696 | 11 | } |
1697 | | |
1698 | | // See if this scale is usable. |
1699 | | |
1700 | 13 | if (!ValidSizeDownScale (testScale, minSize)) |
1701 | 10 | { |
1702 | | |
1703 | | // We cannot downsample at all... |
1704 | | |
1705 | 10 | return bestScale; |
1706 | | |
1707 | 10 | } |
1708 | | |
1709 | | // See if this is closer to the preferred size. |
1710 | | |
1711 | 3 | int32 testSize = SizeForDownScale (testScale); |
1712 | | |
1713 | 3 | if (Abs_int32 (testSize - (int32) prefSize) <= |
1714 | 3 | Abs_int32 (bestSize - (int32) prefSize)) |
1715 | 2 | { |
1716 | 2 | bestScale = testScale; |
1717 | 2 | bestSize = testSize; |
1718 | 2 | } |
1719 | | |
1720 | 1 | else |
1721 | 1 | { |
1722 | 1 | return bestScale; |
1723 | 1 | } |
1724 | | |
1725 | | // Now keep adding square cells as long as possible. |
1726 | | |
1727 | 69 | while (true) |
1728 | 69 | { |
1729 | | |
1730 | 69 | testScale.v += squareCell.v; |
1731 | 69 | testScale.h += squareCell.h; |
1732 | | |
1733 | 69 | if (IsSafeDownScale (testScale)) |
1734 | 69 | { |
1735 | | |
1736 | 69 | if (!ValidSizeDownScale (testScale, minSize)) |
1737 | 2 | { |
1738 | 2 | return bestScale; |
1739 | 2 | } |
1740 | | |
1741 | | // See if this is closer to the preferred size. |
1742 | | |
1743 | 67 | testSize = SizeForDownScale (testScale); |
1744 | | |
1745 | 67 | if (Abs_int32 (testSize - (int32) prefSize) <= |
1746 | 67 | Abs_int32 (bestSize - (int32) prefSize)) |
1747 | 67 | { |
1748 | 67 | bestScale = testScale; |
1749 | 67 | bestSize = testSize; |
1750 | 67 | } |
1751 | | |
1752 | 0 | else |
1753 | 0 | { |
1754 | 0 | return bestScale; |
1755 | 0 | } |
1756 | | |
1757 | 67 | } |
1758 | | |
1759 | 69 | } |
1760 | | |
1761 | 2 | } |
1762 | | |
1763 | 119 | return bestScale; |
1764 | | |
1765 | 132 | } |
1766 | | |
1767 | | /*****************************************************************************/ |
1768 | | |
1769 | | dng_point dng_mosaic_info::DstSize (const dng_point &downScale) const |
1770 | 131 | { |
1771 | | |
1772 | 131 | if (downScale == dng_point (1, 1)) |
1773 | 129 | { |
1774 | | |
1775 | 129 | dng_point scale = FullScale (); |
1776 | | |
1777 | 129 | return dng_point (fSrcSize.v * scale.v, |
1778 | 129 | fSrcSize.h * scale.h); |
1779 | | |
1780 | 129 | } |
1781 | | |
1782 | 2 | const int32 kMaxDownScale = 64; |
1783 | | |
1784 | 2 | if (downScale.h > kMaxDownScale || |
1785 | 2 | downScale.v > kMaxDownScale) |
1786 | 0 | { |
1787 | | |
1788 | 0 | return dng_point (0, 0); |
1789 | | |
1790 | 0 | } |
1791 | | |
1792 | 2 | dng_point size; |
1793 | | |
1794 | 2 | size.v = Max_int32 (1, (fSrcSize.v + (downScale.v >> 1)) / downScale.v); |
1795 | 2 | size.h = Max_int32 (1, (fSrcSize.h + (downScale.h >> 1)) / downScale.h); |
1796 | | |
1797 | 2 | return size; |
1798 | | |
1799 | 2 | } |
1800 | | |
1801 | | /*****************************************************************************/ |
1802 | | |
1803 | | void dng_mosaic_info::InterpolateGeneric (dng_host &host, |
1804 | | dng_negative & /* negative */, |
1805 | | const dng_image &srcImage, |
1806 | | dng_image &dstImage, |
1807 | | uint32 srcPlane) const |
1808 | 129 | { |
1809 | | |
1810 | | // Find destination to source bit shifts. |
1811 | | |
1812 | 129 | dng_point scale = FullScale (); |
1813 | | |
1814 | 129 | uint32 srcShiftV = scale.v - 1; |
1815 | 129 | uint32 srcShiftH = scale.h - 1; |
1816 | | |
1817 | | // Find tile sizes. |
1818 | | |
1819 | 129 | const uint32 kMaxDstTileRows = 128; |
1820 | 129 | const uint32 kMaxDstTileCols = 128; |
1821 | | |
1822 | 129 | dng_point dstTileSize = dstImage.RepeatingTile ().Size (); |
1823 | | |
1824 | 129 | dstTileSize.v = Min_int32 (dstTileSize.v, kMaxDstTileRows); |
1825 | 129 | dstTileSize.h = Min_int32 (dstTileSize.h, kMaxDstTileCols); |
1826 | | |
1827 | 129 | dng_point srcTileSize = dstTileSize; |
1828 | | |
1829 | 129 | srcTileSize.v >>= srcShiftV; |
1830 | 129 | srcTileSize.h >>= srcShiftH; |
1831 | | |
1832 | 129 | srcTileSize.v += fCFAPatternSize.v * 2; |
1833 | 129 | srcTileSize.h += fCFAPatternSize.h * 2; |
1834 | | |
1835 | | // Allocate source buffer. |
1836 | | |
1837 | 129 | dng_pixel_buffer srcBuffer (dng_rect (srcTileSize), srcPlane, 1, |
1838 | 129 | srcImage.PixelType (), pcInterleaved, NULL); |
1839 | | |
1840 | 129 | uint32 srcBufferSize = ComputeBufferSize (srcBuffer.fPixelType, |
1841 | 129 | srcTileSize, srcBuffer.fPlanes, |
1842 | 129 | padNone); |
1843 | | |
1844 | 129 | AutoPtr<dng_memory_block> srcData (host.Allocate (srcBufferSize)); |
1845 | | |
1846 | 129 | srcBuffer.fData = srcData->Buffer (); |
1847 | | |
1848 | | // Allocate destination buffer. |
1849 | | |
1850 | 129 | dng_pixel_buffer dstBuffer (dng_rect (dstTileSize), 0, fColorPlanes, |
1851 | 129 | dstImage.PixelType (), pcRowInterleaved, NULL); |
1852 | | |
1853 | 129 | uint32 dstBufferSize = ComputeBufferSize (dstBuffer.fPixelType, |
1854 | 129 | dstTileSize, dstBuffer.fPlanes, |
1855 | 129 | padNone); |
1856 | | |
1857 | 129 | AutoPtr<dng_memory_block> dstData (host.Allocate (dstBufferSize)); |
1858 | | |
1859 | 129 | dstBuffer.fData = dstData->Buffer (); |
1860 | | |
1861 | | // Create interpolator. |
1862 | | |
1863 | 129 | AutoPtr<dng_bilinear_interpolator> interpolator (new dng_bilinear_interpolator (*this, |
1864 | 129 | srcBuffer.fRowStep, |
1865 | 129 | srcBuffer.fColStep)); |
1866 | | |
1867 | | // Iterate over destination tiles. |
1868 | | |
1869 | 129 | dng_rect dstArea; |
1870 | | |
1871 | 129 | dng_tile_iterator iter1 (dstImage, dstImage.Bounds ()); |
1872 | | |
1873 | 258 | while (iter1.GetOneTile (dstArea)) |
1874 | 129 | { |
1875 | | |
1876 | | // Break into buffer sized tiles. |
1877 | | |
1878 | 129 | dng_rect dstTile; |
1879 | | |
1880 | 129 | dng_tile_iterator iter2 (dstTileSize, dstArea); |
1881 | | |
1882 | 7.22k | while (iter2.GetOneTile (dstTile)) |
1883 | 7.10k | { |
1884 | | |
1885 | 7.10k | host.SniffForAbort (); |
1886 | | |
1887 | | // Setup buffers for this tile. |
1888 | | |
1889 | 7.10k | dng_rect srcTile (dstTile); |
1890 | | |
1891 | 7.10k | srcTile.t >>= srcShiftV; |
1892 | 7.10k | srcTile.b >>= srcShiftV; |
1893 | | |
1894 | 7.10k | srcTile.l >>= srcShiftH; |
1895 | 7.10k | srcTile.r >>= srcShiftH; |
1896 | | |
1897 | 7.10k | srcTile.t -= fCFAPatternSize.v; |
1898 | 7.10k | srcTile.b += fCFAPatternSize.v; |
1899 | | |
1900 | 7.10k | srcTile.l -= fCFAPatternSize.h; |
1901 | 7.10k | srcTile.r += fCFAPatternSize.h; |
1902 | | |
1903 | 7.10k | srcBuffer.fArea = srcTile; |
1904 | 7.10k | dstBuffer.fArea = dstTile; |
1905 | | |
1906 | | // Get source data. |
1907 | | |
1908 | 7.10k | srcImage.Get (srcBuffer, |
1909 | 7.10k | dng_image::edge_repeat, |
1910 | 7.10k | fCFAPatternSize.v, |
1911 | 7.10k | fCFAPatternSize.h); |
1912 | | |
1913 | | // Process data. |
1914 | | |
1915 | 7.10k | interpolator->Interpolate (srcBuffer, |
1916 | 7.10k | dstBuffer); |
1917 | | |
1918 | | // Save results. |
1919 | | |
1920 | 7.10k | dstImage.Put (dstBuffer); |
1921 | | |
1922 | 7.10k | } |
1923 | | |
1924 | 129 | } |
1925 | | |
1926 | 129 | } |
1927 | | |
1928 | | /*****************************************************************************/ |
1929 | | |
1930 | | void dng_mosaic_info::InterpolateFast (dng_host &host, |
1931 | | dng_negative & /* negative */, |
1932 | | const dng_image &srcImage, |
1933 | | dng_image &dstImage, |
1934 | | const dng_point &downScale, |
1935 | | uint32 srcPlane) const |
1936 | 2 | { |
1937 | | |
1938 | | // Create fast interpolator task. |
1939 | | |
1940 | 2 | dng_fast_interpolator interpolator (*this, |
1941 | 2 | srcImage, |
1942 | 2 | dstImage, |
1943 | 2 | downScale, |
1944 | 2 | srcPlane); |
1945 | | |
1946 | | // Find area to process. |
1947 | | |
1948 | 2 | dng_rect bounds = dstImage.Bounds (); |
1949 | | |
1950 | | // Do the interpolation. |
1951 | | |
1952 | 2 | host.PerformAreaTask (interpolator, |
1953 | 2 | bounds); |
1954 | | |
1955 | 2 | } |
1956 | | |
1957 | | /*****************************************************************************/ |
1958 | | |
1959 | | void dng_mosaic_info::Interpolate (dng_host &host, |
1960 | | dng_negative &negative, |
1961 | | const dng_image &srcImage, |
1962 | | dng_image &dstImage, |
1963 | | const dng_point &downScale, |
1964 | | uint32 srcPlane) const |
1965 | 131 | { |
1966 | | |
1967 | 131 | if (downScale == dng_point (1, 1)) |
1968 | 129 | { |
1969 | | |
1970 | 129 | InterpolateGeneric (host, |
1971 | 129 | negative, |
1972 | 129 | srcImage, |
1973 | 129 | dstImage, |
1974 | 129 | srcPlane); |
1975 | | |
1976 | 129 | } |
1977 | | |
1978 | 2 | else |
1979 | 2 | { |
1980 | | |
1981 | 2 | InterpolateFast (host, |
1982 | 2 | negative, |
1983 | 2 | srcImage, |
1984 | 2 | dstImage, |
1985 | 2 | downScale, |
1986 | 2 | srcPlane); |
1987 | | |
1988 | 2 | } |
1989 | | |
1990 | 131 | } |
1991 | | |
1992 | | /*****************************************************************************/ |