Thank you. It makes a lot of sense.
I completely forgot about discarding alpha channel. Also, I'm using half format
so in my specific case I should have used half instead of float in the iterator
constructor.
For future reference, here's the working code:
void
ImageLoader
::
normalize
(
OIIO
::
ImageBuf
*
image
)
{
using
namespace
OIIO
;
auto
stats
=
ImageBufAlgo
::
computePixelStats
(*
image
);
auto
min
=
0.0f
;
auto
max
=
0.0f
;
auto
nc
=
std
::
min
(
3
,
image
->
nchannels
());
for
(
auto
c
=
0
;
c
<
nc
;
++
c
)
{
min
=
std
::
min
(
min
,
stats
.
min
[
c
]
);
max
=
std
::
max
(
max
,
stats
.
max
[
c
]
);
}
auto
roi
=
image
->
roi
();
roi
.
chend
=
nc
;
ImageBufAlgo
::
contrast_remap
(*
image
,
*
image
,
min
,
max
,
0.0f
,
1.0f
,
1.0
,
0.5f
,
roi
);
}
‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
On Thursday, 28 November 2019 02:32, Larry Gritz <[email protected]> wrote:
> To clarify: I believe that the contrast_remap function is new in OIIO 2.1. On
> older versions, or merely if you prefer it, I think you could achieve the
> same thing with
>
> ImageBufAlgo::sub(*image, *image, min, roi);
> ImageBufAlgo::mul(*image, *image, (max-min), roi);
>
> Note also that this whole business of passing the roi explicitly is to limit
> the pixel alterations to just the first 3 channels. You almost surely don't
> want to scale the alpha values or any additional channels.
>
>> On Nov 27, 2019, at 5:27 PM, Larry Gritz <[email protected]> wrote:
>>
>> In what way doesn't it work properly? Does it crash? Appear to do nothing?
>> Do something but not what you expect? What kind of image are you trying (I
>> mean, what data type and channels)?
>>
>> I can only speak in generalities without this info, but here's what I
>> spotted as likely problems.
>>
>> * ConstIterator/Iterator<float> is likely to be problematic, because it
>> requires the buffer itself to be float. (Is it?) Usually we write a function
>> like your normalize as a template and then have a big switch statement that
>> selects a specialized variety based on the data type. (This may not really
>> be a problem if all of your images are stored as 'float' buffers internally.)
>>
>> * You initialized 'min' (why are these half?) to 0.0, which means that "if
>> (it[c] < min)" will probably never be true (unless you have negative
>> values), so it probably is not going to compute the correct minimum. A
>> better way to compute min/max would be:
>>
>> float min = 1e6f;
>> float max = -1e6f;
>> ...
>> for (int c = 0; c < nchannels; ++c) {
>> min = std::min(max, it[c]);
>> max = std::max(max, it[c]);
>> }
>>
>> * Depending on your image, you may also find that scaling all channels based
>> on the biggest min/max may be wrong, particularly if it has any non-color
>> chanels like alpha or Z.
>>
>> So OIIO 2.1 (a release candidate now, scheduled to be the official supported
>> release in 3 days!) has a function that does everything you want. Assuming
>> you're able to use that, here's how I recommend doing this operation
>> robustly (this is off the top of my head, I have not tested, so take with a
>> grain of salt, but this is the basic idea):
>>
>> ImageBufAlgo::PixelStats stats = ImageBufAlgo::computePixelStats(*image);
>> float min = 1e6f;
>> float max = -1e6f;
>> int nc = std::min (3, image->nchannels()); // only consider R,G,B
>> for (int c = 0; c < nc; ++c) {
>> min = std::min(max, stats.min[c]);
>> max = std::max(max, stats.max[c]);
>> }
>> ROI roi = image->roi();
>> roi.chend = 3; // only rescale at most the first three channels!
>> ImageBufAlgo::contrast_remap(*image, *image, min, max, 0.0f, 1.0f, 1.0,
>> 0.5, roi);
>>
>> Using IBA::computePixelStats and contrast_remap has two big advantages over
>> writing the loops yourself: (1) it handles every data type that OIIO
>> supports, not just float; and (2) will go much faster because internally
>> it's multithreaded!
>>
>>> On Nov 27, 2019, at 4:31 PM, Chris Dawlud <[email protected]> wrote:
>>>
>>> Hi,
>>>
>>> I want to normalize exr to make even very bright/dark images visible.
>>> The idea is simple but I can't figure out how to do this correctly.
>>>
>>> I have come up with the following, but it doesn't work properly:
>>>
>>> void
>>>
>>>
>>>
>>> ImageLoader
>>>
>>> ::
>>>
>>> normalize
>>>
>>> (
>>>
>>> OIIO
>>>
>>> ::
>>>
>>> ImageBuf
>>>
>>> *
>>>
>>>
>>>
>>> image
>>>
>>> )
>>>
>>> {
>>>
>>> using
>>>
>>>
>>>
>>> namespace
>>>
>>>
>>>
>>> OIIO
>>>
>>> ;
>>>
>>> auto
>>>
>>>
>>>
>>> min
>>>
>>>
>>>
>>> =
>>>
>>>
>>>
>>> half
>>>
>>> {
>>>
>>>
>>>
>>> 0.0f
>>>
>>>
>>>
>>> };
>>>
>>> auto
>>>
>>>
>>>
>>> max
>>>
>>>
>>>
>>> =
>>>
>>>
>>>
>>> half
>>>
>>> {
>>>
>>>
>>>
>>> 0.0f
>>>
>>>
>>>
>>> };
>>>
>>> for
>>>
>>>
>>>
>>> (
>>>
>>> auto
>>>
>>>
>>>
>>> it
>>>
>>>
>>>
>>> =
>>>
>>>
>>>
>>> ImageBuf
>>>
>>> ::
>>>
>>> ConstIterator
>>>
>>> <
>>>
>>> float
>>>
>>>>{
>>>
>>>
>>>
>>> *
>>>
>>> image
>>>
>>>
>>>
>>> };
>>>
>>>
>>>
>>> !
>>>
>>> it
>>>
>>> .
>>>
>>> done
>>>
>>> ();
>>>
>>>
>>>
>>> ++
>>>
>>> it
>>>
>>> )
>>>
>>> for
>>>
>>>
>>>
>>> (
>>>
>>> auto
>>>
>>>
>>>
>>> c
>>>
>>>
>>>
>>> =
>>>
>>>
>>>
>>> 0
>>>
>>> ;
>>>
>>>
>>>
>>> c
>>>
>>>
>>>
>>> <
>>>
>>>
>>>
>>> image
>>>
>>> ->
>>>
>>> nchannels
>>>
>>> ();
>>>
>>>
>>>
>>> ++
>>>
>>> c
>>>
>>> )
>>>
>>>
>>>
>>> {
>>>
>>> if
>>>
>>>
>>>
>>> (
>>>
>>> it
>>>
>>> [
>>>
>>> c
>>>
>>> ]
>>>
>>>
>>>
>>> <
>>>
>>>
>>>
>>> min
>>>
>>> )
>>>
>>>
>>>
>>> min
>>>
>>>
>>>
>>> =
>>>
>>>
>>>
>>> it
>>>
>>> [
>>>
>>> c
>>>
>>> ]
>>>
>>> ;
>>>
>>> if
>>>
>>>
>>>
>>> (
>>>
>>> it
>>>
>>> [
>>>
>>> c
>>>
>>> ]
>>>
>>>
>>>
>>>>
>>>
>>>
>>>
>>> max
>>>
>>> )
>>>
>>>
>>>
>>> max
>>>
>>>
>>>
>>> =
>>>
>>>
>>>
>>> it
>>>
>>> [
>>>
>>> c
>>>
>>> ]
>>>
>>> ;
>>>
>>> }
>>>
>>> for
>>>
>>>
>>>
>>> (
>>>
>>> auto
>>>
>>>
>>>
>>> it
>>>
>>>
>>>
>>> =
>>>
>>>
>>>
>>> ImageBuf
>>>
>>> ::
>>>
>>> Iterator
>>>
>>> <
>>>
>>> float
>>>
>>>>{
>>>
>>>
>>>
>>> *
>>>
>>> image
>>>
>>>
>>>
>>> };
>>>
>>>
>>>
>>> !
>>>
>>> it
>>>
>>> .
>>>
>>> done
>>>
>>> ();
>>>
>>>
>>>
>>> ++
>>>
>>> it
>>>
>>> )
>>>
>>> for
>>>
>>>
>>>
>>> (
>>>
>>> auto
>>>
>>>
>>>
>>> c
>>>
>>>
>>>
>>> =
>>>
>>>
>>>
>>> 0
>>>
>>> ;
>>>
>>>
>>>
>>> c
>>>
>>>
>>>
>>> <
>>>
>>>
>>>
>>> image
>>>
>>> ->
>>>
>>> nchannels
>>>
>>> ();
>>>
>>>
>>>
>>> ++
>>>
>>> c
>>>
>>> )
>>>
>>> it
>>>
>>> [
>>>
>>> c
>>>
>>> ]
>>>
>>>
>>>
>>> =
>>>
>>>
>>>
>>> 0.0f
>>>
>>>
>>>
>>> +
>>>
>>>
>>>
>>> (
>>>
>>> it
>>>
>>> [
>>>
>>> c
>>>
>>> ]
>>>
>>>
>>>
>>> -
>>>
>>>
>>>
>>> min
>>>
>>> )
>>>
>>>
>>>
>>> *
>>>
>>>
>>>
>>> (
>>>
>>>
>>>
>>> 1.0f
>>>
>>>
>>>
>>> -
>>>
>>>
>>>
>>> 0.0f
>>>
>>>
>>>
>>> )
>>>
>>>
>>>
>>> /
>>>
>>>
>>>
>>> (
>>>
>>> max
>>>
>>>
>>>
>>> -
>>>
>>>
>>>
>>> min
>>>
>>> );
>>>
>>> }
>>>
>>> _______________________________________________
>>> Oiio-dev mailing list
>>> [email protected]
>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>
>> --
>> Larry Gritz
>> [email protected]
>>
>> _______________________________________________
>> Oiio-dev mailing list
>> [email protected]
>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>
> --
> Larry Gritz
> [email protected]_______________________________________________
Oiio-dev mailing list
[email protected]
http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org