You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1859 lines
36 KiB
1859 lines
36 KiB
/*****************************************************************************/
|
|
// Copyright 2008 Adobe Systems Incorporated
|
|
// All Rights Reserved.
|
|
//
|
|
// NOTICE: Adobe permits you to use, modify, and distribute this file in
|
|
// accordance with the terms of the Adobe license agreement accompanying it.
|
|
/*****************************************************************************/
|
|
|
|
/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_bad_pixels.cpp#1 $ */
|
|
/* $DateTime: 2012/05/30 13:28:51 $ */
|
|
/* $Change: 832332 $ */
|
|
/* $Author: tknoll $ */
|
|
|
|
/*****************************************************************************/
|
|
|
|
#include "dng_bad_pixels.h"
|
|
|
|
#include "dng_filter_task.h"
|
|
#include "dng_globals.h"
|
|
#include "dng_host.h"
|
|
#include "dng_image.h"
|
|
#include "dng_negative.h"
|
|
#include "dng_safe_arithmetic.h"
|
|
|
|
#include <algorithm>
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_opcode_FixBadPixelsConstant::dng_opcode_FixBadPixelsConstant
|
|
(uint32 constant,
|
|
uint32 bayerPhase)
|
|
|
|
: dng_filter_opcode (dngOpcode_FixBadPixelsConstant,
|
|
dngVersion_1_3_0_0,
|
|
0)
|
|
|
|
, fConstant (constant)
|
|
, fBayerPhase (bayerPhase)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_opcode_FixBadPixelsConstant::dng_opcode_FixBadPixelsConstant
|
|
(dng_stream &stream)
|
|
|
|
: dng_filter_opcode (dngOpcode_FixBadPixelsConstant,
|
|
stream,
|
|
"FixBadPixelsConstant")
|
|
|
|
, fConstant (0)
|
|
, fBayerPhase (0)
|
|
|
|
{
|
|
|
|
if (stream.Get_uint32 () != 8)
|
|
{
|
|
ThrowBadFormat ();
|
|
}
|
|
|
|
fConstant = stream.Get_uint32 ();
|
|
fBayerPhase = stream.Get_uint32 ();
|
|
|
|
#if qDNGValidate
|
|
|
|
if (gVerbose)
|
|
{
|
|
|
|
printf ("Constant: %u\n", (unsigned) fConstant);
|
|
|
|
printf ("Bayer Phase: %u\n", (unsigned) fBayerPhase);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_opcode_FixBadPixelsConstant::PutData (dng_stream &stream) const
|
|
{
|
|
|
|
stream.Put_uint32 (8);
|
|
|
|
stream.Put_uint32 (fConstant );
|
|
stream.Put_uint32 (fBayerPhase);
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_point dng_opcode_FixBadPixelsConstant::SrcRepeat ()
|
|
{
|
|
|
|
return dng_point (2, 2);
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_rect dng_opcode_FixBadPixelsConstant::SrcArea (const dng_rect &dstArea,
|
|
const dng_rect & /* imageBounds */)
|
|
{
|
|
|
|
dng_rect srcArea = dstArea;
|
|
|
|
srcArea.t -= 2;
|
|
srcArea.l -= 2;
|
|
|
|
srcArea.b += 2;
|
|
srcArea.r += 2;
|
|
|
|
return srcArea;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_opcode_FixBadPixelsConstant::Prepare (dng_negative & /* negative */,
|
|
uint32 /* threadCount */,
|
|
const dng_point & /* tileSize */,
|
|
const dng_rect & /* imageBounds */,
|
|
uint32 imagePlanes,
|
|
uint32 bufferPixelType,
|
|
dng_memory_allocator & /* allocator */)
|
|
{
|
|
|
|
// This opcode is restricted to single channel images.
|
|
|
|
if (imagePlanes != 1)
|
|
{
|
|
|
|
ThrowBadFormat ();
|
|
|
|
}
|
|
|
|
// This opcode is restricted to 16-bit images.
|
|
|
|
if (bufferPixelType != ttShort)
|
|
{
|
|
|
|
ThrowBadFormat ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_opcode_FixBadPixelsConstant::ProcessArea (dng_negative & /* negative */,
|
|
uint32 /* threadIndex */,
|
|
dng_pixel_buffer &srcBuffer,
|
|
dng_pixel_buffer &dstBuffer,
|
|
const dng_rect &dstArea,
|
|
const dng_rect & /* imageBounds */)
|
|
{
|
|
|
|
dstBuffer.CopyArea (srcBuffer,
|
|
dstArea,
|
|
0,
|
|
dstBuffer.fPlanes);
|
|
|
|
uint16 badPixel = (uint16) fConstant;
|
|
|
|
for (int32 dstRow = dstArea.t; dstRow < dstArea.b; dstRow++)
|
|
{
|
|
|
|
const uint16 *sPtr = srcBuffer.ConstPixel_uint16 (dstRow, dstArea.l, 0);
|
|
uint16 *dPtr = dstBuffer.DirtyPixel_uint16 (dstRow, dstArea.l, 0);
|
|
|
|
for (int32 dstCol = dstArea.l; dstCol < dstArea.r; dstCol++)
|
|
{
|
|
|
|
if (*sPtr == badPixel)
|
|
{
|
|
|
|
uint32 count = 0;
|
|
uint32 total = 0;
|
|
|
|
uint16 value;
|
|
|
|
if (IsGreen (dstRow, dstCol)) // Green pixel
|
|
{
|
|
|
|
value = sPtr [-srcBuffer.fRowStep - 1];
|
|
|
|
if (value != badPixel)
|
|
{
|
|
count += 1;
|
|
total += value;
|
|
}
|
|
|
|
value = sPtr [-srcBuffer.fRowStep + 1];
|
|
|
|
if (value != badPixel)
|
|
{
|
|
count += 1;
|
|
total += value;
|
|
}
|
|
|
|
value = sPtr [srcBuffer.fRowStep - 1];
|
|
|
|
if (value != badPixel)
|
|
{
|
|
count += 1;
|
|
total += value;
|
|
}
|
|
|
|
value = sPtr [srcBuffer.fRowStep + 1];
|
|
|
|
if (value != badPixel)
|
|
{
|
|
count += 1;
|
|
total += value;
|
|
}
|
|
|
|
}
|
|
|
|
else // Red/blue pixel.
|
|
{
|
|
|
|
value = sPtr [-srcBuffer.fRowStep * 2];
|
|
|
|
if (value != badPixel)
|
|
{
|
|
count += 1;
|
|
total += value;
|
|
}
|
|
|
|
value = sPtr [srcBuffer.fRowStep * 2];
|
|
|
|
if (value != badPixel)
|
|
{
|
|
count += 1;
|
|
total += value;
|
|
}
|
|
|
|
value = sPtr [-2];
|
|
|
|
if (value != badPixel)
|
|
{
|
|
count += 1;
|
|
total += value;
|
|
}
|
|
|
|
value = sPtr [2];
|
|
|
|
if (value != badPixel)
|
|
{
|
|
count += 1;
|
|
total += value;
|
|
}
|
|
|
|
}
|
|
|
|
if (count == 4) // Most common case.
|
|
{
|
|
|
|
*dPtr = (uint16) ((total + 2) >> 2);
|
|
|
|
}
|
|
|
|
else if (count > 0)
|
|
{
|
|
|
|
*dPtr = (uint16) ((total + (count >> 1)) / count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sPtr++;
|
|
dPtr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_bad_pixel_list::dng_bad_pixel_list ()
|
|
|
|
: fBadPoints ()
|
|
, fBadRects ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_bad_pixel_list::AddPoint (const dng_point &pt)
|
|
{
|
|
|
|
fBadPoints.push_back (pt);
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_bad_pixel_list::AddRect (const dng_rect &r)
|
|
{
|
|
|
|
fBadRects.push_back (r);
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static bool SortBadPoints (const dng_point &a,
|
|
const dng_point &b)
|
|
{
|
|
|
|
if (a.v < b.v)
|
|
return true;
|
|
|
|
if (a.v > b.v)
|
|
return false;
|
|
|
|
return a.h < b.h;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static bool SortBadRects (const dng_rect &a,
|
|
const dng_rect &b)
|
|
{
|
|
|
|
if (a.t < b.t)
|
|
return true;
|
|
|
|
if (a.t > b.t)
|
|
return false;
|
|
|
|
if (a.l < b.l)
|
|
return true;
|
|
|
|
if (a.l > b.l)
|
|
return false;
|
|
|
|
if (a.b < b.b)
|
|
return true;
|
|
|
|
if (a.b > b.b)
|
|
return false;
|
|
|
|
return a.r < b.r;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_bad_pixel_list::Sort ()
|
|
{
|
|
|
|
if (PointCount () > 1)
|
|
{
|
|
|
|
std::sort (fBadPoints.begin (),
|
|
fBadPoints.end (),
|
|
SortBadPoints);
|
|
|
|
}
|
|
|
|
if (RectCount () > 1)
|
|
{
|
|
|
|
std::sort (fBadRects.begin (),
|
|
fBadRects.end (),
|
|
SortBadRects);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
bool dng_bad_pixel_list::IsPointIsolated (uint32 index,
|
|
uint32 radius) const
|
|
{
|
|
|
|
dng_point pt = Point (index);
|
|
|
|
// Search backward through bad point list.
|
|
|
|
for (int32 j = index - 1; j >= 0; j--)
|
|
{
|
|
|
|
const dng_point &pt2 = Point (j);
|
|
|
|
if (pt2.v < pt.v - (int32) radius)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (Abs_int32 (pt2.h - pt.h) <= radius)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
// Search forward through bad point list.
|
|
|
|
for (uint32 k = index + 1; k < PointCount (); k++)
|
|
{
|
|
|
|
const dng_point &pt2 = Point (k);
|
|
|
|
if (pt2.v > pt.v + (int32) radius)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (Abs_int32 (pt2.h - pt.h) <= radius)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
// Search through bad rectangle list.
|
|
|
|
dng_rect testRect (pt.v - radius,
|
|
pt.h - radius,
|
|
pt.v + radius + 1,
|
|
pt.h + radius + 1);
|
|
|
|
for (uint32 n = 0; n < RectCount (); n++)
|
|
{
|
|
|
|
if ((testRect & Rect (n)).NotEmpty ())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
// Did not find point anywhere, so bad pixel is isolated.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
bool dng_bad_pixel_list::IsRectIsolated (uint32 index,
|
|
uint32 radius) const
|
|
{
|
|
|
|
dng_rect testRect = Rect (index);
|
|
|
|
testRect.t -= radius;
|
|
testRect.l -= radius;
|
|
testRect.b += radius;
|
|
testRect.r += radius;
|
|
|
|
for (uint32 n = 0; n < RectCount (); n++)
|
|
{
|
|
|
|
if (n != index)
|
|
{
|
|
|
|
if ((testRect & Rect (n)).NotEmpty ())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
bool dng_bad_pixel_list::IsPointValid (const dng_point &pt,
|
|
const dng_rect &imageBounds,
|
|
uint32 index) const
|
|
{
|
|
|
|
// The point must be in the image bounds to be valid.
|
|
|
|
if (pt.v < imageBounds.t ||
|
|
pt.h < imageBounds.l ||
|
|
pt.v >= imageBounds.b ||
|
|
pt.h >= imageBounds.r)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Only search the bad point list if we have a starting search index.
|
|
|
|
if (index != kNoIndex)
|
|
{
|
|
|
|
// Search backward through bad point list.
|
|
|
|
for (int32 j = index - 1; j >= 0; j--)
|
|
{
|
|
|
|
const dng_point &pt2 = Point (j);
|
|
|
|
if (pt2.v < pt.v)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (pt2 == pt)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
// Search forward through bad point list.
|
|
|
|
for (uint32 k = index + 1; k < PointCount (); k++)
|
|
{
|
|
|
|
const dng_point &pt2 = Point (k);
|
|
|
|
if (pt2.v > pt.v)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (pt2 == pt)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Search through bad rectangle list.
|
|
|
|
for (uint32 n = 0; n < RectCount (); n++)
|
|
{
|
|
|
|
const dng_rect &r = Rect (n);
|
|
|
|
if (pt.v >= r.t &&
|
|
pt.h >= r.l &&
|
|
pt.v < r.b &&
|
|
pt.h < r.r)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
// Did not find point anywhere, so pixel is valid.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_opcode_FixBadPixelsList::dng_opcode_FixBadPixelsList
|
|
(AutoPtr<dng_bad_pixel_list> &list,
|
|
uint32 bayerPhase)
|
|
|
|
|
|
: dng_filter_opcode (dngOpcode_FixBadPixelsList,
|
|
dngVersion_1_3_0_0,
|
|
0)
|
|
|
|
, fList ()
|
|
|
|
, fBayerPhase (bayerPhase)
|
|
|
|
{
|
|
|
|
fList.Reset (list.Release ());
|
|
|
|
fList->Sort ();
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_opcode_FixBadPixelsList::dng_opcode_FixBadPixelsList (dng_stream &stream)
|
|
|
|
: dng_filter_opcode (dngOpcode_FixBadPixelsList,
|
|
stream,
|
|
"FixBadPixelsList")
|
|
|
|
, fList ()
|
|
|
|
, fBayerPhase (0)
|
|
|
|
{
|
|
|
|
uint32 size = stream.Get_uint32 ();
|
|
|
|
fBayerPhase = stream.Get_uint32 ();
|
|
|
|
uint32 pCount = stream.Get_uint32 ();
|
|
uint32 rCount = stream.Get_uint32 ();
|
|
uint32 expectedSize =
|
|
SafeUint32Add(12, SafeUint32Add(SafeUint32Mult(pCount, 8), SafeUint32Mult(rCount, 16)));
|
|
if (size != expectedSize)
|
|
{
|
|
ThrowBadFormat ();
|
|
}
|
|
|
|
fList.Reset (new dng_bad_pixel_list);
|
|
|
|
uint32 index;
|
|
|
|
for (index = 0; index < pCount; index++)
|
|
{
|
|
|
|
dng_point pt;
|
|
|
|
pt.v = stream.Get_int32 ();
|
|
pt.h = stream.Get_int32 ();
|
|
|
|
fList->AddPoint (pt);
|
|
|
|
}
|
|
|
|
for (index = 0; index < rCount; index++)
|
|
{
|
|
|
|
dng_rect r;
|
|
|
|
r.t = stream.Get_int32 ();
|
|
r.l = stream.Get_int32 ();
|
|
r.b = stream.Get_int32 ();
|
|
r.r = stream.Get_int32 ();
|
|
|
|
fList->AddRect (r);
|
|
|
|
}
|
|
|
|
fList->Sort ();
|
|
|
|
#if qDNGValidate
|
|
|
|
if (gVerbose)
|
|
{
|
|
|
|
printf ("Bayer Phase: %u\n", (unsigned) fBayerPhase);
|
|
|
|
printf ("Bad Pixels: %u\n", (unsigned) pCount);
|
|
|
|
for (index = 0; index < pCount && index < gDumpLineLimit; index++)
|
|
{
|
|
printf (" Pixel [%u]: v=%d, h=%d\n",
|
|
(unsigned) index,
|
|
(int) fList->Point (index).v,
|
|
(int) fList->Point (index).h);
|
|
}
|
|
|
|
if (pCount > gDumpLineLimit)
|
|
{
|
|
printf (" ... %u bad pixels skipped\n", (unsigned) (pCount - gDumpLineLimit));
|
|
}
|
|
|
|
printf ("Bad Rects: %u\n", (unsigned) rCount);
|
|
|
|
for (index = 0; index < rCount && index < gDumpLineLimit; index++)
|
|
{
|
|
printf (" Rect [%u]: t=%d, l=%d, b=%d, r=%d\n",
|
|
(unsigned) index,
|
|
(int) fList->Rect (index).t,
|
|
(int) fList->Rect (index).l,
|
|
(int) fList->Rect (index).b,
|
|
(int) fList->Rect (index).r);
|
|
}
|
|
|
|
if (rCount > gDumpLineLimit)
|
|
{
|
|
printf (" ... %u bad rects skipped\n", (unsigned) (rCount - gDumpLineLimit));
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_opcode_FixBadPixelsList::PutData (dng_stream &stream) const
|
|
{
|
|
|
|
uint32 pCount = fList->PointCount ();
|
|
uint32 rCount = fList->RectCount ();
|
|
|
|
stream.Put_uint32 (12 + pCount * 8 + rCount * 16);
|
|
|
|
stream.Put_uint32 (fBayerPhase);
|
|
|
|
stream.Put_uint32 (pCount);
|
|
stream.Put_uint32 (rCount);
|
|
|
|
uint32 index;
|
|
|
|
for (index = 0; index < pCount; index++)
|
|
{
|
|
|
|
const dng_point &pt (fList->Point (index));
|
|
|
|
stream.Put_int32 (pt.v);
|
|
stream.Put_int32 (pt.h);
|
|
|
|
}
|
|
|
|
for (index = 0; index < rCount; index++)
|
|
{
|
|
|
|
const dng_rect &r (fList->Rect (index));
|
|
|
|
stream.Put_int32 (r.t);
|
|
stream.Put_int32 (r.l);
|
|
stream.Put_int32 (r.b);
|
|
stream.Put_int32 (r.r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_rect dng_opcode_FixBadPixelsList::SrcArea (const dng_rect &dstArea,
|
|
const dng_rect & /* imageBounds */)
|
|
{
|
|
|
|
int32 padding = 0;
|
|
|
|
if (fList->PointCount ())
|
|
{
|
|
padding += kBadPointPadding;
|
|
}
|
|
|
|
if (fList->RectCount ())
|
|
{
|
|
padding += kBadRectPadding;
|
|
}
|
|
|
|
dng_rect srcArea = dstArea;
|
|
|
|
srcArea.t -= padding;
|
|
srcArea.l -= padding;
|
|
|
|
srcArea.b += padding;
|
|
srcArea.r += padding;
|
|
|
|
return srcArea;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_point dng_opcode_FixBadPixelsList::SrcRepeat ()
|
|
{
|
|
|
|
return dng_point (2, 2);
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_opcode_FixBadPixelsList::Prepare (dng_negative & /* negative */,
|
|
uint32 /* threadCount */,
|
|
const dng_point & /* tileSize */,
|
|
const dng_rect & /* imageBounds */,
|
|
uint32 imagePlanes,
|
|
uint32 bufferPixelType,
|
|
dng_memory_allocator & /* allocator */)
|
|
{
|
|
|
|
// This opcode is restricted to single channel images.
|
|
|
|
if (imagePlanes != 1)
|
|
{
|
|
|
|
ThrowBadFormat ();
|
|
|
|
}
|
|
|
|
// This opcode is restricted to 16-bit images.
|
|
|
|
if (bufferPixelType != ttShort)
|
|
{
|
|
|
|
ThrowBadFormat ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_opcode_FixBadPixelsList::FixIsolatedPixel (dng_pixel_buffer &buffer,
|
|
dng_point &badPoint)
|
|
{
|
|
|
|
uint16 *p0 = buffer.DirtyPixel_uint16 (badPoint.v - 2, badPoint.h - 2, 0);
|
|
uint16 *p1 = buffer.DirtyPixel_uint16 (badPoint.v - 1, badPoint.h - 2, 0);
|
|
uint16 *p2 = buffer.DirtyPixel_uint16 (badPoint.v , badPoint.h - 2, 0);
|
|
uint16 *p3 = buffer.DirtyPixel_uint16 (badPoint.v + 1, badPoint.h - 2, 0);
|
|
uint16 *p4 = buffer.DirtyPixel_uint16 (badPoint.v + 2, badPoint.h - 2, 0);
|
|
|
|
uint32 est0;
|
|
uint32 est1;
|
|
uint32 est2;
|
|
uint32 est3;
|
|
|
|
uint32 grad0;
|
|
uint32 grad1;
|
|
uint32 grad2;
|
|
uint32 grad3;
|
|
|
|
if (IsGreen (badPoint.v, badPoint.h)) // Green pixel
|
|
{
|
|
|
|
// g00 b01 g02 b03 g04
|
|
// r10 g11 r12 g13 r14
|
|
// g20 b21 g22 b23 g24
|
|
// r30 g31 r32 g33 r34
|
|
// g40 b41 g42 b43 g44
|
|
|
|
int32 b01 = p0 [1];
|
|
int32 g02 = p0 [2];
|
|
int32 b03 = p0 [3];
|
|
|
|
int32 r10 = p1 [0];
|
|
int32 g11 = p1 [1];
|
|
int32 r12 = p1 [2];
|
|
int32 g13 = p1 [3];
|
|
int32 r14 = p1 [4];
|
|
|
|
int32 g20 = p2 [0];
|
|
int32 b21 = p2 [1];
|
|
int32 b23 = p2 [3];
|
|
int32 g24 = p2 [4];
|
|
|
|
int32 r30 = p3 [0];
|
|
int32 g31 = p3 [1];
|
|
int32 r32 = p3 [2];
|
|
int32 g33 = p3 [3];
|
|
int32 r34 = p3 [4];
|
|
|
|
int32 b41 = p4 [1];
|
|
int32 g42 = p4 [2];
|
|
int32 b43 = p4 [3];
|
|
|
|
est0 = g02 + g42;
|
|
|
|
grad0 = Abs_int32 (g02 - g42) +
|
|
Abs_int32 (g11 - g31) +
|
|
Abs_int32 (g13 - g33) +
|
|
Abs_int32 (b01 - b21) +
|
|
Abs_int32 (b03 - b23) +
|
|
Abs_int32 (b21 - b41) +
|
|
Abs_int32 (b23 - b43);
|
|
|
|
est1 = g11 + g33;
|
|
|
|
grad1 = Abs_int32 (g11 - g33) +
|
|
Abs_int32 (g02 - g24) +
|
|
Abs_int32 (g20 - g42) +
|
|
Abs_int32 (b01 - b23) +
|
|
Abs_int32 (r10 - r32) +
|
|
Abs_int32 (r12 - r34) +
|
|
Abs_int32 (b21 - b43);
|
|
|
|
est2 = g20 + g24;
|
|
|
|
grad2 = Abs_int32 (g20 - g24) +
|
|
Abs_int32 (g11 - g13) +
|
|
Abs_int32 (g31 - g33) +
|
|
Abs_int32 (r10 - r12) +
|
|
Abs_int32 (r30 - r32) +
|
|
Abs_int32 (r12 - r14) +
|
|
Abs_int32 (r32 - r34);
|
|
|
|
est3 = g13 + g31;
|
|
|
|
grad3 = Abs_int32 (g13 - g31) +
|
|
Abs_int32 (g02 - g20) +
|
|
Abs_int32 (g24 - g42) +
|
|
Abs_int32 (b03 - b21) +
|
|
Abs_int32 (r14 - r32) +
|
|
Abs_int32 (r12 - r30) +
|
|
Abs_int32 (b23 - b41);
|
|
|
|
}
|
|
|
|
else // Red/blue pixel
|
|
{
|
|
|
|
// b00 g01 b02 g03 b04
|
|
// g10 r11 g12 r13 g14
|
|
// b20 g21 b22 g23 b24
|
|
// g30 r31 g32 r33 g34
|
|
// b40 g41 b42 g43 b44
|
|
|
|
int32 b00 = p0 [0];
|
|
int32 g01 = p0 [1];
|
|
int32 b02 = p0 [2];
|
|
int32 g03 = p0 [3];
|
|
int32 b04 = p0 [4];
|
|
|
|
int32 g10 = p1 [0];
|
|
int32 r11 = p1 [1];
|
|
int32 g12 = p1 [2];
|
|
int32 r13 = p1 [3];
|
|
int32 g14 = p1 [4];
|
|
|
|
int32 b20 = p2 [0];
|
|
int32 g21 = p2 [1];
|
|
int32 g23 = p2 [3];
|
|
int32 b24 = p2 [4];
|
|
|
|
int32 g30 = p3 [0];
|
|
int32 r31 = p3 [1];
|
|
int32 g32 = p3 [2];
|
|
int32 r33 = p3 [3];
|
|
int32 g34 = p3 [4];
|
|
|
|
int32 b40 = p4 [0];
|
|
int32 g41 = p4 [1];
|
|
int32 b42 = p4 [2];
|
|
int32 g43 = p4 [3];
|
|
int32 b44 = p4 [4];
|
|
|
|
est0 = b02 + b42;
|
|
|
|
grad0 = Abs_int32 (b02 - b42) +
|
|
Abs_int32 (g12 - g32) +
|
|
Abs_int32 (g01 - g21) +
|
|
Abs_int32 (g21 - g41) +
|
|
Abs_int32 (g03 - g23) +
|
|
Abs_int32 (g23 - g43) +
|
|
Abs_int32 (r11 - r31) +
|
|
Abs_int32 (r13 - r33);
|
|
|
|
est1 = b00 + b44;
|
|
|
|
grad1 = Abs_int32 (b00 - b44) +
|
|
Abs_int32 (r11 - r33) +
|
|
Abs_int32 (g01 - g23) +
|
|
Abs_int32 (g10 - g32) +
|
|
Abs_int32 (g12 - g34) +
|
|
Abs_int32 (g21 - g43) +
|
|
Abs_int32 (b02 - b24) +
|
|
Abs_int32 (b20 - b42);
|
|
|
|
est2 = b20 + b24;
|
|
|
|
grad2 = Abs_int32 (b20 - b24) +
|
|
Abs_int32 (g21 - g23) +
|
|
Abs_int32 (g10 - g12) +
|
|
Abs_int32 (g12 - g14) +
|
|
Abs_int32 (g30 - g32) +
|
|
Abs_int32 (g32 - g34) +
|
|
Abs_int32 (r11 - r13) +
|
|
Abs_int32 (r31 - r33);
|
|
|
|
est3 = b04 + b40;
|
|
|
|
grad3 = Abs_int32 (b04 - b40) +
|
|
Abs_int32 (r13 - r31) +
|
|
Abs_int32 (g03 - g21) +
|
|
Abs_int32 (g14 - g32) +
|
|
Abs_int32 (g12 - g30) +
|
|
Abs_int32 (g23 - g41) +
|
|
Abs_int32 (b02 - b20) +
|
|
Abs_int32 (b24 - b42);
|
|
|
|
}
|
|
|
|
uint32 minGrad = Min_uint32 (grad0, grad1);
|
|
|
|
minGrad = Min_uint32 (minGrad, grad2);
|
|
minGrad = Min_uint32 (minGrad, grad3);
|
|
|
|
uint32 limit = (minGrad * 3) >> 1;
|
|
|
|
uint32 total = 0;
|
|
uint32 count = 0;
|
|
|
|
if (grad0 <= limit)
|
|
{
|
|
total += est0;
|
|
count += 2;
|
|
}
|
|
|
|
if (grad1 <= limit)
|
|
{
|
|
total += est1;
|
|
count += 2;
|
|
}
|
|
|
|
if (grad2 <= limit)
|
|
{
|
|
total += est2;
|
|
count += 2;
|
|
}
|
|
|
|
if (grad3 <= limit)
|
|
{
|
|
total += est3;
|
|
count += 2;
|
|
}
|
|
|
|
uint32 estimate = (total + (count >> 1)) / count;
|
|
|
|
p2 [2] = (uint16) estimate;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_opcode_FixBadPixelsList::FixClusteredPixel (dng_pixel_buffer &buffer,
|
|
uint32 pointIndex,
|
|
const dng_rect &imageBounds)
|
|
{
|
|
|
|
const uint32 kNumSets = 3;
|
|
const uint32 kSetSize = 4;
|
|
|
|
static const int32 kOffset [kNumSets] [kSetSize] [2] =
|
|
{
|
|
{
|
|
{ -1, 1 },
|
|
{ -1, -1 },
|
|
{ 1, -1 },
|
|
{ 1, 1 }
|
|
},
|
|
{
|
|
{ -2, 0 },
|
|
{ 2, 0 },
|
|
{ 0, -2 },
|
|
{ 0, 2 }
|
|
},
|
|
{
|
|
{ -2, -2 },
|
|
{ -2, 2 },
|
|
{ 2, -2 },
|
|
{ 2, 2 }
|
|
}
|
|
};
|
|
|
|
dng_point badPoint = fList->Point (pointIndex);
|
|
|
|
bool isGreen = IsGreen (badPoint.v, badPoint.h);
|
|
|
|
uint16 *p = buffer.DirtyPixel_uint16 (badPoint.v, badPoint.h, 0);
|
|
|
|
for (uint32 set = 0; set < kNumSets; set++)
|
|
{
|
|
|
|
if (!isGreen && (kOffset [set] [0] [0] & 1) == 1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
uint32 total = 0;
|
|
uint32 count = 0;
|
|
|
|
for (uint32 entry = 0; entry < kSetSize; entry++)
|
|
{
|
|
|
|
dng_point offset (kOffset [set] [entry] [0],
|
|
kOffset [set] [entry] [1]);
|
|
|
|
if (fList->IsPointValid (badPoint + offset,
|
|
imageBounds,
|
|
pointIndex))
|
|
{
|
|
|
|
total += p [offset.v * buffer.fRowStep +
|
|
offset.h * buffer.fColStep];
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (count)
|
|
{
|
|
|
|
uint32 estimate = (total + (count >> 1)) / count;
|
|
|
|
p [0] = (uint16) estimate;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Unable to patch bad pixel. Leave pixel as is.
|
|
|
|
#if qDNGValidate
|
|
|
|
char s [256];
|
|
|
|
sprintf (s, "Unable to repair bad pixel, row %d, column %d",
|
|
(int) badPoint.v,
|
|
(int) badPoint.h);
|
|
|
|
ReportWarning (s);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_opcode_FixBadPixelsList::FixSingleColumn (dng_pixel_buffer &buffer,
|
|
const dng_rect &badRect)
|
|
{
|
|
|
|
int32 cs = buffer.fColStep;
|
|
|
|
for (int32 row = badRect.t; row < badRect.b; row++)
|
|
{
|
|
|
|
uint16 *p0 = buffer.DirtyPixel_uint16 (row - 4, badRect.l - 4, 0);
|
|
uint16 *p1 = buffer.DirtyPixel_uint16 (row - 3, badRect.l - 4, 0);
|
|
uint16 *p2 = buffer.DirtyPixel_uint16 (row - 2, badRect.l - 4, 0);
|
|
uint16 *p3 = buffer.DirtyPixel_uint16 (row - 1, badRect.l - 4, 0);
|
|
uint16 *p4 = buffer.DirtyPixel_uint16 (row , badRect.l - 4, 0);
|
|
uint16 *p5 = buffer.DirtyPixel_uint16 (row + 1, badRect.l - 4, 0);
|
|
uint16 *p6 = buffer.DirtyPixel_uint16 (row + 2, badRect.l - 4, 0);
|
|
uint16 *p7 = buffer.DirtyPixel_uint16 (row + 3, badRect.l - 4, 0);
|
|
uint16 *p8 = buffer.DirtyPixel_uint16 (row + 4, badRect.l - 4, 0);
|
|
|
|
uint32 est0;
|
|
uint32 est1;
|
|
uint32 est2;
|
|
uint32 est3;
|
|
uint32 est4;
|
|
uint32 est5;
|
|
uint32 est6;
|
|
|
|
uint32 grad0;
|
|
uint32 grad1;
|
|
uint32 grad2;
|
|
uint32 grad3;
|
|
uint32 grad4;
|
|
uint32 grad5;
|
|
uint32 grad6;
|
|
|
|
uint32 lower = 0;
|
|
uint32 upper = 0x0FFFF;
|
|
|
|
if (IsGreen (row, badRect.l)) // Green pixel
|
|
{
|
|
|
|
// g00 b01 g02 b03 g04 b05 g06 b07 g08
|
|
// r10 g11 r12 g13 r14 g15 r16 g17 r18
|
|
// g20 b21 g22 b23 g24 b25 g26 b27 g28
|
|
// r30 g31 r32 g33 r34 g35 r36 g37 r38
|
|
// g40 b41 g42 b43 g44 b45 g46 b47 g48
|
|
// r50 g51 r52 g53 r54 g55 r56 g57 r58
|
|
// g60 b61 g62 b63 g64 b65 g66 b67 g68
|
|
// r70 g71 r72 g73 r74 g75 r76 g77 r78
|
|
// g80 b81 g82 b83 g84 b85 g86 b87 g88
|
|
|
|
int32 b03 = p0 [3 * cs];
|
|
int32 b05 = p0 [5 * cs];
|
|
|
|
int32 g11 = p1 [1 * cs];
|
|
int32 g13 = p1 [3 * cs];
|
|
int32 g15 = p1 [5 * cs];
|
|
int32 g17 = p1 [7 * cs];
|
|
|
|
int32 g22 = p2 [2 * cs];
|
|
int32 b23 = p2 [3 * cs];
|
|
int32 b25 = p2 [5 * cs];
|
|
int32 g26 = p2 [6 * cs];
|
|
|
|
int32 r30 = p3 [0 * cs];
|
|
int32 g31 = p3 [1 * cs];
|
|
int32 r32 = p3 [2 * cs];
|
|
int32 g33 = p3 [3 * cs];
|
|
int32 g35 = p3 [5 * cs];
|
|
int32 r36 = p3 [6 * cs];
|
|
int32 g37 = p3 [7 * cs];
|
|
int32 r38 = p3 [8 * cs];
|
|
|
|
int32 g40 = p4 [0 * cs];
|
|
int32 g42 = p4 [2 * cs];
|
|
int32 b43 = p4 [3 * cs];
|
|
int32 b45 = p4 [5 * cs];
|
|
int32 g46 = p4 [6 * cs];
|
|
int32 g48 = p4 [8 * cs];
|
|
|
|
int32 r50 = p5 [0 * cs];
|
|
int32 g51 = p5 [1 * cs];
|
|
int32 r52 = p5 [2 * cs];
|
|
int32 g53 = p5 [3 * cs];
|
|
int32 g55 = p5 [5 * cs];
|
|
int32 r56 = p5 [6 * cs];
|
|
int32 g57 = p5 [7 * cs];
|
|
int32 r58 = p5 [8 * cs];
|
|
|
|
int32 g62 = p6 [2 * cs];
|
|
int32 b63 = p6 [3 * cs];
|
|
int32 b65 = p6 [5 * cs];
|
|
int32 g66 = p6 [6 * cs];
|
|
|
|
int32 g71 = p7 [1 * cs];
|
|
int32 g73 = p7 [3 * cs];
|
|
int32 g75 = p7 [5 * cs];
|
|
int32 g77 = p7 [7 * cs];
|
|
|
|
int32 b83 = p8 [3 * cs];
|
|
int32 b85 = p8 [5 * cs];
|
|
|
|
// In case there is some green split, make an estimate of
|
|
// of the local difference between the greens, and adjust
|
|
// the estimated green values for the difference
|
|
// between the two types of green pixels when estimating
|
|
// across green types.
|
|
|
|
int32 split = ((g22 + g62 + g26 + g66) * 4 +
|
|
(g42 + g46 ) * 8 -
|
|
(g11 + g13 + g15 + g17) -
|
|
(g31 + g33 + g35 + g37) * 3 -
|
|
(g51 + g53 + g55 + g57) * 3 -
|
|
(g71 + g73 + g75 + g77) + 16) >> 5;
|
|
|
|
est0 = g13 + g75 + split * 2;
|
|
|
|
grad0 = Abs_int32 (g13 - g75) +
|
|
Abs_int32 (g15 - g46) +
|
|
Abs_int32 (g22 - g53) +
|
|
Abs_int32 (g35 - g66) +
|
|
Abs_int32 (g42 - g73) +
|
|
Abs_int32 (b03 - b65) +
|
|
Abs_int32 (b23 - b85);
|
|
|
|
est1 = g33 + g55 + split * 2;
|
|
|
|
grad1 = Abs_int32 (g33 - g55) +
|
|
Abs_int32 (g22 - g55) +
|
|
Abs_int32 (g33 - g66) +
|
|
Abs_int32 (g13 - g35) +
|
|
Abs_int32 (g53 - g75) +
|
|
Abs_int32 (b23 - b45) +
|
|
Abs_int32 (b43 - b65);
|
|
|
|
est2 = g31 + g57 + split * 2;
|
|
|
|
grad2 = Abs_int32 (g31 - g57) +
|
|
Abs_int32 (g33 - g46) +
|
|
Abs_int32 (g35 - g48) +
|
|
Abs_int32 (g40 - g53) +
|
|
Abs_int32 (g42 - g55) +
|
|
Abs_int32 (r30 - r56) +
|
|
Abs_int32 (r32 - r58);
|
|
|
|
est3 = g42 + g46;
|
|
|
|
grad3 = Abs_int32 (g42 - g46) * 2 +
|
|
Abs_int32 (g33 - g35) +
|
|
Abs_int32 (g53 - g55) +
|
|
Abs_int32 (b23 - b25) +
|
|
Abs_int32 (b43 - b45) +
|
|
Abs_int32 (b63 - b65);
|
|
|
|
est4 = g37 + g51 + split * 2;
|
|
|
|
grad4 = Abs_int32 (g37 - g51) +
|
|
Abs_int32 (g35 - g42) +
|
|
Abs_int32 (g33 - g40) +
|
|
Abs_int32 (g48 - g55) +
|
|
Abs_int32 (g46 - g53) +
|
|
Abs_int32 (r38 - r52) +
|
|
Abs_int32 (r36 - r50);
|
|
|
|
est5 = g35 + g53 + split * 2;
|
|
|
|
grad5 = Abs_int32 (g35 - g53) +
|
|
Abs_int32 (g26 - g53) +
|
|
Abs_int32 (g35 - g62) +
|
|
Abs_int32 (g15 - g33) +
|
|
Abs_int32 (g55 - g73) +
|
|
Abs_int32 (b25 - b43) +
|
|
Abs_int32 (b45 - b63);
|
|
|
|
est6 = g15 + g73 + split * 2;
|
|
|
|
grad6 = Abs_int32 (g15 - g73) +
|
|
Abs_int32 (g13 - g42) +
|
|
Abs_int32 (g26 - g55) +
|
|
Abs_int32 (g33 - g62) +
|
|
Abs_int32 (g46 - g75) +
|
|
Abs_int32 (b05 - b63) +
|
|
Abs_int32 (b25 - b83);
|
|
|
|
lower = Min_uint32 (Min_uint32 (g33, g35),
|
|
Min_uint32 (g53, g55));
|
|
|
|
upper = Max_uint32 (Max_uint32 (g33, g35),
|
|
Max_uint32 (g53, g55));
|
|
|
|
lower = Pin_int32 (0, lower + split, 65535);
|
|
upper = Pin_int32 (0, upper + split, 65535);
|
|
|
|
}
|
|
|
|
else // Red/blue pixel
|
|
{
|
|
|
|
// b00 g01 b02 g03 b04 g05 b06 g07 b08
|
|
// g10 r11 g12 r13 g14 r15 g16 r17 g18
|
|
// b20 g21 b22 g23 b24 g25 b26 g27 b28
|
|
// g30 r31 g32 r33 g34 r35 g36 r37 g38
|
|
// b40 g41 b42 g43 b44 g45 b46 g47 b48
|
|
// g50 r51 g52 r53 g54 r55 g56 r57 g58
|
|
// b60 g61 b62 g63 b64 g65 b66 g67 b68
|
|
// g70 r71 g72 r73 g74 r75 g76 r77 g78
|
|
// b80 g81 b82 g83 b84 g85 b86 g87 b88
|
|
|
|
int32 b02 = p0 [2 * cs];
|
|
int32 g03 = p0 [3 * cs];
|
|
int32 g05 = p0 [5 * cs];
|
|
int32 b06 = p0 [6 * cs];
|
|
|
|
int32 r13 = p1 [3 * cs];
|
|
int32 r15 = p1 [5 * cs];
|
|
|
|
int32 b20 = p2 [0 * cs];
|
|
int32 b22 = p2 [2 * cs];
|
|
int32 g23 = p2 [3 * cs];
|
|
int32 g25 = p2 [5 * cs];
|
|
int32 b26 = p2 [6 * cs];
|
|
int32 b28 = p2 [8 * cs];
|
|
|
|
int32 r31 = p3 [1 * cs];
|
|
int32 g32 = p3 [2 * cs];
|
|
int32 r33 = p3 [3 * cs];
|
|
int32 r35 = p3 [5 * cs];
|
|
int32 g36 = p3 [6 * cs];
|
|
int32 r37 = p3 [7 * cs];
|
|
|
|
int32 g41 = p4 [1 * cs];
|
|
int32 b42 = p4 [2 * cs];
|
|
int32 g43 = p4 [3 * cs];
|
|
int32 g45 = p4 [5 * cs];
|
|
int32 b46 = p4 [6 * cs];
|
|
int32 g47 = p4 [7 * cs];
|
|
|
|
int32 r51 = p5 [1 * cs];
|
|
int32 g52 = p5 [2 * cs];
|
|
int32 r53 = p5 [3 * cs];
|
|
int32 r55 = p5 [5 * cs];
|
|
int32 g56 = p5 [6 * cs];
|
|
int32 r57 = p5 [7 * cs];
|
|
|
|
int32 b60 = p6 [0 * cs];
|
|
int32 b62 = p6 [2 * cs];
|
|
int32 g63 = p6 [3 * cs];
|
|
int32 g65 = p6 [5 * cs];
|
|
int32 b66 = p6 [6 * cs];
|
|
int32 b68 = p6 [8 * cs];
|
|
|
|
int32 r73 = p7 [3 * cs];
|
|
int32 r75 = p7 [5 * cs];
|
|
|
|
int32 b82 = p8 [2 * cs];
|
|
int32 g83 = p8 [3 * cs];
|
|
int32 g85 = p8 [5 * cs];
|
|
int32 b86 = p8 [6 * cs];
|
|
|
|
est0 = b02 + b86;
|
|
|
|
grad0 = Abs_int32 (b02 - b86) +
|
|
Abs_int32 (r13 - r55) +
|
|
Abs_int32 (r33 - r75) +
|
|
Abs_int32 (g03 - g45) +
|
|
Abs_int32 (g23 - g65) +
|
|
Abs_int32 (g43 - g85);
|
|
|
|
est1 = b22 + b66;
|
|
|
|
grad1 = Abs_int32 (b22 - b66) +
|
|
Abs_int32 (r13 - r35) +
|
|
Abs_int32 (r33 - r55) +
|
|
Abs_int32 (r53 - r75) +
|
|
Abs_int32 (g23 - g45) +
|
|
Abs_int32 (g43 - g65);
|
|
|
|
est2 = b20 + b68;
|
|
|
|
grad2 = Abs_int32 (b20 - b68) +
|
|
Abs_int32 (r31 - r55) +
|
|
Abs_int32 (r33 - r57) +
|
|
Abs_int32 (g23 - g47) +
|
|
Abs_int32 (g32 - g56) +
|
|
Abs_int32 (g41 - g65);
|
|
|
|
est3 = b42 + b46;
|
|
|
|
grad3 = Abs_int32 (b42 - b46) +
|
|
Abs_int32 (r33 - r35) +
|
|
Abs_int32 (r53 - r55) +
|
|
Abs_int32 (g32 - g36) +
|
|
Abs_int32 (g43 - g43) +
|
|
Abs_int32 (g52 - g56);
|
|
|
|
est4 = b28 + b60;
|
|
|
|
grad4 = Abs_int32 (b28 - b60) +
|
|
Abs_int32 (r37 - r53) +
|
|
Abs_int32 (r35 - r51) +
|
|
Abs_int32 (g25 - g41) +
|
|
Abs_int32 (g36 - g52) +
|
|
Abs_int32 (g47 - g63);
|
|
|
|
est5 = b26 + b62;
|
|
|
|
grad5 = Abs_int32 (b26 - b62) +
|
|
Abs_int32 (r15 - r33) +
|
|
Abs_int32 (r35 - r53) +
|
|
Abs_int32 (r55 - r73) +
|
|
Abs_int32 (g25 - g43) +
|
|
Abs_int32 (g45 - g63);
|
|
|
|
est6 = b06 + b82;
|
|
|
|
grad6 = Abs_int32 (b06 - b82) +
|
|
Abs_int32 (r15 - r53) +
|
|
Abs_int32 (r35 - r73) +
|
|
Abs_int32 (g05 - g43) +
|
|
Abs_int32 (g25 - g63) +
|
|
Abs_int32 (g45 - g83);
|
|
|
|
lower = Min_uint32 (b42, b46);
|
|
upper = Max_uint32 (b42, b46);
|
|
|
|
}
|
|
|
|
uint32 minGrad = Min_uint32 (grad0, grad1);
|
|
|
|
minGrad = Min_uint32 (minGrad, grad2);
|
|
minGrad = Min_uint32 (minGrad, grad3);
|
|
minGrad = Min_uint32 (minGrad, grad4);
|
|
minGrad = Min_uint32 (minGrad, grad5);
|
|
minGrad = Min_uint32 (minGrad, grad6);
|
|
|
|
uint32 limit = (minGrad * 3) >> 1;
|
|
|
|
uint32 total = 0;
|
|
uint32 count = 0;
|
|
|
|
if (grad0 <= limit)
|
|
{
|
|
total += est0;
|
|
count += 2;
|
|
}
|
|
|
|
if (grad1 <= limit)
|
|
{
|
|
total += est1;
|
|
count += 2;
|
|
}
|
|
|
|
if (grad2 <= limit)
|
|
{
|
|
total += est2;
|
|
count += 2;
|
|
}
|
|
|
|
if (grad3 <= limit)
|
|
{
|
|
total += est3;
|
|
count += 2;
|
|
}
|
|
|
|
if (grad4 <= limit)
|
|
{
|
|
total += est4;
|
|
count += 2;
|
|
}
|
|
|
|
if (grad5 <= limit)
|
|
{
|
|
total += est5;
|
|
count += 2;
|
|
}
|
|
|
|
if (grad6 <= limit)
|
|
{
|
|
total += est6;
|
|
count += 2;
|
|
}
|
|
|
|
uint32 estimate = (total + (count >> 1)) / count;
|
|
|
|
p4 [4] = (uint16) Pin_uint32 (lower, estimate, upper);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_opcode_FixBadPixelsList::FixSingleRow (dng_pixel_buffer &buffer,
|
|
const dng_rect &badRect)
|
|
{
|
|
|
|
dng_pixel_buffer tBuffer = buffer;
|
|
|
|
tBuffer.fArea = Transpose (buffer.fArea);
|
|
|
|
tBuffer.fRowStep = buffer.fColStep;
|
|
tBuffer.fColStep = buffer.fRowStep;
|
|
|
|
dng_rect tBadRect = Transpose (badRect);
|
|
|
|
FixSingleColumn (tBuffer, tBadRect);
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_opcode_FixBadPixelsList::FixClusteredRect (dng_pixel_buffer &buffer,
|
|
const dng_rect &badRect,
|
|
const dng_rect &imageBounds)
|
|
{
|
|
|
|
const uint32 kNumSets = 8;
|
|
const uint32 kSetSize = 8;
|
|
|
|
static const int32 kOffset [kNumSets] [kSetSize] [2] =
|
|
{
|
|
{
|
|
{ -1, 1 },
|
|
{ -1, -1 },
|
|
{ 1, -1 },
|
|
{ 1, 1 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 }
|
|
},
|
|
{
|
|
{ -2, 0 },
|
|
{ 2, 0 },
|
|
{ 0, -2 },
|
|
{ 0, 2 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 }
|
|
},
|
|
{
|
|
{ -2, -2 },
|
|
{ -2, 2 },
|
|
{ 2, -2 },
|
|
{ 2, 2 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 }
|
|
},
|
|
{
|
|
{ -1, -3 },
|
|
{ -3, -1 },
|
|
{ 1, -3 },
|
|
{ 3, -1 },
|
|
{ -1, 3 },
|
|
{ -3, 1 },
|
|
{ 1, 3 },
|
|
{ 3, 1 }
|
|
},
|
|
{
|
|
{ -4, 0 },
|
|
{ 4, 0 },
|
|
{ 0, -4 },
|
|
{ 0, 4 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 }
|
|
},
|
|
{
|
|
{ -3, -3 },
|
|
{ -3, 3 },
|
|
{ 3, -3 },
|
|
{ 3, 3 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 }
|
|
},
|
|
{
|
|
{ -2, -4 },
|
|
{ -4, -2 },
|
|
{ 2, -4 },
|
|
{ 4, -2 },
|
|
{ -2, 4 },
|
|
{ -4, 2 },
|
|
{ 2, 4 },
|
|
{ 4, 2 }
|
|
},
|
|
{
|
|
{ -4, -4 },
|
|
{ -4, 4 },
|
|
{ 4, -4 },
|
|
{ 4, 4 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 },
|
|
{ 0, 0 }
|
|
}
|
|
};
|
|
|
|
bool didFail = false;
|
|
|
|
for (int32 row = badRect.t; row < badRect.b; row++)
|
|
{
|
|
|
|
for (int32 col = badRect.l; col < badRect.r; col++)
|
|
{
|
|
|
|
uint16 *p = buffer.DirtyPixel_uint16 (row, col, 0);
|
|
|
|
bool isGreen = IsGreen (row, col);
|
|
|
|
bool didFixPixel = false;
|
|
|
|
for (uint32 set = 0; set < kNumSets && !didFixPixel; set++)
|
|
{
|
|
|
|
if (!isGreen && (kOffset [set] [0] [0] & 1) == 1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
uint32 total = 0;
|
|
uint32 count = 0;
|
|
|
|
for (uint32 entry = 0; entry < kSetSize; entry++)
|
|
{
|
|
|
|
dng_point offset (kOffset [set] [entry] [0],
|
|
kOffset [set] [entry] [1]);
|
|
|
|
if (offset.v == 0 &&
|
|
offset.h == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (fList->IsPointValid (dng_point (row, col) + offset,
|
|
imageBounds))
|
|
{
|
|
|
|
total += p [offset.v * buffer.fRowStep +
|
|
offset.h * buffer.fColStep];
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (count)
|
|
{
|
|
|
|
uint32 estimate = (total + (count >> 1)) / count;
|
|
|
|
p [0] = (uint16) estimate;
|
|
|
|
didFixPixel = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!didFixPixel)
|
|
{
|
|
|
|
didFail = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#if qDNGValidate
|
|
|
|
if (didFail)
|
|
{
|
|
|
|
ReportWarning ("Unable to repair bad rectangle");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_opcode_FixBadPixelsList::ProcessArea (dng_negative & /* negative */,
|
|
uint32 /* threadIndex */,
|
|
dng_pixel_buffer &srcBuffer,
|
|
dng_pixel_buffer &dstBuffer,
|
|
const dng_rect &dstArea,
|
|
const dng_rect &imageBounds)
|
|
{
|
|
|
|
uint32 pointCount = fList->PointCount ();
|
|
uint32 rectCount = fList->RectCount ();
|
|
|
|
dng_rect fixArea = dstArea;
|
|
|
|
if (rectCount)
|
|
{
|
|
fixArea.t -= kBadRectPadding;
|
|
fixArea.l -= kBadRectPadding;
|
|
fixArea.b += kBadRectPadding;
|
|
fixArea.r += kBadRectPadding;
|
|
}
|
|
|
|
bool didFixPoint = false;
|
|
|
|
if (pointCount)
|
|
{
|
|
|
|
for (uint32 pointIndex = 0; pointIndex < pointCount; pointIndex++)
|
|
{
|
|
|
|
dng_point badPoint = fList->Point (pointIndex);
|
|
|
|
if (badPoint.v >= fixArea.t &&
|
|
badPoint.h >= fixArea.l &&
|
|
badPoint.v < fixArea.b &&
|
|
badPoint.h < fixArea.r)
|
|
{
|
|
|
|
bool isIsolated = fList->IsPointIsolated (pointIndex,
|
|
kBadPointPadding);
|
|
|
|
if (isIsolated &&
|
|
badPoint.v >= imageBounds.t + kBadPointPadding &&
|
|
badPoint.h >= imageBounds.l + kBadPointPadding &&
|
|
badPoint.v < imageBounds.b - kBadPointPadding &&
|
|
badPoint.h < imageBounds.r - kBadPointPadding)
|
|
{
|
|
|
|
FixIsolatedPixel (srcBuffer,
|
|
badPoint);
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
FixClusteredPixel (srcBuffer,
|
|
pointIndex,
|
|
imageBounds);
|
|
|
|
}
|
|
|
|
didFixPoint = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (rectCount)
|
|
{
|
|
|
|
if (didFixPoint)
|
|
{
|
|
|
|
srcBuffer.RepeatSubArea (imageBounds,
|
|
SrcRepeat ().v,
|
|
SrcRepeat ().h);
|
|
|
|
}
|
|
|
|
for (uint32 rectIndex = 0; rectIndex < rectCount; rectIndex++)
|
|
{
|
|
|
|
dng_rect badRect = fList->Rect (rectIndex);
|
|
|
|
dng_rect overlap = dstArea & badRect;
|
|
|
|
if (overlap.NotEmpty ())
|
|
{
|
|
|
|
bool isIsolated = fList->IsRectIsolated (rectIndex,
|
|
kBadRectPadding);
|
|
|
|
if (isIsolated &&
|
|
badRect.r == badRect.l + 1 &&
|
|
badRect.l >= imageBounds.l + SrcRepeat ().h &&
|
|
badRect.r <= imageBounds.r - SrcRepeat ().v)
|
|
{
|
|
|
|
FixSingleColumn (srcBuffer,
|
|
overlap);
|
|
|
|
}
|
|
|
|
else if (isIsolated &&
|
|
badRect.b == badRect.t + 1 &&
|
|
badRect.t >= imageBounds.t + SrcRepeat ().h &&
|
|
badRect.b <= imageBounds.b - SrcRepeat ().v)
|
|
{
|
|
|
|
FixSingleRow (srcBuffer,
|
|
overlap);
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
FixClusteredRect (srcBuffer,
|
|
overlap,
|
|
imageBounds);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dstBuffer.CopyArea (srcBuffer,
|
|
dstArea,
|
|
0,
|
|
dstBuffer.fPlanes);
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|