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 | |