1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
|
// ======================================================================== //
// Copyright 2009-2019 Intel Corporation //
// //
// Licensed under the Apache License, Version 2.0 (the "License"); //
// you may not use this file except in compliance with the License. //
// You may obtain a copy of the License at //
// //
// http://www.apache.org/licenses/LICENSE-2.0 //
// //
// Unless required by applicable law or agreed to in writing, software //
// distributed under the License is distributed on an "AS IS" BASIS, //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and //
// limitations under the License. //
// ======================================================================== //
#pragma once
#include "image.h"
#include "node.h"
namespace oidn {
__forceinline float luminance(float r, float g, float b)
{
return 0.212671f * r + 0.715160f * g + 0.072169f * b;
}
// Color transfer function base class
class TransferFunction
{
public:
virtual ~TransferFunction() = default;
virtual float forward(float y) const = 0;
virtual float inverse(float x) const = 0;
};
// HDR transfer function base class
class HDRTransferFunction : public TransferFunction
{
protected:
static constexpr float yMax = 65504.f;
float exposure;
float rcpExposure;
public:
HDRTransferFunction(float exposure = 1.f)
{
setExposure(exposure);
}
void setExposure(float exposure)
{
this->exposure = exposure;
this->rcpExposure = (exposure != 0.f) ? (1.f / exposure) : 0.f;
}
};
// Linear transfer function (LDR)
class LinearTransferFunction : public TransferFunction
{
public:
__forceinline float forward(float y) const override
{
return min(y, 1.f);
}
__forceinline float inverse(float x) const override
{
return min(x, 1.f);
}
};
// 2.2 gamma transfer function (LDR)
class GammaTransferFunction : public TransferFunction
{
public:
__forceinline float forward(float y) const override
{
return min(pow(y, 1.f/2.2f), 1.f);
}
__forceinline float inverse(float x) const override
{
return min(pow(x, 2.2f), 1.f);
}
};
// Logarithmic transfer function (HDR)
// Compresses [0..65504] to [0..1]
class LogTransferFunction : public HDRTransferFunction
{
private:
static const float xScale;
public:
LogTransferFunction(float exposure = 1.f)
: HDRTransferFunction(exposure)
{
}
__forceinline float forward(float y) const override
{
return log(y * exposure + 1.f) * xScale;
}
__forceinline float inverse(float x) const override
{
return (exp(x * (1.f/xScale)) - 1.f) * rcpExposure;
}
};
// PQX transfer function (HDR)
// Compresses [0..65504] to [0..1]
class PQXTransferFunction : public HDRTransferFunction
{
private:
static constexpr float m1 = 2610.f / 4096.f / 4.f;
static constexpr float m2 = 2523.f / 4096.f * 128.f;
static constexpr float c1 = 3424.f / 4096.f;
static constexpr float c2 = 2413.f / 4096.f * 32.f;
static constexpr float c3 = 2392.f / 4096.f * 32.f;
static constexpr float a = 3711.f / 4096.f / 8.f;
static constexpr float yScale = 100.f / 10000.f;
static const float xScale;
public:
PQXTransferFunction(float exposure = 1.f)
: HDRTransferFunction(exposure)
{
}
__forceinline float forward(float y) const override
{
return pqxForward(y * exposure * yScale) * xScale;
}
__forceinline float inverse(float x) const override
{
return pqxInverse(x * (1.f/xScale)) * (1.f/yScale) * rcpExposure;
}
private:
static __forceinline float pqForward(float y)
{
const float yp = pow(y, m1);
return pow((c1 + c2 * yp) * rcp(1.f + c3 * yp), m2);
}
static __forceinline float pqxForward(float y)
{
if (y <= 1.f)
return pqForward(y);
else
return a * log(y) + 1.f;
}
static __forceinline float pqInverse(float x)
{
const float xp = pow(x, 1.f/m2);
return pow(max((xp - c1) * rcp(c2 - c3 * xp), 0.f), 1.f/m1);
}
static __forceinline float pqxInverse(float x)
{
if (x <= 1.f)
return pqInverse(x);
else
return exp((x - 1.f) * (1.f/a));
}
};
// Autoexposure node
class AutoexposureNode : public Node
{
private:
Image color;
std::shared_ptr<HDRTransferFunction> transferFunc;
public:
AutoexposureNode(const Image& color,
const std::shared_ptr<HDRTransferFunction>& transferFunc)
: color(color),
transferFunc(transferFunc)
{}
void execute(stream& sm) override
{
const float exposure = autoexposure(color);
//printf("exposure = %f\n", exposure);
transferFunc->setExposure(exposure);
}
private:
static float autoexposure(const Image& color);
};
} // namespace oidn
|