/src/dng_sdk/source/dng_gain_map.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 0 | { |
61 | | |
62 | 0 | return fValueBase + fValueStep * fValueIndex; |
63 | | |
64 | 0 | } |
65 | | |
66 | | void Increment () |
67 | 0 | { |
68 | | |
69 | 0 | if (++fColumn >= fResetColumn) |
70 | 0 | { |
71 | | |
72 | 0 | ResetColumn (); |
73 | | |
74 | 0 | } |
75 | | |
76 | 0 | else |
77 | 0 | { |
78 | | |
79 | 0 | fValueIndex += 1.0f; |
80 | | |
81 | 0 | } |
82 | | |
83 | 0 | } |
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 | 0 | : fMap (map) |
102 | | |
103 | 0 | , fScale (1.0 / mapBounds.H (), |
104 | 0 | 1.0 / mapBounds.W ()) |
105 | | |
106 | 0 | , fOffset (0.5 - mapBounds.t, |
107 | 0 | 0.5 - mapBounds.l) |
108 | | |
109 | 0 | , fColumn (column) |
110 | 0 | , fPlane (plane) |
111 | | |
112 | 0 | , fRowIndex1 (0) |
113 | 0 | , fRowIndex2 (0) |
114 | 0 | , fRowFract (0.0f) |
115 | | |
116 | 0 | , fResetColumn (0) |
117 | | |
118 | 0 | , fValueBase (0.0f) |
119 | 0 | , fValueStep (0.0f) |
120 | 0 | , fValueIndex (0.0f) |
121 | | |
122 | 0 | { |
123 | | |
124 | 0 | real64 rowIndexF = (fScale.v * (row + fOffset.v) - |
125 | 0 | fMap.Origin ().v) / fMap.Spacing ().v; |
126 | | |
127 | 0 | if (rowIndexF <= 0.0) |
128 | 0 | { |
129 | | |
130 | 0 | fRowIndex1 = 0; |
131 | 0 | fRowIndex2 = 0; |
132 | | |
133 | 0 | fRowFract = 0.0f; |
134 | |
|
135 | 0 | } |
136 | | |
137 | 0 | else |
138 | 0 | { |
139 | | |
140 | 0 | if (fMap.Points ().v < 1) |
141 | 0 | { |
142 | 0 | ThrowProgramError ("Empty gain map"); |
143 | 0 | } |
144 | 0 | uint32 lastRow = static_cast<uint32> (fMap.Points ().v - 1); |
145 | | |
146 | 0 | if (rowIndexF >= static_cast<real64> (lastRow)) |
147 | 0 | { |
148 | | |
149 | 0 | fRowIndex1 = lastRow; |
150 | 0 | fRowIndex2 = fRowIndex1; |
151 | | |
152 | 0 | fRowFract = 0.0f; |
153 | | |
154 | 0 | } |
155 | | |
156 | 0 | else |
157 | 0 | { |
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 | 0 | fRowIndex1 = static_cast<uint32> (rowIndexF); |
163 | 0 | fRowIndex2 = fRowIndex1 + 1; |
164 | | |
165 | 0 | fRowFract = (real32) (rowIndexF - (real64) fRowIndex1); |
166 | | |
167 | 0 | } |
168 | | |
169 | 0 | } |
170 | | |
171 | 0 | ResetColumn (); |
172 | | |
173 | 0 | } |
174 | | |
175 | | /*****************************************************************************/ |
176 | | |
177 | | real32 dng_gain_map_interpolator::InterpolateEntry (uint32 colIndex) |
178 | 0 | { |
179 | | |
180 | 0 | return fMap.Entry (fRowIndex1, colIndex, fPlane) * (1.0f - fRowFract) + |
181 | 0 | fMap.Entry (fRowIndex2, colIndex, fPlane) * ( fRowFract); |
182 | | |
183 | 0 | } |
184 | | |
185 | | /*****************************************************************************/ |
186 | | |
187 | | void dng_gain_map_interpolator::ResetColumn () |
188 | 0 | { |
189 | | |
190 | 0 | real64 colIndexF = ((fScale.h * (fColumn + fOffset.h)) - |
191 | 0 | fMap.Origin ().h) / fMap.Spacing ().h; |
192 | | |
193 | 0 | if (colIndexF <= 0.0) |
194 | 0 | { |
195 | | |
196 | 0 | fValueBase = InterpolateEntry (0); |
197 | | |
198 | 0 | fValueStep = 0.0f; |
199 | | |
200 | 0 | fResetColumn = (int32) ceil (fMap.Origin ().h / fScale.h - fOffset.h); |
201 | |
|
202 | 0 | } |
203 | | |
204 | 0 | else |
205 | 0 | { |
206 | | |
207 | 0 | if (fMap.Points ().h < 1) |
208 | 0 | { |
209 | 0 | ThrowProgramError ("Empty gain map"); |
210 | 0 | } |
211 | 0 | uint32 lastCol = static_cast<uint32> (fMap.Points ().h - 1); |
212 | | |
213 | 0 | if (colIndexF >= static_cast<real64> (lastCol)) |
214 | 0 | { |
215 | | |
216 | 0 | fValueBase = InterpolateEntry (lastCol); |
217 | | |
218 | 0 | fValueStep = 0.0f; |
219 | | |
220 | 0 | fResetColumn = 0x7FFFFFFF; |
221 | | |
222 | 0 | } |
223 | | |
224 | 0 | else |
225 | 0 | { |
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 | 0 | uint32 colIndex = static_cast<uint32> (colIndexF); |
232 | 0 | real64 base = InterpolateEntry (colIndex); |
233 | 0 | real64 delta = InterpolateEntry (colIndex + 1) - base; |
234 | | |
235 | 0 | fValueBase = (real32) (base + delta * (colIndexF - (real64) colIndex)); |
236 | | |
237 | 0 | fValueStep = (real32) ((delta * fScale.h) / fMap.Spacing ().h); |
238 | | |
239 | 0 | fResetColumn = (int32) ceil (((colIndex + 1) * fMap.Spacing ().h + |
240 | 0 | fMap.Origin ().h) / fScale.h - fOffset.h); |
241 | | |
242 | 0 | } |
243 | | |
244 | 0 | } |
245 | | |
246 | 0 | fValueIndex = 0.0f; |
247 | | |
248 | 0 | } |
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 | 406 | : fPoints (points) |
259 | 406 | , fSpacing (spacing) |
260 | 406 | , fOrigin (origin) |
261 | 406 | , fPlanes (planes) |
262 | | |
263 | 406 | , fRowStep (SafeUint32Mult(planes, points.h)) |
264 | | |
265 | 406 | , fBuffer () |
266 | | |
267 | 406 | { |
268 | | |
269 | 406 | fBuffer.Reset (allocator.Allocate ( |
270 | 406 | ComputeBufferSize (ttFloat, fPoints, fPlanes, pad16Bytes))); |
271 | | |
272 | 406 | } |
273 | | |
274 | | /*****************************************************************************/ |
275 | | |
276 | | real32 dng_gain_map::Interpolate (int32 row, |
277 | | int32 col, |
278 | | uint32 plane, |
279 | | const dng_rect &bounds) const |
280 | 0 | { |
281 | | |
282 | 0 | dng_gain_map_interpolator interp (*this, |
283 | 0 | bounds, |
284 | 0 | row, |
285 | 0 | col, |
286 | 0 | plane); |
287 | | |
288 | 0 | return interp.Interpolate (); |
289 | | |
290 | 0 | } |
291 | | |
292 | | /*****************************************************************************/ |
293 | | |
294 | | uint32 dng_gain_map::PutStreamSize () const |
295 | 0 | { |
296 | | |
297 | 0 | return 44 + fPoints.v * fPoints.h * fPlanes * 4; |
298 | | |
299 | 0 | } |
300 | | |
301 | | /*****************************************************************************/ |
302 | | |
303 | | void dng_gain_map::PutStream (dng_stream &stream) const |
304 | 0 | { |
305 | | |
306 | 0 | stream.Put_uint32 (fPoints.v); |
307 | 0 | stream.Put_uint32 (fPoints.h); |
308 | | |
309 | 0 | stream.Put_real64 (fSpacing.v); |
310 | 0 | stream.Put_real64 (fSpacing.h); |
311 | | |
312 | 0 | stream.Put_real64 (fOrigin.v); |
313 | 0 | stream.Put_real64 (fOrigin.h); |
314 | | |
315 | 0 | stream.Put_uint32 (fPlanes); |
316 | | |
317 | 0 | for (int32 rowIndex = 0; rowIndex < fPoints.v; rowIndex++) |
318 | 0 | { |
319 | | |
320 | 0 | for (int32 colIndex = 0; colIndex < fPoints.h; colIndex++) |
321 | 0 | { |
322 | | |
323 | 0 | for (uint32 plane = 0; plane < fPlanes; plane++) |
324 | 0 | { |
325 | | |
326 | 0 | stream.Put_real32 (Entry (rowIndex, |
327 | 0 | colIndex, |
328 | 0 | plane)); |
329 | | |
330 | 0 | } |
331 | | |
332 | 0 | } |
333 | | |
334 | 0 | } |
335 | | |
336 | 0 | } |
337 | | |
338 | | /*****************************************************************************/ |
339 | | |
340 | | dng_gain_map * dng_gain_map::GetStream (dng_host &host, |
341 | | dng_stream &stream) |
342 | 699 | { |
343 | | |
344 | 699 | dng_point mapPoints; |
345 | | |
346 | 699 | mapPoints.v = stream.Get_uint32 (); |
347 | 699 | mapPoints.h = stream.Get_uint32 (); |
348 | | |
349 | 699 | dng_point_real64 mapSpacing; |
350 | | |
351 | 699 | mapSpacing.v = stream.Get_real64 (); |
352 | 699 | mapSpacing.h = stream.Get_real64 (); |
353 | | |
354 | 699 | dng_point_real64 mapOrigin; |
355 | | |
356 | 699 | mapOrigin.v = stream.Get_real64 (); |
357 | 699 | mapOrigin.h = stream.Get_real64 (); |
358 | | |
359 | 699 | 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 | 699 | if (mapPoints.v == 1) |
386 | 47 | { |
387 | 47 | mapSpacing.v = 1.0; |
388 | 47 | mapOrigin.v = 0.0; |
389 | 47 | } |
390 | | |
391 | 699 | if (mapPoints.h == 1) |
392 | 77 | { |
393 | 77 | mapSpacing.h = 1.0; |
394 | 77 | mapOrigin.h = 0.0; |
395 | 77 | } |
396 | | |
397 | 699 | if (mapPoints.v < 1 || |
398 | 699 | mapPoints.h < 1 || |
399 | 699 | mapSpacing.v <= 0.0 || |
400 | 699 | mapSpacing.h <= 0.0 || |
401 | 699 | mapPlanes < 1) |
402 | 263 | { |
403 | 263 | ThrowBadFormat (); |
404 | 263 | } |
405 | | |
406 | 699 | AutoPtr<dng_gain_map> map (new dng_gain_map (host.Allocator (), |
407 | 699 | mapPoints, |
408 | 699 | mapSpacing, |
409 | 699 | mapOrigin, |
410 | 699 | mapPlanes)); |
411 | | |
412 | | #if qDNGValidate |
413 | | |
414 | | uint32 linesPrinted = 0; |
415 | | uint32 linesSkipped = 0; |
416 | | |
417 | | #endif |
418 | | |
419 | 4.48k | for (int32 rowIndex = 0; rowIndex < mapPoints.v; rowIndex++) |
420 | 3.78k | { |
421 | | |
422 | 9.98k | for (int32 colIndex = 0; colIndex < mapPoints.h; colIndex++) |
423 | 6.20k | { |
424 | | |
425 | 19.6k | for (uint32 plane = 0; plane < mapPlanes; plane++) |
426 | 13.4k | { |
427 | | |
428 | 13.4k | real32 x = stream.Get_real32 (); |
429 | | |
430 | 13.4k | 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 | 13.4k | } |
458 | | |
459 | 6.20k | } |
460 | | |
461 | 3.78k | } |
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 | 699 | return map.Release (); |
475 | | |
476 | 699 | } |
477 | | |
478 | | /*****************************************************************************/ |
479 | | |
480 | | dng_opcode_GainMap::dng_opcode_GainMap (const dng_area_spec &areaSpec, |
481 | | AutoPtr<dng_gain_map> &gainMap) |
482 | | |
483 | 0 | : dng_inplace_opcode (dngOpcode_GainMap, |
484 | 0 | dngVersion_1_3_0_0, |
485 | 0 | kFlag_None) |
486 | | |
487 | 0 | , fAreaSpec (areaSpec) |
488 | | |
489 | 0 | , fGainMap () |
490 | | |
491 | 0 | { |
492 | | |
493 | 0 | fGainMap.Reset (gainMap.Release ()); |
494 | | |
495 | 0 | } |
496 | | |
497 | | /*****************************************************************************/ |
498 | | |
499 | | dng_opcode_GainMap::dng_opcode_GainMap (dng_host &host, |
500 | | dng_stream &stream) |
501 | | |
502 | 1.14k | : dng_inplace_opcode (dngOpcode_GainMap, |
503 | 1.14k | stream, |
504 | 1.14k | "GainMap") |
505 | | |
506 | 1.14k | , fAreaSpec () |
507 | | |
508 | 1.14k | , fGainMap () |
509 | | |
510 | 1.14k | { |
511 | | |
512 | 1.14k | uint32 byteCount = stream.Get_uint32 (); |
513 | | |
514 | 1.14k | uint64 startPosition = stream.Position (); |
515 | | |
516 | 1.14k | fAreaSpec.GetData (stream); |
517 | | |
518 | 1.14k | fGainMap.Reset (dng_gain_map::GetStream (host, stream)); |
519 | | |
520 | 1.14k | if (stream.Position () != startPosition + byteCount) |
521 | 29 | { |
522 | 29 | ThrowBadFormat (); |
523 | 29 | } |
524 | | |
525 | 1.14k | } |
526 | | |
527 | | /*****************************************************************************/ |
528 | | |
529 | | void dng_opcode_GainMap::PutData (dng_stream &stream) const |
530 | 0 | { |
531 | | |
532 | 0 | stream.Put_uint32 (dng_area_spec::kDataSize + |
533 | 0 | fGainMap->PutStreamSize ()); |
534 | | |
535 | 0 | fAreaSpec.PutData (stream); |
536 | | |
537 | 0 | fGainMap->PutStream (stream); |
538 | | |
539 | 0 | } |
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 | 0 | { |
549 | | |
550 | 0 | dng_rect overlap = fAreaSpec.Overlap (dstArea); |
551 | | |
552 | 0 | if (overlap.NotEmpty ()) |
553 | 0 | { |
554 | | |
555 | 0 | uint32 cols = overlap.W (); |
556 | | |
557 | 0 | uint32 colPitch = fAreaSpec.ColPitch (); |
558 | | |
559 | 0 | for (uint32 plane = fAreaSpec.Plane (); |
560 | 0 | plane < fAreaSpec.Plane () + fAreaSpec.Planes () && |
561 | 0 | plane < buffer.Planes (); |
562 | 0 | plane++) |
563 | 0 | { |
564 | | |
565 | 0 | uint32 mapPlane = Min_uint32 (plane, fGainMap->Planes () - 1); |
566 | | |
567 | 0 | for (int32 row = overlap.t; row < overlap.b; row += fAreaSpec.RowPitch ()) |
568 | 0 | { |
569 | | |
570 | 0 | real32 *dPtr = buffer.DirtyPixel_real32 (row, overlap.l, plane); |
571 | | |
572 | 0 | dng_gain_map_interpolator interp (*fGainMap, |
573 | 0 | imageBounds, |
574 | 0 | row, |
575 | 0 | overlap.l, |
576 | 0 | mapPlane); |
577 | | |
578 | 0 | for (uint32 col = 0; col < cols; col += colPitch) |
579 | 0 | { |
580 | | |
581 | 0 | real32 gain = interp.Interpolate (); |
582 | | |
583 | 0 | dPtr [col] = Min_real32 (dPtr [col] * gain, 1.0f); |
584 | | |
585 | 0 | for (uint32 j = 0; j < colPitch; j++) |
586 | 0 | { |
587 | 0 | interp.Increment (); |
588 | 0 | } |
589 | | |
590 | 0 | } |
591 | | |
592 | 0 | } |
593 | | |
594 | 0 | } |
595 | | |
596 | 0 | } |
597 | |
|
598 | 0 | } |
599 | | |
600 | | /*****************************************************************************/ |