Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F62725549
rgbecontrib.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Wed, May 15, 04:15
Size
9 KB
Mime Type
text/x-c
Expires
Fri, May 17, 04:15 (2 d)
Engine
blob
Format
Raw Data
Handle
17681600
Attached To
R10977 RADIANCE Photon Map
rgbecontrib.c
View Options
/*
=========================================================================
Routines to encode/decode RGBE representation of normalised binned
contributions. See rgbecontrib.h for encoding details.
Compile with -D_RGBE_CONTRIB_TEST to enable unit test (requires libm)
Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
(c) Lucerne University of Applied Sciences and Arts,
supported by the Swiss National Science Foundation
(SNSF #179067, "Light Fields for Spatio-Temporal Glare Assessment")
=========================================================================
$Id$
*/
#include "rgbecontrib.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
RGBEContrib
RGBEContribEnc
(
double
rgb
[
3
],
double
norm
[
3
],
unsigned
bin
)
/* Normalise signed float RGB contributions against abs(norm), and encode
* to RGBE with associated bin. Issues warning if norm < abs(rgb). */
{
#define sgn(a) ((a) >= 0 ? 1.0 : -1.0)
double
rgbNorm
[
3
],
mantNorm
;
int
i
,
exp
;
RGBEContrib
rgbeCont
=
{
0
,
0
,
0
,
0
};
/* Check and set bin */
if
(
bin
>
RGBE_CONTRIB_BINMAX
)
{
fprintf
(
stderr
,
"WARNING - RGBEContrib bin overflow
\n
"
);
return
rgbeCont
;
}
else
rgbeCont
.
bin
=
bin
;
/* Normalise RGB. */
for
(
i
=
0
;
i
<
3
;
i
++
)
if
(
norm
[
i
]
==
0
)
{
fprintf
(
stderr
,
"WARNING - Zero RGBEContrib normalisation
\n
"
);
return
rgbeCont
;
}
else
{
rgbNorm
[
i
]
=
rgb
[
i
]
/
norm
[
i
];
if
(
fabs
(
fabs
(
rgbNorm
[
i
])
-
1
)
<
RGBE_CONTRIB_MIN
)
/* Normalisation to 1. This must be avoided by offsetting by
minimum value, otherwise frexp() returns a positive exponent.
Normalisation to >1 is caught by overflow check below */
rgbNorm
[
i
]
=
sgn
(
rgbNorm
[
i
])
*
(
1
-
RGBE_CONTRIB_MIN
);
}
/* Mantissa normalisation factor (= RGB maximum) */
mantNorm
=
max
(
max
(
fabs
(
rgbNorm
[
0
]),
fabs
(
rgbNorm
[
1
])),
fabs
(
rgbNorm
[
2
])
);
/* Check RGB range */
if
(
mantNorm
<
RGBE_CONTRIB_MIN
)
{
/* Below encoding range, clamp to zero */
fprintf
(
stderr
,
"WARNING - RGBEContrib underflow, clamping to 0
\n
"
);
return
rgbeCont
;
}
if
(
mantNorm
>
RGBE_CONTRIB_MAX
)
{
/* Exceeds encoding range, clamp to maximum */
fprintf
(
stderr
,
"WARNING - RGBEContrib overflow, clamping to +/-%.1f
\n
"
,
RGBE_CONTRIB_MAX
);
rgbeCont
.
red
=
(
1
+
sgn
(
rgbNorm
[
0
]))
*
RGBE_CONTRIB_MANTMAX
+
0.5
;
rgbeCont
.
grn
=
(
1
+
sgn
(
rgbNorm
[
1
]))
*
RGBE_CONTRIB_MANTMAX
+
0.5
;
rgbeCont
.
blu
=
(
1
+
sgn
(
rgbNorm
[
2
]))
*
RGBE_CONTRIB_MANTMAX
+
0.5
;
return
rgbeCont
;
}
/* Get normalised mantissa and exponent to base 2 */
mantNorm
=
frexp
(
mantNorm
,
&
exp
)
*
RGBE_CONTRIB_MANTMAX
/
mantNorm
;
/* Set RGB integer mantissas, adding excess (zero offset) and rounding
up or down, depending on sign. Clamp to RGBE_CONTRIB_MANTOVF to
prevent rounding beyond overflow into negative! */
rgbeCont
.
red
=
min
(
(
int
)(
rgbNorm
[
0
]
*
mantNorm
+
RGBE_CONTRIB_MANTMAX
+
0.5
),
RGBE_CONTRIB_MANTOVF
);
rgbeCont
.
grn
=
min
(
(
int
)(
rgbNorm
[
1
]
*
mantNorm
+
RGBE_CONTRIB_MANTMAX
+
0.5
),
RGBE_CONTRIB_MANTOVF
);
rgbeCont
.
blu
=
min
(
(
int
)(
rgbNorm
[
2
]
*
mantNorm
+
RGBE_CONTRIB_MANTMAX
+
0.5
),
RGBE_CONTRIB_MANTOVF
);
/* Drop the exponent sign, since implicitly negative */
rgbeCont
.
exp
=
abs
(
exp
);
return
rgbeCont
;
#undef sgn
}
unsigned
RGBEContribDec
(
RGBEContrib
rgbeCont
,
double
norm
[
3
],
double
rgb
[
3
]
)
/* Decode RGBE contribution, returning signed floating point contributions
* in array rgb after denormalisation against norm, and the associated
* bin as return value. */
{
#
define
sgn
(
a
)
((
a
)
>=
RGBE_CONTRIB_MANTMAX
?
0.1
:
-
0.1
)
/* Mantissa normalisation factor; exponent implicitly negative */
const
double
mantNorm
=
ldexp
(
1.0
,
-
rgbeCont
.
exp
)
/
RGBE_CONTRIB_MANTMAX
;
/* Decode and set RGB components, subtracting excess (zero offset) and
* adding some jitter to break up quantisation artefacts.
* Clamp to -RGBE_CONTRIB_MAX (-1) in case jitter underflows.
* Denormalise to original range with user-specified factor. */
rgb
[
0
]
=
norm
[
0
]
*
max
(
mantNorm
*
(
rgbeCont
.
red
-
RGBE_CONTRIB_MANTMAX
+
drand48
()
*
sgn
(
rgbeCont
.
red
)
),
-
RGBE_CONTRIB_MAX
);
rgb
[
1
]
=
norm
[
1
]
*
max
(
mantNorm
*
(
rgbeCont
.
grn
-
RGBE_CONTRIB_MANTMAX
+
drand48
()
*
sgn
(
rgbeCont
.
grn
)
),
-
RGBE_CONTRIB_MAX
);
rgb
[
2
]
=
norm
[
2
]
*
max
(
mantNorm
*
(
rgbeCont
.
blu
-
RGBE_CONTRIB_MANTMAX
+
drand48
()
*
sgn
(
rgbeCont
.
blu
)
),
-
RGBE_CONTRIB_MAX
);
/* Return bin */
return
rgbeCont
.
bin
;
#undef sgn
}
#ifdef _RGBE_CONTRIB_TEST
/* Build standalone to run unit test */
#define RGBMAX 1
int
main
(
int
argc
,
char
**
argv
)
{
double
rgb
[
3
]
=
{
0
,
0
,
0
},
rgbDec
[
3
],
rgbNorm
[
3
]
=
{
0
,
0
,
0
},
relDiff
,
rmse
,
rmseSum
;
const
short
rndState0
[
3
]
=
{
11
,
23
,
31
};
short
encFlag
=
0
,
rndState
[
3
];
unsigned
numTests
,
i
,
j
,
k
,
bin
,
binDec
;
RGBEContrib
rgbeCont
;
/* Test range checks */
puts
(
"Check bin overflow"
);
RGBEContribEnc
(
rgb
,
rgbNorm
,
RGBE_CONTRIB_BINMAX
<<
1
);
puts
(
"
\n
Check zero normalisation"
);
RGBEContribEnc
(
rgb
,
rgbNorm
,
0
);
puts
(
"
\n
Check underflow"
);
rgbNorm
[
0
]
=
rgbNorm
[
1
]
=
rgbNorm
[
2
]
=
1
;
rgb
[
0
]
=
RGBE_CONTRIB_MIN
/
2
;
RGBEContribEnc
(
rgb
,
rgbNorm
,
0
);
puts
(
"
\n
Check overflow (positive)"
);
rgb
[
0
]
=
2
;
RGBEContribEnc
(
rgb
,
rgbNorm
,
0
);
puts
(
"
\n
Check overflow (negative)"
);
rgb
[
0
]
=
-
2
;
RGBEContribEnc
(
rgb
,
rgbNorm
,
0
);
putchar
(
'\n'
);
if
(
argc
>
1
&&
(
numTests
=
atoi
(
argv
[
1
]))
>
0
)
{
rgbNorm
[
0
]
=
rgbNorm
[
1
]
=
rgbNorm
[
2
]
=
0
;
/* Iterate twice with same random RGB tuples; gather normalisation
factors in 1st pass, then do actual encode/decode tests using
found normalisation in 2nd pass. */
do
{
/* Initialise RNG state so this can be restored to obtain the
same RGB tuple sequence in both passes. This state needs to
be kept separate from the RNG used for jittering in the
encode/decode routines. */
for
(
i
=
0
;
i
<
3
;
i
++
)
rndState
[
i
]
=
rndState0
[
i
];
/* Random encode vs. decode */
for
(
k
=
0
,
rmseSum
=
0
;
k
<
numTests
;
k
++
)
{
bin
=
(
unsigned
)(
RGBE_CONTRIB_BINMAX
*
erand48
(
rndState
));
#if 1
for
(
i
=
0
;
i
<
3
;
i
++
)
{
if
(
i
>
0
)
/* Correlate RGB */
rgb
[
i
]
=
rgb
[
0
]
*
(
0.1
+
0.9
*
erand48
(
rndState
));
else
rgb
[
i
]
=
RGBMAX
*
(
2
*
erand48
(
rndState
)
-
1
);
}
#else
#if 1
rgb
[
0
]
=
rgb
[
1
]
=
rgb
[
2
]
=
RGBMAX
*
(
2
*
erand48
(
rndState
)
-
1
);
#else
rgb
[
0
]
=
0.9772
;
rgb
[
1
]
=
0.4369
;
rgb
[
2
]
=
0.1869
;
#endif
#endif
if
(
encFlag
)
{
/* Encode */
/*
rgb [0] = rgbNorm [0];
rgb [1] = 0.0077;
rgb [2] = 0.0058;
*/
rgbeCont
=
RGBEContribEnc
(
rgb
,
rgbNorm
,
bin
);
printf
(
"% 7.4f
\t
% 7.4f
\t
% 7.4f
\t
%4d
\t
-->
\t
"
"%02d:%02d:%02d:%02d
\t
-->
\t
"
,
rgb
[
0
],
rgb
[
1
],
rgb
[
2
],
bin
,
rgbeCont
.
red
,
rgbeCont
.
grn
,
rgbeCont
.
blu
,
rgbeCont
.
exp
);
/* Decode */
binDec
=
RGBEContribDec
(
rgbeCont
,
rgbNorm
,
rgbDec
);
for
(
j
=
rmse
=
0
;
j
<
3
;
j
++
)
{
relDiff
=
1
-
rgbDec
[
j
]
/
rgb
[
j
];
rmse
+=
relDiff
*
relDiff
;
}
rmseSum
+=
rmse
=
sqrt
(
rmse
/
3
);
printf
(
"% 7.4f
\t
% 7.4f
\t
% 7.4f
\t
%4d
\t
RMSE = %.1f%%
\n
"
,
rgbDec
[
0
],
rgbDec
[
1
],
rgbDec
[
2
],
binDec
,
100
*
rmse
);
}
else
{
/* Update RGB normalisation factor */
for
(
i
=
0
;
i
<
3
;
i
++
)
if
(
fabs
(
rgb
[
i
])
>
rgbNorm
[
i
])
rgbNorm
[
i
]
=
fabs
(
rgb
[
i
]);
}
}
/* Dump results */
if
(
!
encFlag
)
printf
(
"RGB Normalisation = (%.3f, %.3f, %.3f)
\n\n
"
,
rgbNorm
[
0
],
rgbNorm
[
1
],
rgbNorm
[
2
]
);
else
printf
(
"
\n
Avg RMSE = %.1f%%
\n
"
,
100
*
rmseSum
/
numTests
);
}
while
(
encFlag
=
!
encFlag
);
}
return
0
;
}
#endif
Event Timeline
Log In to Comment