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