Home | History | Annotate | Download | only in source
      1 /*****************************************************************************/
      2 // Copyright 2008-2009 Adobe Systems Incorporated
      3 // All Rights Reserved.
      4 //
      5 // NOTICE:  Adobe permits you to use, modify, and distribute this file in
      6 // accordance with the terms of the Adobe license agreement accompanying it.
      7 /*****************************************************************************/
      8 
      9 /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_gain_map.cpp#1 $ */
     10 /* $DateTime: 2012/05/30 13:28:51 $ */
     11 /* $Change: 832332 $ */
     12 /* $Author: tknoll $ */
     13 
     14 /*****************************************************************************/
     15 
     16 #include "dng_gain_map.h"
     17 
     18 #include "dng_exceptions.h"
     19 #include "dng_globals.h"
     20 #include "dng_host.h"
     21 #include "dng_pixel_buffer.h"
     22 #include "dng_safe_arithmetic.h"
     23 #include "dng_stream.h"
     24 #include "dng_tag_values.h"
     25 
     26 /*****************************************************************************/
     27 
     28 class dng_gain_map_interpolator
     29 	{
     30 
     31 	private:
     32 
     33 		const dng_gain_map &fMap;
     34 
     35 		dng_point_real64 fScale;
     36 		dng_point_real64 fOffset;
     37 
     38 		int32 fColumn;
     39 		int32 fPlane;
     40 
     41 		uint32 fRowIndex1;
     42 		uint32 fRowIndex2;
     43 		real32 fRowFract;
     44 
     45 		int32 fResetColumn;
     46 
     47 		real32 fValueBase;
     48 		real32 fValueStep;
     49 		real32 fValueIndex;
     50 
     51 	public:
     52 
     53 		dng_gain_map_interpolator (const dng_gain_map &map,
     54 								   const dng_rect &mapBounds,
     55 								   int32 row,
     56 								   int32 column,
     57 								   uint32 plane);
     58 
     59 		real32 Interpolate () const
     60 			{
     61 
     62 			return fValueBase + fValueStep * fValueIndex;
     63 
     64 			}
     65 
     66 		void Increment ()
     67 			{
     68 
     69 			if (++fColumn >= fResetColumn)
     70 				{
     71 
     72 				ResetColumn ();
     73 
     74 				}
     75 
     76 			else
     77 				{
     78 
     79 				fValueIndex += 1.0f;
     80 
     81 				}
     82 
     83 			}
     84 
     85 	private:
     86 
     87 		real32 InterpolateEntry (uint32 colIndex);
     88 
     89 		void ResetColumn ();
     90 
     91 	};
     92 
     93 /*****************************************************************************/
     94 
     95 dng_gain_map_interpolator::dng_gain_map_interpolator (const dng_gain_map &map,
     96 													  const dng_rect &mapBounds,
     97 													  int32 row,
     98 													  int32 column,
     99 													  uint32 plane)
    100 
    101 	:	fMap (map)
    102 
    103 	,	fScale (1.0 / mapBounds.H (),
    104 				1.0 / mapBounds.W ())
    105 
    106 	,	fOffset (0.5 - mapBounds.t,
    107 				 0.5 - mapBounds.l)
    108 
    109 	,	fColumn (column)
    110 	,	fPlane  (plane)
    111 
    112 	,	fRowIndex1 (0)
    113 	,	fRowIndex2 (0)
    114 	,	fRowFract  (0.0f)
    115 
    116 	,	fResetColumn (0)
    117 
    118 	,	fValueBase  (0.0f)
    119 	,	fValueStep  (0.0f)
    120 	,	fValueIndex (0.0f)
    121 
    122 	{
    123 
    124 	real64 rowIndexF = (fScale.v * (row + fOffset.v) -
    125 						fMap.Origin ().v) / fMap.Spacing ().v;
    126 
    127 	if (rowIndexF <= 0.0)
    128 		{
    129 
    130 		fRowIndex1 = 0;
    131 		fRowIndex2 = 0;
    132 
    133 		fRowFract = 0.0f;
    134 
    135 		}
    136 
    137 	else
    138 		{
    139 
    140 		if (fMap.Points ().v < 1)
    141 			{
    142 			ThrowProgramError ("Empty gain map");
    143 			}
    144 		uint32 lastRow = static_cast<uint32> (fMap.Points ().v - 1);
    145 
    146 		if (rowIndexF >= static_cast<real64> (lastRow))
    147 			{
    148 
    149 			fRowIndex1 = lastRow;
    150 			fRowIndex2 = fRowIndex1;
    151 
    152 			fRowFract = 0.0f;
    153 
    154 			}
    155 
    156 		else
    157 			{
    158 
    159 			// If we got here, we know that rowIndexF can safely be converted to
    160 			// a uint32 and that static_cast<uint32> (rowIndexF) < lastRow. This
    161 			// implies fRowIndex2 <= lastRow below.
    162 			fRowIndex1 = static_cast<uint32> (rowIndexF);
    163 			fRowIndex2 = fRowIndex1 + 1;
    164 
    165 			fRowFract = (real32) (rowIndexF - (real64) fRowIndex1);
    166 
    167 			}
    168 
    169 		}
    170 
    171 	ResetColumn ();
    172 
    173 	}
    174 
    175 /*****************************************************************************/
    176 
    177 real32 dng_gain_map_interpolator::InterpolateEntry (uint32 colIndex)
    178 	{
    179 
    180 	return fMap.Entry (fRowIndex1, colIndex, fPlane) * (1.0f - fRowFract) +
    181 		   fMap.Entry (fRowIndex2, colIndex, fPlane) * (       fRowFract);
    182 
    183 	}
    184 
    185 /*****************************************************************************/
    186 
    187 void dng_gain_map_interpolator::ResetColumn ()
    188 	{
    189 
    190 	real64 colIndexF = ((fScale.h * (fColumn + fOffset.h)) -
    191 						fMap.Origin ().h) / fMap.Spacing ().h;
    192 
    193 	if (colIndexF <= 0.0)
    194 		{
    195 
    196 		fValueBase = InterpolateEntry (0);
    197 
    198 		fValueStep = 0.0f;
    199 
    200 		fResetColumn = (int32) ceil (fMap.Origin ().h / fScale.h - fOffset.h);
    201 
    202 		}
    203 
    204 	else
    205 		{
    206 
    207 		if (fMap.Points ().h < 1)
    208 			{
    209 			ThrowProgramError ("Empty gain map");
    210 			}
    211 		uint32 lastCol = static_cast<uint32> (fMap.Points ().h - 1);
    212 
    213 		if (colIndexF >= static_cast<real64> (lastCol))
    214 			{
    215 
    216 			fValueBase = InterpolateEntry (lastCol);
    217 
    218 			fValueStep = 0.0f;
    219 
    220 			fResetColumn = 0x7FFFFFFF;
    221 
    222 			}
    223 
    224 		else
    225 			{
    226 
    227 			// If we got here, we know that colIndexF can safely be converted to
    228 			// a uint32 and that static_cast<uint32> (colIndexF) < lastCol. This
    229 			// implies colIndex + 1 <= lastCol, i.e. the argument to
    230 			// InterpolateEntry() below is valid.
    231 			uint32 colIndex = static_cast<uint32> (colIndexF);
    232 			real64 base  = InterpolateEntry (colIndex);
    233 			real64 delta = InterpolateEntry (colIndex + 1) - base;
    234 
    235 			fValueBase = (real32) (base + delta * (colIndexF - (real64) colIndex));
    236 
    237 			fValueStep = (real32) ((delta * fScale.h) / fMap.Spacing ().h);
    238 
    239 			fResetColumn = (int32) ceil (((colIndex + 1) * fMap.Spacing ().h +
    240 										  fMap.Origin ().h) / fScale.h - fOffset.h);
    241 
    242 			}
    243 
    244 		}
    245 
    246 	fValueIndex = 0.0f;
    247 
    248 	}
    249 
    250 /*****************************************************************************/
    251 
    252 dng_gain_map::dng_gain_map (dng_memory_allocator &allocator,
    253 							const dng_point &points,
    254 							const dng_point_real64 &spacing,
    255 							const dng_point_real64 &origin,
    256 							uint32 planes)
    257 
    258 	:	fPoints  (points)
    259 	,	fSpacing (spacing)
    260 	,	fOrigin  (origin)
    261 	,	fPlanes  (planes)
    262 
    263 	,	fRowStep (SafeUint32Mult(planes, points.h))
    264 
    265 	,	fBuffer ()
    266 
    267 	{
    268 
    269 	fBuffer.Reset (allocator.Allocate (
    270 		ComputeBufferSize (ttFloat, fPoints, fPlanes, pad16Bytes)));
    271 
    272 	}
    273 
    274 /*****************************************************************************/
    275 
    276 real32 dng_gain_map::Interpolate (int32 row,
    277 								  int32 col,
    278 								  uint32 plane,
    279 								  const dng_rect &bounds) const
    280 	{
    281 
    282 	dng_gain_map_interpolator interp (*this,
    283 									  bounds,
    284 									  row,
    285 									  col,
    286 									  plane);
    287 
    288 	return interp.Interpolate ();
    289 
    290 	}
    291 
    292 /*****************************************************************************/
    293 
    294 uint32 dng_gain_map::PutStreamSize () const
    295 	{
    296 
    297 	return 44 + fPoints.v * fPoints.h * fPlanes * 4;
    298 
    299 	}
    300 
    301 /*****************************************************************************/
    302 
    303 void dng_gain_map::PutStream (dng_stream &stream) const
    304 	{
    305 
    306 	stream.Put_uint32 (fPoints.v);
    307 	stream.Put_uint32 (fPoints.h);
    308 
    309 	stream.Put_real64 (fSpacing.v);
    310 	stream.Put_real64 (fSpacing.h);
    311 
    312 	stream.Put_real64 (fOrigin.v);
    313 	stream.Put_real64 (fOrigin.h);
    314 
    315 	stream.Put_uint32 (fPlanes);
    316 
    317 	for (int32 rowIndex = 0; rowIndex < fPoints.v; rowIndex++)
    318 		{
    319 
    320 		for (int32 colIndex = 0; colIndex < fPoints.h; colIndex++)
    321 			{
    322 
    323 			for (uint32 plane = 0; plane < fPlanes; plane++)
    324 				{
    325 
    326 				stream.Put_real32 (Entry (rowIndex,
    327 										  colIndex,
    328 										  plane));
    329 
    330 				}
    331 
    332 			}
    333 
    334 		}
    335 
    336 	}
    337 
    338 /*****************************************************************************/
    339 
    340 dng_gain_map * dng_gain_map::GetStream (dng_host &host,
    341 										dng_stream &stream)
    342 	{
    343 
    344 	dng_point mapPoints;
    345 
    346 	mapPoints.v = stream.Get_uint32 ();
    347 	mapPoints.h = stream.Get_uint32 ();
    348 
    349 	dng_point_real64 mapSpacing;
    350 
    351 	mapSpacing.v = stream.Get_real64 ();
    352 	mapSpacing.h = stream.Get_real64 ();
    353 
    354 	dng_point_real64 mapOrigin;
    355 
    356 	mapOrigin.v = stream.Get_real64 ();
    357 	mapOrigin.h = stream.Get_real64 ();
    358 
    359 	uint32 mapPlanes = stream.Get_uint32 ();
    360 
    361 	#if qDNGValidate
    362 
    363 	if (gVerbose)
    364 		{
    365 
    366 		printf ("Points: v=%d, h=%d\n",
    367 				(int) mapPoints.v,
    368 				(int) mapPoints.h);
    369 
    370 		printf ("Spacing: v=%.6f, h=%.6f\n",
    371 				mapSpacing.v,
    372 				mapSpacing.h);
    373 
    374 		printf ("Origin: v=%.6f, h=%.6f\n",
    375 				mapOrigin.v,
    376 				mapOrigin.h);
    377 
    378 		printf ("Planes: %u\n",
    379 				(unsigned) mapPlanes);
    380 
    381 		}
    382 
    383 	#endif
    384 
    385 	if (mapPoints.v == 1)
    386 		{
    387 		mapSpacing.v = 1.0;
    388 		mapOrigin.v  = 0.0;
    389 		}
    390 
    391 	if (mapPoints.h == 1)
    392 		{
    393 		mapSpacing.h = 1.0;
    394 		mapOrigin.h  = 0.0;
    395 		}
    396 
    397 	if (mapPoints.v < 1 ||
    398 		mapPoints.h < 1 ||
    399 		mapSpacing.v <= 0.0 ||
    400 		mapSpacing.h <= 0.0 ||
    401 		mapPlanes < 1)
    402 		{
    403 		ThrowBadFormat ();
    404 		}
    405 
    406 	AutoPtr<dng_gain_map> map (new dng_gain_map (host.Allocator (),
    407 												 mapPoints,
    408 												 mapSpacing,
    409 												 mapOrigin,
    410 												 mapPlanes));
    411 
    412 	#if qDNGValidate
    413 
    414 	uint32 linesPrinted = 0;
    415 	uint32 linesSkipped = 0;
    416 
    417 	#endif
    418 
    419 	for (int32 rowIndex = 0; rowIndex < mapPoints.v; rowIndex++)
    420 		{
    421 
    422 		for (int32 colIndex = 0; colIndex < mapPoints.h; colIndex++)
    423 			{
    424 
    425 			for (uint32 plane = 0; plane < mapPlanes; plane++)
    426 				{
    427 
    428 				real32 x = stream.Get_real32 ();
    429 
    430 				map->Entry (rowIndex, colIndex, plane) = x;
    431 
    432 				#if qDNGValidate
    433 
    434 				if (gVerbose)
    435 					{
    436 
    437 					if (linesPrinted < gDumpLineLimit)
    438 						{
    439 
    440 						printf ("    Map [%3u] [%3u] [%u] = %.4f\n",
    441 								(unsigned) rowIndex,
    442 								(unsigned) colIndex,
    443 								(unsigned) plane,
    444 								x);
    445 
    446 						linesPrinted++;
    447 
    448 						}
    449 
    450 					else
    451 						linesSkipped++;
    452 
    453 					}
    454 
    455 				#endif
    456 
    457 				}
    458 
    459 			}
    460 
    461 		}
    462 
    463 	#if qDNGValidate
    464 
    465 	if (linesSkipped)
    466 		{
    467 
    468 		printf ("    ... %u map entries skipped\n", (unsigned) linesSkipped);
    469 
    470 		}
    471 
    472 	#endif
    473 
    474 	return map.Release ();
    475 
    476 	}
    477 
    478 /*****************************************************************************/
    479 
    480 dng_opcode_GainMap::dng_opcode_GainMap (const dng_area_spec &areaSpec,
    481 										AutoPtr<dng_gain_map> &gainMap)
    482 
    483 	:	dng_inplace_opcode (dngOpcode_GainMap,
    484 						    dngVersion_1_3_0_0,
    485 						    kFlag_None)
    486 
    487 	,	fAreaSpec (areaSpec)
    488 
    489 	,	fGainMap ()
    490 
    491 	{
    492 
    493 	fGainMap.Reset (gainMap.Release ());
    494 
    495 	}
    496 
    497 /*****************************************************************************/
    498 
    499 dng_opcode_GainMap::dng_opcode_GainMap (dng_host &host,
    500 										dng_stream &stream)
    501 
    502 	:	dng_inplace_opcode (dngOpcode_GainMap,
    503 							stream,
    504 							"GainMap")
    505 
    506 	,	fAreaSpec ()
    507 
    508 	,	fGainMap ()
    509 
    510 	{
    511 
    512 	uint32 byteCount = stream.Get_uint32 ();
    513 
    514 	uint64 startPosition = stream.Position ();
    515 
    516 	fAreaSpec.GetData (stream);
    517 
    518 	fGainMap.Reset (dng_gain_map::GetStream (host, stream));
    519 
    520 	if (stream.Position () != startPosition + byteCount)
    521 		{
    522 		ThrowBadFormat ();
    523 		}
    524 
    525 	}
    526 
    527 /*****************************************************************************/
    528 
    529 void dng_opcode_GainMap::PutData (dng_stream &stream) const
    530 	{
    531 
    532 	stream.Put_uint32 (dng_area_spec::kDataSize +
    533 					   fGainMap->PutStreamSize ());
    534 
    535 	fAreaSpec.PutData (stream);
    536 
    537 	fGainMap->PutStream (stream);
    538 
    539 	}
    540 
    541 /*****************************************************************************/
    542 
    543 void dng_opcode_GainMap::ProcessArea (dng_negative & /* negative */,
    544 									  uint32 /* threadIndex */,
    545 									  dng_pixel_buffer &buffer,
    546 									  const dng_rect &dstArea,
    547 									  const dng_rect &imageBounds)
    548 	{
    549 
    550 	dng_rect overlap = fAreaSpec.Overlap (dstArea);
    551 
    552 	if (overlap.NotEmpty ())
    553 		{
    554 
    555 		uint32 cols = overlap.W ();
    556 
    557 		uint32 colPitch = fAreaSpec.ColPitch ();
    558 
    559 		for (uint32 plane = fAreaSpec.Plane ();
    560 			 plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
    561 			 plane < buffer.Planes ();
    562 			 plane++)
    563 			{
    564 
    565 			uint32 mapPlane = Min_uint32 (plane, fGainMap->Planes () - 1);
    566 
    567 			for (int32 row = overlap.t; row < overlap.b; row += fAreaSpec.RowPitch ())
    568 				{
    569 
    570 				real32 *dPtr = buffer.DirtyPixel_real32 (row, overlap.l, plane);
    571 
    572 				dng_gain_map_interpolator interp (*fGainMap,
    573 												  imageBounds,
    574 												  row,
    575 												  overlap.l,
    576 												  mapPlane);
    577 
    578 				for (uint32 col = 0; col < cols; col += colPitch)
    579 					{
    580 
    581 					real32 gain = interp.Interpolate ();
    582 
    583 					dPtr [col] = Min_real32 (dPtr [col] * gain, 1.0f);
    584 
    585 					for (uint32 j = 0; j < colPitch; j++)
    586 						{
    587 						interp.Increment ();
    588 						}
    589 
    590 					}
    591 
    592 				}
    593 
    594 			}
    595 
    596 		}
    597 
    598 	}
    599 
    600 /*****************************************************************************/
    601