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