1 | /*****************************************************************************/ |
2 | // Copyright 2008 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_bad_pixels.cpp#1 $ */ |
10 | /* $DateTime: 2012/05/30 13:28:51 $ */ |
11 | /* $Change: 832332 $ */ |
12 | /* $Author: tknoll $ */ |
13 | |
14 | /*****************************************************************************/ |
15 | |
16 | #include "dng_bad_pixels.h" |
17 | |
18 | #include "dng_filter_task.h" |
19 | #include "dng_globals.h" |
20 | #include "dng_host.h" |
21 | #include "dng_image.h" |
22 | #include "dng_negative.h" |
23 | #include "dng_safe_arithmetic.h" |
24 | |
25 | #include <algorithm> |
26 | |
27 | /*****************************************************************************/ |
28 | |
29 | dng_opcode_FixBadPixelsConstant::dng_opcode_FixBadPixelsConstant |
30 | (uint32 constant, |
31 | uint32 bayerPhase) |
32 | |
33 | : dng_filter_opcode (dngOpcode_FixBadPixelsConstant, |
34 | dngVersion_1_3_0_0, |
35 | 0) |
36 | |
37 | , fConstant (constant) |
38 | , fBayerPhase (bayerPhase) |
39 | |
40 | { |
41 | |
42 | } |
43 | |
44 | /*****************************************************************************/ |
45 | |
46 | dng_opcode_FixBadPixelsConstant::dng_opcode_FixBadPixelsConstant |
47 | (dng_stream &stream) |
48 | |
49 | : dng_filter_opcode (dngOpcode_FixBadPixelsConstant, |
50 | stream, |
51 | "FixBadPixelsConstant" ) |
52 | |
53 | , fConstant (0) |
54 | , fBayerPhase (0) |
55 | |
56 | { |
57 | |
58 | if (stream.Get_uint32 () != 8) |
59 | { |
60 | ThrowBadFormat (); |
61 | } |
62 | |
63 | fConstant = stream.Get_uint32 (); |
64 | fBayerPhase = stream.Get_uint32 (); |
65 | |
66 | #if qDNGValidate |
67 | |
68 | if (gVerbose) |
69 | { |
70 | |
71 | printf ("Constant: %u\n" , (unsigned) fConstant); |
72 | |
73 | printf ("Bayer Phase: %u\n" , (unsigned) fBayerPhase); |
74 | |
75 | } |
76 | |
77 | #endif |
78 | |
79 | } |
80 | |
81 | /*****************************************************************************/ |
82 | |
83 | void dng_opcode_FixBadPixelsConstant::PutData (dng_stream &stream) const |
84 | { |
85 | |
86 | stream.Put_uint32 (8); |
87 | |
88 | stream.Put_uint32 (fConstant ); |
89 | stream.Put_uint32 (fBayerPhase); |
90 | |
91 | } |
92 | |
93 | /*****************************************************************************/ |
94 | |
95 | dng_point dng_opcode_FixBadPixelsConstant::SrcRepeat () |
96 | { |
97 | |
98 | return dng_point (2, 2); |
99 | |
100 | } |
101 | |
102 | /*****************************************************************************/ |
103 | |
104 | dng_rect dng_opcode_FixBadPixelsConstant::SrcArea (const dng_rect &dstArea, |
105 | const dng_rect & /* imageBounds */) |
106 | { |
107 | |
108 | dng_rect srcArea = dstArea; |
109 | |
110 | srcArea.t -= 2; |
111 | srcArea.l -= 2; |
112 | |
113 | srcArea.b += 2; |
114 | srcArea.r += 2; |
115 | |
116 | return srcArea; |
117 | |
118 | } |
119 | |
120 | /*****************************************************************************/ |
121 | |
122 | void dng_opcode_FixBadPixelsConstant::Prepare (dng_negative & /* negative */, |
123 | uint32 /* threadCount */, |
124 | const dng_point & /* tileSize */, |
125 | const dng_rect & /* imageBounds */, |
126 | uint32 imagePlanes, |
127 | uint32 bufferPixelType, |
128 | dng_memory_allocator & /* allocator */) |
129 | { |
130 | |
131 | // This opcode is restricted to single channel images. |
132 | |
133 | if (imagePlanes != 1) |
134 | { |
135 | |
136 | ThrowBadFormat (); |
137 | |
138 | } |
139 | |
140 | // This opcode is restricted to 16-bit images. |
141 | |
142 | if (bufferPixelType != ttShort) |
143 | { |
144 | |
145 | ThrowBadFormat (); |
146 | |
147 | } |
148 | |
149 | } |
150 | |
151 | /*****************************************************************************/ |
152 | |
153 | void dng_opcode_FixBadPixelsConstant::ProcessArea (dng_negative & /* negative */, |
154 | uint32 /* threadIndex */, |
155 | dng_pixel_buffer &srcBuffer, |
156 | dng_pixel_buffer &dstBuffer, |
157 | const dng_rect &dstArea, |
158 | const dng_rect & /* imageBounds */) |
159 | { |
160 | |
161 | dstBuffer.CopyArea (srcBuffer, |
162 | dstArea, |
163 | 0, |
164 | dstBuffer.fPlanes); |
165 | |
166 | uint16 badPixel = (uint16) fConstant; |
167 | |
168 | for (int32 dstRow = dstArea.t; dstRow < dstArea.b; dstRow++) |
169 | { |
170 | |
171 | const uint16 *sPtr = srcBuffer.ConstPixel_uint16 (dstRow, dstArea.l, 0); |
172 | uint16 *dPtr = dstBuffer.DirtyPixel_uint16 (dstRow, dstArea.l, 0); |
173 | |
174 | for (int32 dstCol = dstArea.l; dstCol < dstArea.r; dstCol++) |
175 | { |
176 | |
177 | if (*sPtr == badPixel) |
178 | { |
179 | |
180 | uint32 count = 0; |
181 | uint32 total = 0; |
182 | |
183 | uint16 value; |
184 | |
185 | if (IsGreen (dstRow, dstCol)) // Green pixel |
186 | { |
187 | |
188 | value = sPtr [-srcBuffer.fRowStep - 1]; |
189 | |
190 | if (value != badPixel) |
191 | { |
192 | count += 1; |
193 | total += value; |
194 | } |
195 | |
196 | value = sPtr [-srcBuffer.fRowStep + 1]; |
197 | |
198 | if (value != badPixel) |
199 | { |
200 | count += 1; |
201 | total += value; |
202 | } |
203 | |
204 | value = sPtr [srcBuffer.fRowStep - 1]; |
205 | |
206 | if (value != badPixel) |
207 | { |
208 | count += 1; |
209 | total += value; |
210 | } |
211 | |
212 | value = sPtr [srcBuffer.fRowStep + 1]; |
213 | |
214 | if (value != badPixel) |
215 | { |
216 | count += 1; |
217 | total += value; |
218 | } |
219 | |
220 | } |
221 | |
222 | else // Red/blue pixel. |
223 | { |
224 | |
225 | value = sPtr [-srcBuffer.fRowStep * 2]; |
226 | |
227 | if (value != badPixel) |
228 | { |
229 | count += 1; |
230 | total += value; |
231 | } |
232 | |
233 | value = sPtr [srcBuffer.fRowStep * 2]; |
234 | |
235 | if (value != badPixel) |
236 | { |
237 | count += 1; |
238 | total += value; |
239 | } |
240 | |
241 | value = sPtr [-2]; |
242 | |
243 | if (value != badPixel) |
244 | { |
245 | count += 1; |
246 | total += value; |
247 | } |
248 | |
249 | value = sPtr [2]; |
250 | |
251 | if (value != badPixel) |
252 | { |
253 | count += 1; |
254 | total += value; |
255 | } |
256 | |
257 | } |
258 | |
259 | if (count == 4) // Most common case. |
260 | { |
261 | |
262 | *dPtr = (uint16) ((total + 2) >> 2); |
263 | |
264 | } |
265 | |
266 | else if (count > 0) |
267 | { |
268 | |
269 | *dPtr = (uint16) ((total + (count >> 1)) / count); |
270 | |
271 | } |
272 | |
273 | } |
274 | |
275 | sPtr++; |
276 | dPtr++; |
277 | |
278 | } |
279 | |
280 | } |
281 | |
282 | } |
283 | |
284 | /*****************************************************************************/ |
285 | |
286 | dng_bad_pixel_list::dng_bad_pixel_list () |
287 | |
288 | : fBadPoints () |
289 | , fBadRects () |
290 | |
291 | { |
292 | |
293 | } |
294 | |
295 | /*****************************************************************************/ |
296 | |
297 | void dng_bad_pixel_list::AddPoint (const dng_point &pt) |
298 | { |
299 | |
300 | fBadPoints.push_back (pt); |
301 | |
302 | } |
303 | |
304 | /*****************************************************************************/ |
305 | |
306 | void dng_bad_pixel_list::AddRect (const dng_rect &r) |
307 | { |
308 | |
309 | fBadRects.push_back (r); |
310 | |
311 | } |
312 | |
313 | /*****************************************************************************/ |
314 | |
315 | static bool SortBadPoints (const dng_point &a, |
316 | const dng_point &b) |
317 | { |
318 | |
319 | if (a.v < b.v) |
320 | return true; |
321 | |
322 | if (a.v > b.v) |
323 | return false; |
324 | |
325 | return a.h < b.h; |
326 | |
327 | } |
328 | |
329 | /*****************************************************************************/ |
330 | |
331 | static bool SortBadRects (const dng_rect &a, |
332 | const dng_rect &b) |
333 | { |
334 | |
335 | if (a.t < b.t) |
336 | return true; |
337 | |
338 | if (a.t > b.t) |
339 | return false; |
340 | |
341 | if (a.l < b.l) |
342 | return true; |
343 | |
344 | if (a.l > b.l) |
345 | return false; |
346 | |
347 | if (a.b < b.b) |
348 | return true; |
349 | |
350 | if (a.b > b.b) |
351 | return false; |
352 | |
353 | return a.r < b.r; |
354 | |
355 | } |
356 | |
357 | /*****************************************************************************/ |
358 | |
359 | void dng_bad_pixel_list::Sort () |
360 | { |
361 | |
362 | if (PointCount () > 1) |
363 | { |
364 | |
365 | std::sort (fBadPoints.begin (), |
366 | fBadPoints.end (), |
367 | SortBadPoints); |
368 | |
369 | } |
370 | |
371 | if (RectCount () > 1) |
372 | { |
373 | |
374 | std::sort (fBadRects.begin (), |
375 | fBadRects.end (), |
376 | SortBadRects); |
377 | |
378 | } |
379 | |
380 | } |
381 | |
382 | /*****************************************************************************/ |
383 | |
384 | bool dng_bad_pixel_list::IsPointIsolated (uint32 index, |
385 | uint32 radius) const |
386 | { |
387 | |
388 | dng_point pt = Point (index); |
389 | |
390 | // Search backward through bad point list. |
391 | |
392 | for (int32 j = index - 1; j >= 0; j--) |
393 | { |
394 | |
395 | const dng_point &pt2 = Point (j); |
396 | |
397 | if (pt2.v < pt.v - (int32) radius) |
398 | { |
399 | break; |
400 | } |
401 | |
402 | if (Abs_int32 (pt2.h - pt.h) <= radius) |
403 | { |
404 | return false; |
405 | } |
406 | |
407 | } |
408 | |
409 | // Search forward through bad point list. |
410 | |
411 | for (uint32 k = index + 1; k < PointCount (); k++) |
412 | { |
413 | |
414 | const dng_point &pt2 = Point (k); |
415 | |
416 | if (pt2.v > pt.v + (int32) radius) |
417 | { |
418 | break; |
419 | } |
420 | |
421 | if (Abs_int32 (pt2.h - pt.h) <= radius) |
422 | { |
423 | return false; |
424 | } |
425 | |
426 | } |
427 | |
428 | // Search through bad rectangle list. |
429 | |
430 | dng_rect testRect (pt.v - radius, |
431 | pt.h - radius, |
432 | pt.v + radius + 1, |
433 | pt.h + radius + 1); |
434 | |
435 | for (uint32 n = 0; n < RectCount (); n++) |
436 | { |
437 | |
438 | if ((testRect & Rect (n)).NotEmpty ()) |
439 | { |
440 | return false; |
441 | } |
442 | |
443 | } |
444 | |
445 | // Did not find point anywhere, so bad pixel is isolated. |
446 | |
447 | return true; |
448 | |
449 | } |
450 | |
451 | /*****************************************************************************/ |
452 | |
453 | bool dng_bad_pixel_list::IsRectIsolated (uint32 index, |
454 | uint32 radius) const |
455 | { |
456 | |
457 | dng_rect testRect = Rect (index); |
458 | |
459 | testRect.t -= radius; |
460 | testRect.l -= radius; |
461 | testRect.b += radius; |
462 | testRect.r += radius; |
463 | |
464 | for (uint32 n = 0; n < RectCount (); n++) |
465 | { |
466 | |
467 | if (n != index) |
468 | { |
469 | |
470 | if ((testRect & Rect (n)).NotEmpty ()) |
471 | { |
472 | return false; |
473 | } |
474 | |
475 | } |
476 | |
477 | } |
478 | |
479 | return true; |
480 | |
481 | } |
482 | |
483 | /*****************************************************************************/ |
484 | |
485 | bool dng_bad_pixel_list::IsPointValid (const dng_point &pt, |
486 | const dng_rect &imageBounds, |
487 | uint32 index) const |
488 | { |
489 | |
490 | // The point must be in the image bounds to be valid. |
491 | |
492 | if (pt.v < imageBounds.t || |
493 | pt.h < imageBounds.l || |
494 | pt.v >= imageBounds.b || |
495 | pt.h >= imageBounds.r) |
496 | { |
497 | return false; |
498 | } |
499 | |
500 | // Only search the bad point list if we have a starting search index. |
501 | |
502 | if (index != kNoIndex) |
503 | { |
504 | |
505 | // Search backward through bad point list. |
506 | |
507 | for (int32 j = index - 1; j >= 0; j--) |
508 | { |
509 | |
510 | const dng_point &pt2 = Point (j); |
511 | |
512 | if (pt2.v < pt.v) |
513 | { |
514 | break; |
515 | } |
516 | |
517 | if (pt2 == pt) |
518 | { |
519 | return false; |
520 | } |
521 | |
522 | } |
523 | |
524 | // Search forward through bad point list. |
525 | |
526 | for (uint32 k = index + 1; k < PointCount (); k++) |
527 | { |
528 | |
529 | const dng_point &pt2 = Point (k); |
530 | |
531 | if (pt2.v > pt.v) |
532 | { |
533 | break; |
534 | } |
535 | |
536 | if (pt2 == pt) |
537 | { |
538 | return false; |
539 | } |
540 | |
541 | } |
542 | |
543 | } |
544 | |
545 | // Search through bad rectangle list. |
546 | |
547 | for (uint32 n = 0; n < RectCount (); n++) |
548 | { |
549 | |
550 | const dng_rect &r = Rect (n); |
551 | |
552 | if (pt.v >= r.t && |
553 | pt.h >= r.l && |
554 | pt.v < r.b && |
555 | pt.h < r.r) |
556 | { |
557 | return false; |
558 | } |
559 | |
560 | } |
561 | |
562 | // Did not find point anywhere, so pixel is valid. |
563 | |
564 | return true; |
565 | |
566 | } |
567 | |
568 | /*****************************************************************************/ |
569 | |
570 | dng_opcode_FixBadPixelsList::dng_opcode_FixBadPixelsList |
571 | (AutoPtr<dng_bad_pixel_list> &list, |
572 | uint32 bayerPhase) |
573 | |
574 | |
575 | : dng_filter_opcode (dngOpcode_FixBadPixelsList, |
576 | dngVersion_1_3_0_0, |
577 | 0) |
578 | |
579 | , fList () |
580 | |
581 | , fBayerPhase (bayerPhase) |
582 | |
583 | { |
584 | |
585 | fList.Reset (list.Release ()); |
586 | |
587 | fList->Sort (); |
588 | |
589 | } |
590 | |
591 | /*****************************************************************************/ |
592 | |
593 | dng_opcode_FixBadPixelsList::dng_opcode_FixBadPixelsList (dng_stream &stream) |
594 | |
595 | : dng_filter_opcode (dngOpcode_FixBadPixelsList, |
596 | stream, |
597 | "FixBadPixelsList" ) |
598 | |
599 | , fList () |
600 | |
601 | , fBayerPhase (0) |
602 | |
603 | { |
604 | |
605 | uint32 size = stream.Get_uint32 (); |
606 | |
607 | fBayerPhase = stream.Get_uint32 (); |
608 | |
609 | uint32 pCount = stream.Get_uint32 (); |
610 | uint32 rCount = stream.Get_uint32 (); |
611 | uint32 expectedSize = |
612 | SafeUint32Add(12, SafeUint32Add(SafeUint32Mult(pCount, 8), SafeUint32Mult(rCount, 16))); |
613 | if (size != expectedSize) |
614 | { |
615 | ThrowBadFormat (); |
616 | } |
617 | |
618 | fList.Reset (new dng_bad_pixel_list); |
619 | |
620 | uint32 index; |
621 | |
622 | for (index = 0; index < pCount; index++) |
623 | { |
624 | |
625 | dng_point pt; |
626 | |
627 | pt.v = stream.Get_int32 (); |
628 | pt.h = stream.Get_int32 (); |
629 | |
630 | fList->AddPoint (pt); |
631 | |
632 | } |
633 | |
634 | for (index = 0; index < rCount; index++) |
635 | { |
636 | |
637 | dng_rect r; |
638 | |
639 | r.t = stream.Get_int32 (); |
640 | r.l = stream.Get_int32 (); |
641 | r.b = stream.Get_int32 (); |
642 | r.r = stream.Get_int32 (); |
643 | |
644 | fList->AddRect (r); |
645 | |
646 | } |
647 | |
648 | fList->Sort (); |
649 | |
650 | #if qDNGValidate |
651 | |
652 | if (gVerbose) |
653 | { |
654 | |
655 | printf ("Bayer Phase: %u\n" , (unsigned) fBayerPhase); |
656 | |
657 | printf ("Bad Pixels: %u\n" , (unsigned) pCount); |
658 | |
659 | for (index = 0; index < pCount && index < gDumpLineLimit; index++) |
660 | { |
661 | printf (" Pixel [%u]: v=%d, h=%d\n" , |
662 | (unsigned) index, |
663 | (int) fList->Point (index).v, |
664 | (int) fList->Point (index).h); |
665 | } |
666 | |
667 | if (pCount > gDumpLineLimit) |
668 | { |
669 | printf (" ... %u bad pixels skipped\n" , (unsigned) (pCount - gDumpLineLimit)); |
670 | } |
671 | |
672 | printf ("Bad Rects: %u\n" , (unsigned) rCount); |
673 | |
674 | for (index = 0; index < rCount && index < gDumpLineLimit; index++) |
675 | { |
676 | printf (" Rect [%u]: t=%d, l=%d, b=%d, r=%d\n" , |
677 | (unsigned) index, |
678 | (int) fList->Rect (index).t, |
679 | (int) fList->Rect (index).l, |
680 | (int) fList->Rect (index).b, |
681 | (int) fList->Rect (index).r); |
682 | } |
683 | |
684 | if (rCount > gDumpLineLimit) |
685 | { |
686 | printf (" ... %u bad rects skipped\n" , (unsigned) (rCount - gDumpLineLimit)); |
687 | } |
688 | |
689 | } |
690 | |
691 | #endif |
692 | |
693 | } |
694 | |
695 | /*****************************************************************************/ |
696 | |
697 | void dng_opcode_FixBadPixelsList::PutData (dng_stream &stream) const |
698 | { |
699 | |
700 | uint32 pCount = fList->PointCount (); |
701 | uint32 rCount = fList->RectCount (); |
702 | |
703 | stream.Put_uint32 (12 + pCount * 8 + rCount * 16); |
704 | |
705 | stream.Put_uint32 (fBayerPhase); |
706 | |
707 | stream.Put_uint32 (pCount); |
708 | stream.Put_uint32 (rCount); |
709 | |
710 | uint32 index; |
711 | |
712 | for (index = 0; index < pCount; index++) |
713 | { |
714 | |
715 | const dng_point &pt (fList->Point (index)); |
716 | |
717 | stream.Put_int32 (pt.v); |
718 | stream.Put_int32 (pt.h); |
719 | |
720 | } |
721 | |
722 | for (index = 0; index < rCount; index++) |
723 | { |
724 | |
725 | const dng_rect &r (fList->Rect (index)); |
726 | |
727 | stream.Put_int32 (r.t); |
728 | stream.Put_int32 (r.l); |
729 | stream.Put_int32 (r.b); |
730 | stream.Put_int32 (r.r); |
731 | |
732 | } |
733 | |
734 | } |
735 | |
736 | /*****************************************************************************/ |
737 | |
738 | dng_rect dng_opcode_FixBadPixelsList::SrcArea (const dng_rect &dstArea, |
739 | const dng_rect & /* imageBounds */) |
740 | { |
741 | |
742 | int32 padding = 0; |
743 | |
744 | if (fList->PointCount ()) |
745 | { |
746 | padding += kBadPointPadding; |
747 | } |
748 | |
749 | if (fList->RectCount ()) |
750 | { |
751 | padding += kBadRectPadding; |
752 | } |
753 | |
754 | dng_rect srcArea = dstArea; |
755 | |
756 | srcArea.t -= padding; |
757 | srcArea.l -= padding; |
758 | |
759 | srcArea.b += padding; |
760 | srcArea.r += padding; |
761 | |
762 | return srcArea; |
763 | |
764 | } |
765 | |
766 | /*****************************************************************************/ |
767 | |
768 | dng_point dng_opcode_FixBadPixelsList::SrcRepeat () |
769 | { |
770 | |
771 | return dng_point (2, 2); |
772 | |
773 | } |
774 | |
775 | /*****************************************************************************/ |
776 | |
777 | void dng_opcode_FixBadPixelsList::Prepare (dng_negative & /* negative */, |
778 | uint32 /* threadCount */, |
779 | const dng_point & /* tileSize */, |
780 | const dng_rect & /* imageBounds */, |
781 | uint32 imagePlanes, |
782 | uint32 bufferPixelType, |
783 | dng_memory_allocator & /* allocator */) |
784 | { |
785 | |
786 | // This opcode is restricted to single channel images. |
787 | |
788 | if (imagePlanes != 1) |
789 | { |
790 | |
791 | ThrowBadFormat (); |
792 | |
793 | } |
794 | |
795 | // This opcode is restricted to 16-bit images. |
796 | |
797 | if (bufferPixelType != ttShort) |
798 | { |
799 | |
800 | ThrowBadFormat (); |
801 | |
802 | } |
803 | |
804 | } |
805 | |
806 | /*****************************************************************************/ |
807 | |
808 | void dng_opcode_FixBadPixelsList::FixIsolatedPixel (dng_pixel_buffer &buffer, |
809 | dng_point &badPoint) |
810 | { |
811 | |
812 | uint16 *p0 = buffer.DirtyPixel_uint16 (badPoint.v - 2, badPoint.h - 2, 0); |
813 | uint16 *p1 = buffer.DirtyPixel_uint16 (badPoint.v - 1, badPoint.h - 2, 0); |
814 | uint16 *p2 = buffer.DirtyPixel_uint16 (badPoint.v , badPoint.h - 2, 0); |
815 | uint16 *p3 = buffer.DirtyPixel_uint16 (badPoint.v + 1, badPoint.h - 2, 0); |
816 | uint16 *p4 = buffer.DirtyPixel_uint16 (badPoint.v + 2, badPoint.h - 2, 0); |
817 | |
818 | uint32 est0; |
819 | uint32 est1; |
820 | uint32 est2; |
821 | uint32 est3; |
822 | |
823 | uint32 grad0; |
824 | uint32 grad1; |
825 | uint32 grad2; |
826 | uint32 grad3; |
827 | |
828 | if (IsGreen (badPoint.v, badPoint.h)) // Green pixel |
829 | { |
830 | |
831 | // g00 b01 g02 b03 g04 |
832 | // r10 g11 r12 g13 r14 |
833 | // g20 b21 g22 b23 g24 |
834 | // r30 g31 r32 g33 r34 |
835 | // g40 b41 g42 b43 g44 |
836 | |
837 | int32 b01 = p0 [1]; |
838 | int32 g02 = p0 [2]; |
839 | int32 b03 = p0 [3]; |
840 | |
841 | int32 r10 = p1 [0]; |
842 | int32 g11 = p1 [1]; |
843 | int32 r12 = p1 [2]; |
844 | int32 g13 = p1 [3]; |
845 | int32 r14 = p1 [4]; |
846 | |
847 | int32 g20 = p2 [0]; |
848 | int32 b21 = p2 [1]; |
849 | int32 b23 = p2 [3]; |
850 | int32 g24 = p2 [4]; |
851 | |
852 | int32 r30 = p3 [0]; |
853 | int32 g31 = p3 [1]; |
854 | int32 r32 = p3 [2]; |
855 | int32 g33 = p3 [3]; |
856 | int32 r34 = p3 [4]; |
857 | |
858 | int32 b41 = p4 [1]; |
859 | int32 g42 = p4 [2]; |
860 | int32 b43 = p4 [3]; |
861 | |
862 | est0 = g02 + g42; |
863 | |
864 | grad0 = Abs_int32 (g02 - g42) + |
865 | Abs_int32 (g11 - g31) + |
866 | Abs_int32 (g13 - g33) + |
867 | Abs_int32 (b01 - b21) + |
868 | Abs_int32 (b03 - b23) + |
869 | Abs_int32 (b21 - b41) + |
870 | Abs_int32 (b23 - b43); |
871 | |
872 | est1 = g11 + g33; |
873 | |
874 | grad1 = Abs_int32 (g11 - g33) + |
875 | Abs_int32 (g02 - g24) + |
876 | Abs_int32 (g20 - g42) + |
877 | Abs_int32 (b01 - b23) + |
878 | Abs_int32 (r10 - r32) + |
879 | Abs_int32 (r12 - r34) + |
880 | Abs_int32 (b21 - b43); |
881 | |
882 | est2 = g20 + g24; |
883 | |
884 | grad2 = Abs_int32 (g20 - g24) + |
885 | Abs_int32 (g11 - g13) + |
886 | Abs_int32 (g31 - g33) + |
887 | Abs_int32 (r10 - r12) + |
888 | Abs_int32 (r30 - r32) + |
889 | Abs_int32 (r12 - r14) + |
890 | Abs_int32 (r32 - r34); |
891 | |
892 | est3 = g13 + g31; |
893 | |
894 | grad3 = Abs_int32 (g13 - g31) + |
895 | Abs_int32 (g02 - g20) + |
896 | Abs_int32 (g24 - g42) + |
897 | Abs_int32 (b03 - b21) + |
898 | Abs_int32 (r14 - r32) + |
899 | Abs_int32 (r12 - r30) + |
900 | Abs_int32 (b23 - b41); |
901 | |
902 | } |
903 | |
904 | else // Red/blue pixel |
905 | { |
906 | |
907 | // b00 g01 b02 g03 b04 |
908 | // g10 r11 g12 r13 g14 |
909 | // b20 g21 b22 g23 b24 |
910 | // g30 r31 g32 r33 g34 |
911 | // b40 g41 b42 g43 b44 |
912 | |
913 | int32 b00 = p0 [0]; |
914 | int32 g01 = p0 [1]; |
915 | int32 b02 = p0 [2]; |
916 | int32 g03 = p0 [3]; |
917 | int32 b04 = p0 [4]; |
918 | |
919 | int32 g10 = p1 [0]; |
920 | int32 r11 = p1 [1]; |
921 | int32 g12 = p1 [2]; |
922 | int32 r13 = p1 [3]; |
923 | int32 g14 = p1 [4]; |
924 | |
925 | int32 b20 = p2 [0]; |
926 | int32 g21 = p2 [1]; |
927 | int32 g23 = p2 [3]; |
928 | int32 b24 = p2 [4]; |
929 | |
930 | int32 g30 = p3 [0]; |
931 | int32 r31 = p3 [1]; |
932 | int32 g32 = p3 [2]; |
933 | int32 r33 = p3 [3]; |
934 | int32 g34 = p3 [4]; |
935 | |
936 | int32 b40 = p4 [0]; |
937 | int32 g41 = p4 [1]; |
938 | int32 b42 = p4 [2]; |
939 | int32 g43 = p4 [3]; |
940 | int32 b44 = p4 [4]; |
941 | |
942 | est0 = b02 + b42; |
943 | |
944 | grad0 = Abs_int32 (b02 - b42) + |
945 | Abs_int32 (g12 - g32) + |
946 | Abs_int32 (g01 - g21) + |
947 | Abs_int32 (g21 - g41) + |
948 | Abs_int32 (g03 - g23) + |
949 | Abs_int32 (g23 - g43) + |
950 | Abs_int32 (r11 - r31) + |
951 | Abs_int32 (r13 - r33); |
952 | |
953 | est1 = b00 + b44; |
954 | |
955 | grad1 = Abs_int32 (b00 - b44) + |
956 | Abs_int32 (r11 - r33) + |
957 | Abs_int32 (g01 - g23) + |
958 | Abs_int32 (g10 - g32) + |
959 | Abs_int32 (g12 - g34) + |
960 | Abs_int32 (g21 - g43) + |
961 | Abs_int32 (b02 - b24) + |
962 | Abs_int32 (b20 - b42); |
963 | |
964 | est2 = b20 + b24; |
965 | |
966 | grad2 = Abs_int32 (b20 - b24) + |
967 | Abs_int32 (g21 - g23) + |
968 | Abs_int32 (g10 - g12) + |
969 | Abs_int32 (g12 - g14) + |
970 | Abs_int32 (g30 - g32) + |
971 | Abs_int32 (g32 - g34) + |
972 | Abs_int32 (r11 - r13) + |
973 | Abs_int32 (r31 - r33); |
974 | |
975 | est3 = b04 + b40; |
976 | |
977 | grad3 = Abs_int32 (b04 - b40) + |
978 | Abs_int32 (r13 - r31) + |
979 | Abs_int32 (g03 - g21) + |
980 | Abs_int32 (g14 - g32) + |
981 | Abs_int32 (g12 - g30) + |
982 | Abs_int32 (g23 - g41) + |
983 | Abs_int32 (b02 - b20) + |
984 | Abs_int32 (b24 - b42); |
985 | |
986 | } |
987 | |
988 | uint32 minGrad = Min_uint32 (grad0, grad1); |
989 | |
990 | minGrad = Min_uint32 (minGrad, grad2); |
991 | minGrad = Min_uint32 (minGrad, grad3); |
992 | |
993 | uint32 limit = (minGrad * 3) >> 1; |
994 | |
995 | uint32 total = 0; |
996 | uint32 count = 0; |
997 | |
998 | if (grad0 <= limit) |
999 | { |
1000 | total += est0; |
1001 | count += 2; |
1002 | } |
1003 | |
1004 | if (grad1 <= limit) |
1005 | { |
1006 | total += est1; |
1007 | count += 2; |
1008 | } |
1009 | |
1010 | if (grad2 <= limit) |
1011 | { |
1012 | total += est2; |
1013 | count += 2; |
1014 | } |
1015 | |
1016 | if (grad3 <= limit) |
1017 | { |
1018 | total += est3; |
1019 | count += 2; |
1020 | } |
1021 | |
1022 | uint32 estimate = (total + (count >> 1)) / count; |
1023 | |
1024 | p2 [2] = (uint16) estimate; |
1025 | |
1026 | } |
1027 | |
1028 | /*****************************************************************************/ |
1029 | |
1030 | void dng_opcode_FixBadPixelsList::FixClusteredPixel (dng_pixel_buffer &buffer, |
1031 | uint32 pointIndex, |
1032 | const dng_rect &imageBounds) |
1033 | { |
1034 | |
1035 | const uint32 kNumSets = 3; |
1036 | const uint32 kSetSize = 4; |
1037 | |
1038 | static const int32 kOffset [kNumSets] [kSetSize] [2] = |
1039 | { |
1040 | { |
1041 | { -1, 1 }, |
1042 | { -1, -1 }, |
1043 | { 1, -1 }, |
1044 | { 1, 1 } |
1045 | }, |
1046 | { |
1047 | { -2, 0 }, |
1048 | { 2, 0 }, |
1049 | { 0, -2 }, |
1050 | { 0, 2 } |
1051 | }, |
1052 | { |
1053 | { -2, -2 }, |
1054 | { -2, 2 }, |
1055 | { 2, -2 }, |
1056 | { 2, 2 } |
1057 | } |
1058 | }; |
1059 | |
1060 | dng_point badPoint = fList->Point (pointIndex); |
1061 | |
1062 | bool isGreen = IsGreen (badPoint.v, badPoint.h); |
1063 | |
1064 | uint16 *p = buffer.DirtyPixel_uint16 (badPoint.v, badPoint.h, 0); |
1065 | |
1066 | for (uint32 set = 0; set < kNumSets; set++) |
1067 | { |
1068 | |
1069 | if (!isGreen && (kOffset [set] [0] [0] & 1) == 1) |
1070 | { |
1071 | continue; |
1072 | } |
1073 | |
1074 | uint32 total = 0; |
1075 | uint32 count = 0; |
1076 | |
1077 | for (uint32 entry = 0; entry < kSetSize; entry++) |
1078 | { |
1079 | |
1080 | dng_point offset (kOffset [set] [entry] [0], |
1081 | kOffset [set] [entry] [1]); |
1082 | |
1083 | if (fList->IsPointValid (badPoint + offset, |
1084 | imageBounds, |
1085 | pointIndex)) |
1086 | { |
1087 | |
1088 | total += p [offset.v * buffer.fRowStep + |
1089 | offset.h * buffer.fColStep]; |
1090 | |
1091 | count++; |
1092 | |
1093 | } |
1094 | |
1095 | } |
1096 | |
1097 | if (count) |
1098 | { |
1099 | |
1100 | uint32 estimate = (total + (count >> 1)) / count; |
1101 | |
1102 | p [0] = (uint16) estimate; |
1103 | |
1104 | return; |
1105 | |
1106 | } |
1107 | |
1108 | } |
1109 | |
1110 | // Unable to patch bad pixel. Leave pixel as is. |
1111 | |
1112 | #if qDNGValidate |
1113 | |
1114 | char s [256]; |
1115 | |
1116 | sprintf (s, "Unable to repair bad pixel, row %d, column %d" , |
1117 | (int) badPoint.v, |
1118 | (int) badPoint.h); |
1119 | |
1120 | ReportWarning (s); |
1121 | |
1122 | #endif |
1123 | |
1124 | } |
1125 | |
1126 | /*****************************************************************************/ |
1127 | |
1128 | void dng_opcode_FixBadPixelsList::FixSingleColumn (dng_pixel_buffer &buffer, |
1129 | const dng_rect &badRect) |
1130 | { |
1131 | |
1132 | int32 cs = buffer.fColStep; |
1133 | |
1134 | for (int32 row = badRect.t; row < badRect.b; row++) |
1135 | { |
1136 | |
1137 | uint16 *p0 = buffer.DirtyPixel_uint16 (row - 4, badRect.l - 4, 0); |
1138 | uint16 *p1 = buffer.DirtyPixel_uint16 (row - 3, badRect.l - 4, 0); |
1139 | uint16 *p2 = buffer.DirtyPixel_uint16 (row - 2, badRect.l - 4, 0); |
1140 | uint16 *p3 = buffer.DirtyPixel_uint16 (row - 1, badRect.l - 4, 0); |
1141 | uint16 *p4 = buffer.DirtyPixel_uint16 (row , badRect.l - 4, 0); |
1142 | uint16 *p5 = buffer.DirtyPixel_uint16 (row + 1, badRect.l - 4, 0); |
1143 | uint16 *p6 = buffer.DirtyPixel_uint16 (row + 2, badRect.l - 4, 0); |
1144 | uint16 *p7 = buffer.DirtyPixel_uint16 (row + 3, badRect.l - 4, 0); |
1145 | uint16 *p8 = buffer.DirtyPixel_uint16 (row + 4, badRect.l - 4, 0); |
1146 | |
1147 | uint32 est0; |
1148 | uint32 est1; |
1149 | uint32 est2; |
1150 | uint32 est3; |
1151 | uint32 est4; |
1152 | uint32 est5; |
1153 | uint32 est6; |
1154 | |
1155 | uint32 grad0; |
1156 | uint32 grad1; |
1157 | uint32 grad2; |
1158 | uint32 grad3; |
1159 | uint32 grad4; |
1160 | uint32 grad5; |
1161 | uint32 grad6; |
1162 | |
1163 | uint32 lower = 0; |
1164 | uint32 upper = 0x0FFFF; |
1165 | |
1166 | if (IsGreen (row, badRect.l)) // Green pixel |
1167 | { |
1168 | |
1169 | // g00 b01 g02 b03 g04 b05 g06 b07 g08 |
1170 | // r10 g11 r12 g13 r14 g15 r16 g17 r18 |
1171 | // g20 b21 g22 b23 g24 b25 g26 b27 g28 |
1172 | // r30 g31 r32 g33 r34 g35 r36 g37 r38 |
1173 | // g40 b41 g42 b43 g44 b45 g46 b47 g48 |
1174 | // r50 g51 r52 g53 r54 g55 r56 g57 r58 |
1175 | // g60 b61 g62 b63 g64 b65 g66 b67 g68 |
1176 | // r70 g71 r72 g73 r74 g75 r76 g77 r78 |
1177 | // g80 b81 g82 b83 g84 b85 g86 b87 g88 |
1178 | |
1179 | int32 b03 = p0 [3 * cs]; |
1180 | int32 b05 = p0 [5 * cs]; |
1181 | |
1182 | int32 g11 = p1 [1 * cs]; |
1183 | int32 g13 = p1 [3 * cs]; |
1184 | int32 g15 = p1 [5 * cs]; |
1185 | int32 g17 = p1 [7 * cs]; |
1186 | |
1187 | int32 g22 = p2 [2 * cs]; |
1188 | int32 b23 = p2 [3 * cs]; |
1189 | int32 b25 = p2 [5 * cs]; |
1190 | int32 g26 = p2 [6 * cs]; |
1191 | |
1192 | int32 r30 = p3 [0 * cs]; |
1193 | int32 g31 = p3 [1 * cs]; |
1194 | int32 r32 = p3 [2 * cs]; |
1195 | int32 g33 = p3 [3 * cs]; |
1196 | int32 g35 = p3 [5 * cs]; |
1197 | int32 r36 = p3 [6 * cs]; |
1198 | int32 g37 = p3 [7 * cs]; |
1199 | int32 r38 = p3 [8 * cs]; |
1200 | |
1201 | int32 g40 = p4 [0 * cs]; |
1202 | int32 g42 = p4 [2 * cs]; |
1203 | int32 b43 = p4 [3 * cs]; |
1204 | int32 b45 = p4 [5 * cs]; |
1205 | int32 g46 = p4 [6 * cs]; |
1206 | int32 g48 = p4 [8 * cs]; |
1207 | |
1208 | int32 r50 = p5 [0 * cs]; |
1209 | int32 g51 = p5 [1 * cs]; |
1210 | int32 r52 = p5 [2 * cs]; |
1211 | int32 g53 = p5 [3 * cs]; |
1212 | int32 g55 = p5 [5 * cs]; |
1213 | int32 r56 = p5 [6 * cs]; |
1214 | int32 g57 = p5 [7 * cs]; |
1215 | int32 r58 = p5 [8 * cs]; |
1216 | |
1217 | int32 g62 = p6 [2 * cs]; |
1218 | int32 b63 = p6 [3 * cs]; |
1219 | int32 b65 = p6 [5 * cs]; |
1220 | int32 g66 = p6 [6 * cs]; |
1221 | |
1222 | int32 g71 = p7 [1 * cs]; |
1223 | int32 g73 = p7 [3 * cs]; |
1224 | int32 g75 = p7 [5 * cs]; |
1225 | int32 g77 = p7 [7 * cs]; |
1226 | |
1227 | int32 b83 = p8 [3 * cs]; |
1228 | int32 b85 = p8 [5 * cs]; |
1229 | |
1230 | // In case there is some green split, make an estimate of |
1231 | // of the local difference between the greens, and adjust |
1232 | // the estimated green values for the difference |
1233 | // between the two types of green pixels when estimating |
1234 | // across green types. |
1235 | |
1236 | int32 split = ((g22 + g62 + g26 + g66) * 4 + |
1237 | (g42 + g46 ) * 8 - |
1238 | (g11 + g13 + g15 + g17) - |
1239 | (g31 + g33 + g35 + g37) * 3 - |
1240 | (g51 + g53 + g55 + g57) * 3 - |
1241 | (g71 + g73 + g75 + g77) + 16) >> 5; |
1242 | |
1243 | est0 = g13 + g75 + split * 2; |
1244 | |
1245 | grad0 = Abs_int32 (g13 - g75) + |
1246 | Abs_int32 (g15 - g46) + |
1247 | Abs_int32 (g22 - g53) + |
1248 | Abs_int32 (g35 - g66) + |
1249 | Abs_int32 (g42 - g73) + |
1250 | Abs_int32 (b03 - b65) + |
1251 | Abs_int32 (b23 - b85); |
1252 | |
1253 | est1 = g33 + g55 + split * 2; |
1254 | |
1255 | grad1 = Abs_int32 (g33 - g55) + |
1256 | Abs_int32 (g22 - g55) + |
1257 | Abs_int32 (g33 - g66) + |
1258 | Abs_int32 (g13 - g35) + |
1259 | Abs_int32 (g53 - g75) + |
1260 | Abs_int32 (b23 - b45) + |
1261 | Abs_int32 (b43 - b65); |
1262 | |
1263 | est2 = g31 + g57 + split * 2; |
1264 | |
1265 | grad2 = Abs_int32 (g31 - g57) + |
1266 | Abs_int32 (g33 - g46) + |
1267 | Abs_int32 (g35 - g48) + |
1268 | Abs_int32 (g40 - g53) + |
1269 | Abs_int32 (g42 - g55) + |
1270 | Abs_int32 (r30 - r56) + |
1271 | Abs_int32 (r32 - r58); |
1272 | |
1273 | est3 = g42 + g46; |
1274 | |
1275 | grad3 = Abs_int32 (g42 - g46) * 2 + |
1276 | Abs_int32 (g33 - g35) + |
1277 | Abs_int32 (g53 - g55) + |
1278 | Abs_int32 (b23 - b25) + |
1279 | Abs_int32 (b43 - b45) + |
1280 | Abs_int32 (b63 - b65); |
1281 | |
1282 | est4 = g37 + g51 + split * 2; |
1283 | |
1284 | grad4 = Abs_int32 (g37 - g51) + |
1285 | Abs_int32 (g35 - g42) + |
1286 | Abs_int32 (g33 - g40) + |
1287 | Abs_int32 (g48 - g55) + |
1288 | Abs_int32 (g46 - g53) + |
1289 | Abs_int32 (r38 - r52) + |
1290 | Abs_int32 (r36 - r50); |
1291 | |
1292 | est5 = g35 + g53 + split * 2; |
1293 | |
1294 | grad5 = Abs_int32 (g35 - g53) + |
1295 | Abs_int32 (g26 - g53) + |
1296 | Abs_int32 (g35 - g62) + |
1297 | Abs_int32 (g15 - g33) + |
1298 | Abs_int32 (g55 - g73) + |
1299 | Abs_int32 (b25 - b43) + |
1300 | Abs_int32 (b45 - b63); |
1301 | |
1302 | est6 = g15 + g73 + split * 2; |
1303 | |
1304 | grad6 = Abs_int32 (g15 - g73) + |
1305 | Abs_int32 (g13 - g42) + |
1306 | Abs_int32 (g26 - g55) + |
1307 | Abs_int32 (g33 - g62) + |
1308 | Abs_int32 (g46 - g75) + |
1309 | Abs_int32 (b05 - b63) + |
1310 | Abs_int32 (b25 - b83); |
1311 | |
1312 | lower = Min_uint32 (Min_uint32 (g33, g35), |
1313 | Min_uint32 (g53, g55)); |
1314 | |
1315 | upper = Max_uint32 (Max_uint32 (g33, g35), |
1316 | Max_uint32 (g53, g55)); |
1317 | |
1318 | lower = Pin_int32 (0, lower + split, 65535); |
1319 | upper = Pin_int32 (0, upper + split, 65535); |
1320 | |
1321 | } |
1322 | |
1323 | else // Red/blue pixel |
1324 | { |
1325 | |
1326 | // b00 g01 b02 g03 b04 g05 b06 g07 b08 |
1327 | // g10 r11 g12 r13 g14 r15 g16 r17 g18 |
1328 | // b20 g21 b22 g23 b24 g25 b26 g27 b28 |
1329 | // g30 r31 g32 r33 g34 r35 g36 r37 g38 |
1330 | // b40 g41 b42 g43 b44 g45 b46 g47 b48 |
1331 | // g50 r51 g52 r53 g54 r55 g56 r57 g58 |
1332 | // b60 g61 b62 g63 b64 g65 b66 g67 b68 |
1333 | // g70 r71 g72 r73 g74 r75 g76 r77 g78 |
1334 | // b80 g81 b82 g83 b84 g85 b86 g87 b88 |
1335 | |
1336 | int32 b02 = p0 [2 * cs]; |
1337 | int32 g03 = p0 [3 * cs]; |
1338 | int32 g05 = p0 [5 * cs]; |
1339 | int32 b06 = p0 [6 * cs]; |
1340 | |
1341 | int32 r13 = p1 [3 * cs]; |
1342 | int32 r15 = p1 [5 * cs]; |
1343 | |
1344 | int32 b20 = p2 [0 * cs]; |
1345 | int32 b22 = p2 [2 * cs]; |
1346 | int32 g23 = p2 [3 * cs]; |
1347 | int32 g25 = p2 [5 * cs]; |
1348 | int32 b26 = p2 [6 * cs]; |
1349 | int32 b28 = p2 [8 * cs]; |
1350 | |
1351 | int32 r31 = p3 [1 * cs]; |
1352 | int32 g32 = p3 [2 * cs]; |
1353 | int32 r33 = p3 [3 * cs]; |
1354 | int32 r35 = p3 [5 * cs]; |
1355 | int32 g36 = p3 [6 * cs]; |
1356 | int32 r37 = p3 [7 * cs]; |
1357 | |
1358 | int32 g41 = p4 [1 * cs]; |
1359 | int32 b42 = p4 [2 * cs]; |
1360 | int32 g43 = p4 [3 * cs]; |
1361 | int32 g45 = p4 [5 * cs]; |
1362 | int32 b46 = p4 [6 * cs]; |
1363 | int32 g47 = p4 [7 * cs]; |
1364 | |
1365 | int32 r51 = p5 [1 * cs]; |
1366 | int32 g52 = p5 [2 * cs]; |
1367 | int32 r53 = p5 [3 * cs]; |
1368 | int32 r55 = p5 [5 * cs]; |
1369 | int32 g56 = p5 [6 * cs]; |
1370 | int32 r57 = p5 [7 * cs]; |
1371 | |
1372 | int32 b60 = p6 [0 * cs]; |
1373 | int32 b62 = p6 [2 * cs]; |
1374 | int32 g63 = p6 [3 * cs]; |
1375 | int32 g65 = p6 [5 * cs]; |
1376 | int32 b66 = p6 [6 * cs]; |
1377 | int32 b68 = p6 [8 * cs]; |
1378 | |
1379 | int32 r73 = p7 [3 * cs]; |
1380 | int32 r75 = p7 [5 * cs]; |
1381 | |
1382 | int32 b82 = p8 [2 * cs]; |
1383 | int32 g83 = p8 [3 * cs]; |
1384 | int32 g85 = p8 [5 * cs]; |
1385 | int32 b86 = p8 [6 * cs]; |
1386 | |
1387 | est0 = b02 + b86; |
1388 | |
1389 | grad0 = Abs_int32 (b02 - b86) + |
1390 | Abs_int32 (r13 - r55) + |
1391 | Abs_int32 (r33 - r75) + |
1392 | Abs_int32 (g03 - g45) + |
1393 | Abs_int32 (g23 - g65) + |
1394 | Abs_int32 (g43 - g85); |
1395 | |
1396 | est1 = b22 + b66; |
1397 | |
1398 | grad1 = Abs_int32 (b22 - b66) + |
1399 | Abs_int32 (r13 - r35) + |
1400 | Abs_int32 (r33 - r55) + |
1401 | Abs_int32 (r53 - r75) + |
1402 | Abs_int32 (g23 - g45) + |
1403 | Abs_int32 (g43 - g65); |
1404 | |
1405 | est2 = b20 + b68; |
1406 | |
1407 | grad2 = Abs_int32 (b20 - b68) + |
1408 | Abs_int32 (r31 - r55) + |
1409 | Abs_int32 (r33 - r57) + |
1410 | Abs_int32 (g23 - g47) + |
1411 | Abs_int32 (g32 - g56) + |
1412 | Abs_int32 (g41 - g65); |
1413 | |
1414 | est3 = b42 + b46; |
1415 | |
1416 | grad3 = Abs_int32 (b42 - b46) + |
1417 | Abs_int32 (r33 - r35) + |
1418 | Abs_int32 (r53 - r55) + |
1419 | Abs_int32 (g32 - g36) + |
1420 | Abs_int32 (g43 - g43) + |
1421 | Abs_int32 (g52 - g56); |
1422 | |
1423 | est4 = b28 + b60; |
1424 | |
1425 | grad4 = Abs_int32 (b28 - b60) + |
1426 | Abs_int32 (r37 - r53) + |
1427 | Abs_int32 (r35 - r51) + |
1428 | Abs_int32 (g25 - g41) + |
1429 | Abs_int32 (g36 - g52) + |
1430 | Abs_int32 (g47 - g63); |
1431 | |
1432 | est5 = b26 + b62; |
1433 | |
1434 | grad5 = Abs_int32 (b26 - b62) + |
1435 | Abs_int32 (r15 - r33) + |
1436 | Abs_int32 (r35 - r53) + |
1437 | Abs_int32 (r55 - r73) + |
1438 | Abs_int32 (g25 - g43) + |
1439 | Abs_int32 (g45 - g63); |
1440 | |
1441 | est6 = b06 + b82; |
1442 | |
1443 | grad6 = Abs_int32 (b06 - b82) + |
1444 | Abs_int32 (r15 - r53) + |
1445 | Abs_int32 (r35 - r73) + |
1446 | Abs_int32 (g05 - g43) + |
1447 | Abs_int32 (g25 - g63) + |
1448 | Abs_int32 (g45 - g83); |
1449 | |
1450 | lower = Min_uint32 (b42, b46); |
1451 | upper = Max_uint32 (b42, b46); |
1452 | |
1453 | } |
1454 | |
1455 | uint32 minGrad = Min_uint32 (grad0, grad1); |
1456 | |
1457 | minGrad = Min_uint32 (minGrad, grad2); |
1458 | minGrad = Min_uint32 (minGrad, grad3); |
1459 | minGrad = Min_uint32 (minGrad, grad4); |
1460 | minGrad = Min_uint32 (minGrad, grad5); |
1461 | minGrad = Min_uint32 (minGrad, grad6); |
1462 | |
1463 | uint32 limit = (minGrad * 3) >> 1; |
1464 | |
1465 | uint32 total = 0; |
1466 | uint32 count = 0; |
1467 | |
1468 | if (grad0 <= limit) |
1469 | { |
1470 | total += est0; |
1471 | count += 2; |
1472 | } |
1473 | |
1474 | if (grad1 <= limit) |
1475 | { |
1476 | total += est1; |
1477 | count += 2; |
1478 | } |
1479 | |
1480 | if (grad2 <= limit) |
1481 | { |
1482 | total += est2; |
1483 | count += 2; |
1484 | } |
1485 | |
1486 | if (grad3 <= limit) |
1487 | { |
1488 | total += est3; |
1489 | count += 2; |
1490 | } |
1491 | |
1492 | if (grad4 <= limit) |
1493 | { |
1494 | total += est4; |
1495 | count += 2; |
1496 | } |
1497 | |
1498 | if (grad5 <= limit) |
1499 | { |
1500 | total += est5; |
1501 | count += 2; |
1502 | } |
1503 | |
1504 | if (grad6 <= limit) |
1505 | { |
1506 | total += est6; |
1507 | count += 2; |
1508 | } |
1509 | |
1510 | uint32 estimate = (total + (count >> 1)) / count; |
1511 | |
1512 | p4 [4] = (uint16) Pin_uint32 (lower, estimate, upper); |
1513 | |
1514 | } |
1515 | |
1516 | } |
1517 | |
1518 | /*****************************************************************************/ |
1519 | |
1520 | void dng_opcode_FixBadPixelsList::FixSingleRow (dng_pixel_buffer &buffer, |
1521 | const dng_rect &badRect) |
1522 | { |
1523 | |
1524 | dng_pixel_buffer tBuffer = buffer; |
1525 | |
1526 | tBuffer.fArea = Transpose (buffer.fArea); |
1527 | |
1528 | tBuffer.fRowStep = buffer.fColStep; |
1529 | tBuffer.fColStep = buffer.fRowStep; |
1530 | |
1531 | dng_rect tBadRect = Transpose (badRect); |
1532 | |
1533 | FixSingleColumn (tBuffer, tBadRect); |
1534 | |
1535 | } |
1536 | |
1537 | /*****************************************************************************/ |
1538 | |
1539 | void dng_opcode_FixBadPixelsList::FixClusteredRect (dng_pixel_buffer &buffer, |
1540 | const dng_rect &badRect, |
1541 | const dng_rect &imageBounds) |
1542 | { |
1543 | |
1544 | const uint32 kNumSets = 8; |
1545 | const uint32 kSetSize = 8; |
1546 | |
1547 | static const int32 kOffset [kNumSets] [kSetSize] [2] = |
1548 | { |
1549 | { |
1550 | { -1, 1 }, |
1551 | { -1, -1 }, |
1552 | { 1, -1 }, |
1553 | { 1, 1 }, |
1554 | { 0, 0 }, |
1555 | { 0, 0 }, |
1556 | { 0, 0 }, |
1557 | { 0, 0 } |
1558 | }, |
1559 | { |
1560 | { -2, 0 }, |
1561 | { 2, 0 }, |
1562 | { 0, -2 }, |
1563 | { 0, 2 }, |
1564 | { 0, 0 }, |
1565 | { 0, 0 }, |
1566 | { 0, 0 }, |
1567 | { 0, 0 } |
1568 | }, |
1569 | { |
1570 | { -2, -2 }, |
1571 | { -2, 2 }, |
1572 | { 2, -2 }, |
1573 | { 2, 2 }, |
1574 | { 0, 0 }, |
1575 | { 0, 0 }, |
1576 | { 0, 0 }, |
1577 | { 0, 0 } |
1578 | }, |
1579 | { |
1580 | { -1, -3 }, |
1581 | { -3, -1 }, |
1582 | { 1, -3 }, |
1583 | { 3, -1 }, |
1584 | { -1, 3 }, |
1585 | { -3, 1 }, |
1586 | { 1, 3 }, |
1587 | { 3, 1 } |
1588 | }, |
1589 | { |
1590 | { -4, 0 }, |
1591 | { 4, 0 }, |
1592 | { 0, -4 }, |
1593 | { 0, 4 }, |
1594 | { 0, 0 }, |
1595 | { 0, 0 }, |
1596 | { 0, 0 }, |
1597 | { 0, 0 } |
1598 | }, |
1599 | { |
1600 | { -3, -3 }, |
1601 | { -3, 3 }, |
1602 | { 3, -3 }, |
1603 | { 3, 3 }, |
1604 | { 0, 0 }, |
1605 | { 0, 0 }, |
1606 | { 0, 0 }, |
1607 | { 0, 0 } |
1608 | }, |
1609 | { |
1610 | { -2, -4 }, |
1611 | { -4, -2 }, |
1612 | { 2, -4 }, |
1613 | { 4, -2 }, |
1614 | { -2, 4 }, |
1615 | { -4, 2 }, |
1616 | { 2, 4 }, |
1617 | { 4, 2 } |
1618 | }, |
1619 | { |
1620 | { -4, -4 }, |
1621 | { -4, 4 }, |
1622 | { 4, -4 }, |
1623 | { 4, 4 }, |
1624 | { 0, 0 }, |
1625 | { 0, 0 }, |
1626 | { 0, 0 }, |
1627 | { 0, 0 } |
1628 | } |
1629 | }; |
1630 | |
1631 | bool didFail = false; |
1632 | |
1633 | for (int32 row = badRect.t; row < badRect.b; row++) |
1634 | { |
1635 | |
1636 | for (int32 col = badRect.l; col < badRect.r; col++) |
1637 | { |
1638 | |
1639 | uint16 *p = buffer.DirtyPixel_uint16 (row, col, 0); |
1640 | |
1641 | bool isGreen = IsGreen (row, col); |
1642 | |
1643 | bool didFixPixel = false; |
1644 | |
1645 | for (uint32 set = 0; set < kNumSets && !didFixPixel; set++) |
1646 | { |
1647 | |
1648 | if (!isGreen && (kOffset [set] [0] [0] & 1) == 1) |
1649 | { |
1650 | continue; |
1651 | } |
1652 | |
1653 | uint32 total = 0; |
1654 | uint32 count = 0; |
1655 | |
1656 | for (uint32 entry = 0; entry < kSetSize; entry++) |
1657 | { |
1658 | |
1659 | dng_point offset (kOffset [set] [entry] [0], |
1660 | kOffset [set] [entry] [1]); |
1661 | |
1662 | if (offset.v == 0 && |
1663 | offset.h == 0) |
1664 | { |
1665 | break; |
1666 | } |
1667 | |
1668 | if (fList->IsPointValid (dng_point (row, col) + offset, |
1669 | imageBounds)) |
1670 | { |
1671 | |
1672 | total += p [offset.v * buffer.fRowStep + |
1673 | offset.h * buffer.fColStep]; |
1674 | |
1675 | count++; |
1676 | |
1677 | } |
1678 | |
1679 | } |
1680 | |
1681 | if (count) |
1682 | { |
1683 | |
1684 | uint32 estimate = (total + (count >> 1)) / count; |
1685 | |
1686 | p [0] = (uint16) estimate; |
1687 | |
1688 | didFixPixel = true; |
1689 | |
1690 | } |
1691 | |
1692 | } |
1693 | |
1694 | if (!didFixPixel) |
1695 | { |
1696 | |
1697 | didFail = true; |
1698 | |
1699 | } |
1700 | |
1701 | } |
1702 | |
1703 | } |
1704 | |
1705 | #if qDNGValidate |
1706 | |
1707 | if (didFail) |
1708 | { |
1709 | |
1710 | ReportWarning ("Unable to repair bad rectangle" ); |
1711 | |
1712 | } |
1713 | |
1714 | #endif |
1715 | |
1716 | } |
1717 | |
1718 | /*****************************************************************************/ |
1719 | |
1720 | void dng_opcode_FixBadPixelsList::ProcessArea (dng_negative & /* negative */, |
1721 | uint32 /* threadIndex */, |
1722 | dng_pixel_buffer &srcBuffer, |
1723 | dng_pixel_buffer &dstBuffer, |
1724 | const dng_rect &dstArea, |
1725 | const dng_rect &imageBounds) |
1726 | { |
1727 | |
1728 | uint32 pointCount = fList->PointCount (); |
1729 | uint32 rectCount = fList->RectCount (); |
1730 | |
1731 | dng_rect fixArea = dstArea; |
1732 | |
1733 | if (rectCount) |
1734 | { |
1735 | fixArea.t -= kBadRectPadding; |
1736 | fixArea.l -= kBadRectPadding; |
1737 | fixArea.b += kBadRectPadding; |
1738 | fixArea.r += kBadRectPadding; |
1739 | } |
1740 | |
1741 | bool didFixPoint = false; |
1742 | |
1743 | if (pointCount) |
1744 | { |
1745 | |
1746 | for (uint32 pointIndex = 0; pointIndex < pointCount; pointIndex++) |
1747 | { |
1748 | |
1749 | dng_point badPoint = fList->Point (pointIndex); |
1750 | |
1751 | if (badPoint.v >= fixArea.t && |
1752 | badPoint.h >= fixArea.l && |
1753 | badPoint.v < fixArea.b && |
1754 | badPoint.h < fixArea.r) |
1755 | { |
1756 | |
1757 | bool isIsolated = fList->IsPointIsolated (pointIndex, |
1758 | kBadPointPadding); |
1759 | |
1760 | if (isIsolated && |
1761 | badPoint.v >= imageBounds.t + kBadPointPadding && |
1762 | badPoint.h >= imageBounds.l + kBadPointPadding && |
1763 | badPoint.v < imageBounds.b - kBadPointPadding && |
1764 | badPoint.h < imageBounds.r - kBadPointPadding) |
1765 | { |
1766 | |
1767 | FixIsolatedPixel (srcBuffer, |
1768 | badPoint); |
1769 | |
1770 | } |
1771 | |
1772 | else |
1773 | { |
1774 | |
1775 | FixClusteredPixel (srcBuffer, |
1776 | pointIndex, |
1777 | imageBounds); |
1778 | |
1779 | } |
1780 | |
1781 | didFixPoint = true; |
1782 | |
1783 | } |
1784 | |
1785 | } |
1786 | |
1787 | } |
1788 | |
1789 | if (rectCount) |
1790 | { |
1791 | |
1792 | if (didFixPoint) |
1793 | { |
1794 | |
1795 | srcBuffer.RepeatSubArea (imageBounds, |
1796 | SrcRepeat ().v, |
1797 | SrcRepeat ().h); |
1798 | |
1799 | } |
1800 | |
1801 | for (uint32 rectIndex = 0; rectIndex < rectCount; rectIndex++) |
1802 | { |
1803 | |
1804 | dng_rect badRect = fList->Rect (rectIndex); |
1805 | |
1806 | dng_rect overlap = dstArea & badRect; |
1807 | |
1808 | if (overlap.NotEmpty ()) |
1809 | { |
1810 | |
1811 | bool isIsolated = fList->IsRectIsolated (rectIndex, |
1812 | kBadRectPadding); |
1813 | |
1814 | if (isIsolated && |
1815 | badRect.r == badRect.l + 1 && |
1816 | badRect.l >= imageBounds.l + SrcRepeat ().h && |
1817 | badRect.r <= imageBounds.r - SrcRepeat ().v) |
1818 | { |
1819 | |
1820 | FixSingleColumn (srcBuffer, |
1821 | overlap); |
1822 | |
1823 | } |
1824 | |
1825 | else if (isIsolated && |
1826 | badRect.b == badRect.t + 1 && |
1827 | badRect.t >= imageBounds.t + SrcRepeat ().h && |
1828 | badRect.b <= imageBounds.b - SrcRepeat ().v) |
1829 | { |
1830 | |
1831 | FixSingleRow (srcBuffer, |
1832 | overlap); |
1833 | |
1834 | } |
1835 | |
1836 | else |
1837 | { |
1838 | |
1839 | FixClusteredRect (srcBuffer, |
1840 | overlap, |
1841 | imageBounds); |
1842 | |
1843 | } |
1844 | |
1845 | } |
1846 | |
1847 | } |
1848 | |
1849 | } |
1850 | |
1851 | dstBuffer.CopyArea (srcBuffer, |
1852 | dstArea, |
1853 | 0, |
1854 | dstBuffer.fPlanes); |
1855 | |
1856 | } |
1857 | |
1858 | /*****************************************************************************/ |
1859 | |