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.
601 lines
12 KiB
601 lines
12 KiB
/*****************************************************************************/
|
|
// Copyright 2008-2009 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_gain_map.cpp#1 $ */
|
|
/* $DateTime: 2012/05/30 13:28:51 $ */
|
|
/* $Change: 832332 $ */
|
|
/* $Author: tknoll $ */
|
|
|
|
/*****************************************************************************/
|
|
|
|
#include "dng_gain_map.h"
|
|
|
|
#include "dng_exceptions.h"
|
|
#include "dng_globals.h"
|
|
#include "dng_host.h"
|
|
#include "dng_pixel_buffer.h"
|
|
#include "dng_safe_arithmetic.h"
|
|
#include "dng_stream.h"
|
|
#include "dng_tag_values.h"
|
|
|
|
/*****************************************************************************/
|
|
|
|
class dng_gain_map_interpolator
|
|
{
|
|
|
|
private:
|
|
|
|
const dng_gain_map &fMap;
|
|
|
|
dng_point_real64 fScale;
|
|
dng_point_real64 fOffset;
|
|
|
|
int32 fColumn;
|
|
int32 fPlane;
|
|
|
|
uint32 fRowIndex1;
|
|
uint32 fRowIndex2;
|
|
real32 fRowFract;
|
|
|
|
int32 fResetColumn;
|
|
|
|
real32 fValueBase;
|
|
real32 fValueStep;
|
|
real32 fValueIndex;
|
|
|
|
public:
|
|
|
|
dng_gain_map_interpolator (const dng_gain_map &map,
|
|
const dng_rect &mapBounds,
|
|
int32 row,
|
|
int32 column,
|
|
uint32 plane);
|
|
|
|
real32 Interpolate () const
|
|
{
|
|
|
|
return fValueBase + fValueStep * fValueIndex;
|
|
|
|
}
|
|
|
|
void Increment ()
|
|
{
|
|
|
|
if (++fColumn >= fResetColumn)
|
|
{
|
|
|
|
ResetColumn ();
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
fValueIndex += 1.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
real32 InterpolateEntry (uint32 colIndex);
|
|
|
|
void ResetColumn ();
|
|
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_gain_map_interpolator::dng_gain_map_interpolator (const dng_gain_map &map,
|
|
const dng_rect &mapBounds,
|
|
int32 row,
|
|
int32 column,
|
|
uint32 plane)
|
|
|
|
: fMap (map)
|
|
|
|
, fScale (1.0 / mapBounds.H (),
|
|
1.0 / mapBounds.W ())
|
|
|
|
, fOffset (0.5 - mapBounds.t,
|
|
0.5 - mapBounds.l)
|
|
|
|
, fColumn (column)
|
|
, fPlane (plane)
|
|
|
|
, fRowIndex1 (0)
|
|
, fRowIndex2 (0)
|
|
, fRowFract (0.0f)
|
|
|
|
, fResetColumn (0)
|
|
|
|
, fValueBase (0.0f)
|
|
, fValueStep (0.0f)
|
|
, fValueIndex (0.0f)
|
|
|
|
{
|
|
|
|
real64 rowIndexF = (fScale.v * (row + fOffset.v) -
|
|
fMap.Origin ().v) / fMap.Spacing ().v;
|
|
|
|
if (rowIndexF <= 0.0)
|
|
{
|
|
|
|
fRowIndex1 = 0;
|
|
fRowIndex2 = 0;
|
|
|
|
fRowFract = 0.0f;
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
if (fMap.Points ().v < 1)
|
|
{
|
|
ThrowProgramError ("Empty gain map");
|
|
}
|
|
uint32 lastRow = static_cast<uint32> (fMap.Points ().v - 1);
|
|
|
|
if (rowIndexF >= static_cast<real64> (lastRow))
|
|
{
|
|
|
|
fRowIndex1 = lastRow;
|
|
fRowIndex2 = fRowIndex1;
|
|
|
|
fRowFract = 0.0f;
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
// If we got here, we know that rowIndexF can safely be converted to
|
|
// a uint32 and that static_cast<uint32> (rowIndexF) < lastRow. This
|
|
// implies fRowIndex2 <= lastRow below.
|
|
fRowIndex1 = static_cast<uint32> (rowIndexF);
|
|
fRowIndex2 = fRowIndex1 + 1;
|
|
|
|
fRowFract = (real32) (rowIndexF - (real64) fRowIndex1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ResetColumn ();
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
real32 dng_gain_map_interpolator::InterpolateEntry (uint32 colIndex)
|
|
{
|
|
|
|
return fMap.Entry (fRowIndex1, colIndex, fPlane) * (1.0f - fRowFract) +
|
|
fMap.Entry (fRowIndex2, colIndex, fPlane) * ( fRowFract);
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_gain_map_interpolator::ResetColumn ()
|
|
{
|
|
|
|
real64 colIndexF = ((fScale.h * (fColumn + fOffset.h)) -
|
|
fMap.Origin ().h) / fMap.Spacing ().h;
|
|
|
|
if (colIndexF <= 0.0)
|
|
{
|
|
|
|
fValueBase = InterpolateEntry (0);
|
|
|
|
fValueStep = 0.0f;
|
|
|
|
fResetColumn = (int32) ceil (fMap.Origin ().h / fScale.h - fOffset.h);
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
if (fMap.Points ().h < 1)
|
|
{
|
|
ThrowProgramError ("Empty gain map");
|
|
}
|
|
uint32 lastCol = static_cast<uint32> (fMap.Points ().h - 1);
|
|
|
|
if (colIndexF >= static_cast<real64> (lastCol))
|
|
{
|
|
|
|
fValueBase = InterpolateEntry (lastCol);
|
|
|
|
fValueStep = 0.0f;
|
|
|
|
fResetColumn = 0x7FFFFFFF;
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
// If we got here, we know that colIndexF can safely be converted to
|
|
// a uint32 and that static_cast<uint32> (colIndexF) < lastCol. This
|
|
// implies colIndex + 1 <= lastCol, i.e. the argument to
|
|
// InterpolateEntry() below is valid.
|
|
uint32 colIndex = static_cast<uint32> (colIndexF);
|
|
real64 base = InterpolateEntry (colIndex);
|
|
real64 delta = InterpolateEntry (colIndex + 1) - base;
|
|
|
|
fValueBase = (real32) (base + delta * (colIndexF - (real64) colIndex));
|
|
|
|
fValueStep = (real32) ((delta * fScale.h) / fMap.Spacing ().h);
|
|
|
|
fResetColumn = (int32) ceil (((colIndex + 1) * fMap.Spacing ().h +
|
|
fMap.Origin ().h) / fScale.h - fOffset.h);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fValueIndex = 0.0f;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_gain_map::dng_gain_map (dng_memory_allocator &allocator,
|
|
const dng_point &points,
|
|
const dng_point_real64 &spacing,
|
|
const dng_point_real64 &origin,
|
|
uint32 planes)
|
|
|
|
: fPoints (points)
|
|
, fSpacing (spacing)
|
|
, fOrigin (origin)
|
|
, fPlanes (planes)
|
|
|
|
, fRowStep (SafeUint32Mult(planes, points.h))
|
|
|
|
, fBuffer ()
|
|
|
|
{
|
|
|
|
fBuffer.Reset (allocator.Allocate (
|
|
ComputeBufferSize (ttFloat, fPoints, fPlanes, pad16Bytes)));
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
real32 dng_gain_map::Interpolate (int32 row,
|
|
int32 col,
|
|
uint32 plane,
|
|
const dng_rect &bounds) const
|
|
{
|
|
|
|
dng_gain_map_interpolator interp (*this,
|
|
bounds,
|
|
row,
|
|
col,
|
|
plane);
|
|
|
|
return interp.Interpolate ();
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
uint32 dng_gain_map::PutStreamSize () const
|
|
{
|
|
|
|
return 44 + fPoints.v * fPoints.h * fPlanes * 4;
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_gain_map::PutStream (dng_stream &stream) const
|
|
{
|
|
|
|
stream.Put_uint32 (fPoints.v);
|
|
stream.Put_uint32 (fPoints.h);
|
|
|
|
stream.Put_real64 (fSpacing.v);
|
|
stream.Put_real64 (fSpacing.h);
|
|
|
|
stream.Put_real64 (fOrigin.v);
|
|
stream.Put_real64 (fOrigin.h);
|
|
|
|
stream.Put_uint32 (fPlanes);
|
|
|
|
for (int32 rowIndex = 0; rowIndex < fPoints.v; rowIndex++)
|
|
{
|
|
|
|
for (int32 colIndex = 0; colIndex < fPoints.h; colIndex++)
|
|
{
|
|
|
|
for (uint32 plane = 0; plane < fPlanes; plane++)
|
|
{
|
|
|
|
stream.Put_real32 (Entry (rowIndex,
|
|
colIndex,
|
|
plane));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_gain_map * dng_gain_map::GetStream (dng_host &host,
|
|
dng_stream &stream)
|
|
{
|
|
|
|
dng_point mapPoints;
|
|
|
|
mapPoints.v = stream.Get_uint32 ();
|
|
mapPoints.h = stream.Get_uint32 ();
|
|
|
|
dng_point_real64 mapSpacing;
|
|
|
|
mapSpacing.v = stream.Get_real64 ();
|
|
mapSpacing.h = stream.Get_real64 ();
|
|
|
|
dng_point_real64 mapOrigin;
|
|
|
|
mapOrigin.v = stream.Get_real64 ();
|
|
mapOrigin.h = stream.Get_real64 ();
|
|
|
|
uint32 mapPlanes = stream.Get_uint32 ();
|
|
|
|
#if qDNGValidate
|
|
|
|
if (gVerbose)
|
|
{
|
|
|
|
printf ("Points: v=%d, h=%d\n",
|
|
(int) mapPoints.v,
|
|
(int) mapPoints.h);
|
|
|
|
printf ("Spacing: v=%.6f, h=%.6f\n",
|
|
mapSpacing.v,
|
|
mapSpacing.h);
|
|
|
|
printf ("Origin: v=%.6f, h=%.6f\n",
|
|
mapOrigin.v,
|
|
mapOrigin.h);
|
|
|
|
printf ("Planes: %u\n",
|
|
(unsigned) mapPlanes);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (mapPoints.v == 1)
|
|
{
|
|
mapSpacing.v = 1.0;
|
|
mapOrigin.v = 0.0;
|
|
}
|
|
|
|
if (mapPoints.h == 1)
|
|
{
|
|
mapSpacing.h = 1.0;
|
|
mapOrigin.h = 0.0;
|
|
}
|
|
|
|
if (mapPoints.v < 1 ||
|
|
mapPoints.h < 1 ||
|
|
mapSpacing.v <= 0.0 ||
|
|
mapSpacing.h <= 0.0 ||
|
|
mapPlanes < 1)
|
|
{
|
|
ThrowBadFormat ();
|
|
}
|
|
|
|
AutoPtr<dng_gain_map> map (new dng_gain_map (host.Allocator (),
|
|
mapPoints,
|
|
mapSpacing,
|
|
mapOrigin,
|
|
mapPlanes));
|
|
|
|
#if qDNGValidate
|
|
|
|
uint32 linesPrinted = 0;
|
|
uint32 linesSkipped = 0;
|
|
|
|
#endif
|
|
|
|
for (int32 rowIndex = 0; rowIndex < mapPoints.v; rowIndex++)
|
|
{
|
|
|
|
for (int32 colIndex = 0; colIndex < mapPoints.h; colIndex++)
|
|
{
|
|
|
|
for (uint32 plane = 0; plane < mapPlanes; plane++)
|
|
{
|
|
|
|
real32 x = stream.Get_real32 ();
|
|
|
|
map->Entry (rowIndex, colIndex, plane) = x;
|
|
|
|
#if qDNGValidate
|
|
|
|
if (gVerbose)
|
|
{
|
|
|
|
if (linesPrinted < gDumpLineLimit)
|
|
{
|
|
|
|
printf (" Map [%3u] [%3u] [%u] = %.4f\n",
|
|
(unsigned) rowIndex,
|
|
(unsigned) colIndex,
|
|
(unsigned) plane,
|
|
x);
|
|
|
|
linesPrinted++;
|
|
|
|
}
|
|
|
|
else
|
|
linesSkipped++;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#if qDNGValidate
|
|
|
|
if (linesSkipped)
|
|
{
|
|
|
|
printf (" ... %u map entries skipped\n", (unsigned) linesSkipped);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return map.Release ();
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_opcode_GainMap::dng_opcode_GainMap (const dng_area_spec &areaSpec,
|
|
AutoPtr<dng_gain_map> &gainMap)
|
|
|
|
: dng_inplace_opcode (dngOpcode_GainMap,
|
|
dngVersion_1_3_0_0,
|
|
kFlag_None)
|
|
|
|
, fAreaSpec (areaSpec)
|
|
|
|
, fGainMap ()
|
|
|
|
{
|
|
|
|
fGainMap.Reset (gainMap.Release ());
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
dng_opcode_GainMap::dng_opcode_GainMap (dng_host &host,
|
|
dng_stream &stream)
|
|
|
|
: dng_inplace_opcode (dngOpcode_GainMap,
|
|
stream,
|
|
"GainMap")
|
|
|
|
, fAreaSpec ()
|
|
|
|
, fGainMap ()
|
|
|
|
{
|
|
|
|
uint32 byteCount = stream.Get_uint32 ();
|
|
|
|
uint64 startPosition = stream.Position ();
|
|
|
|
fAreaSpec.GetData (stream);
|
|
|
|
fGainMap.Reset (dng_gain_map::GetStream (host, stream));
|
|
|
|
if (stream.Position () != startPosition + byteCount)
|
|
{
|
|
ThrowBadFormat ();
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_opcode_GainMap::PutData (dng_stream &stream) const
|
|
{
|
|
|
|
stream.Put_uint32 (dng_area_spec::kDataSize +
|
|
fGainMap->PutStreamSize ());
|
|
|
|
fAreaSpec.PutData (stream);
|
|
|
|
fGainMap->PutStream (stream);
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void dng_opcode_GainMap::ProcessArea (dng_negative & /* negative */,
|
|
uint32 /* threadIndex */,
|
|
dng_pixel_buffer &buffer,
|
|
const dng_rect &dstArea,
|
|
const dng_rect &imageBounds)
|
|
{
|
|
|
|
dng_rect overlap = fAreaSpec.Overlap (dstArea);
|
|
|
|
if (overlap.NotEmpty ())
|
|
{
|
|
|
|
uint32 cols = overlap.W ();
|
|
|
|
uint32 colPitch = fAreaSpec.ColPitch ();
|
|
|
|
for (uint32 plane = fAreaSpec.Plane ();
|
|
plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
|
|
plane < buffer.Planes ();
|
|
plane++)
|
|
{
|
|
|
|
uint32 mapPlane = Min_uint32 (plane, fGainMap->Planes () - 1);
|
|
|
|
for (int32 row = overlap.t; row < overlap.b; row += fAreaSpec.RowPitch ())
|
|
{
|
|
|
|
real32 *dPtr = buffer.DirtyPixel_real32 (row, overlap.l, plane);
|
|
|
|
dng_gain_map_interpolator interp (*fGainMap,
|
|
imageBounds,
|
|
row,
|
|
overlap.l,
|
|
mapPlane);
|
|
|
|
for (uint32 col = 0; col < cols; col += colPitch)
|
|
{
|
|
|
|
real32 gain = interp.Interpolate ();
|
|
|
|
dPtr [col] = Min_real32 (dPtr [col] * gain, 1.0f);
|
|
|
|
for (uint32 j = 0; j < colPitch; j++)
|
|
{
|
|
interp.Increment ();
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|