Wildmeshing Toolkit
Loading...
Searching...
No Matches
load_image_exr.cpp
Go to the documentation of this file.
1#include "load_image_exr.hpp"
2
3#define TINYEXR_USE_STB_ZLIB 1
4#define TINYEXR_USE_MINIZ 0
5#define TINYEXR_IMPLEMENTATION
6#include <tinyexr.h>
7#include <cassert>
9using namespace wmtk;
10auto load_image_exr_red_channel(const std::filesystem::path& path)
11 -> std::tuple<size_t, size_t, std::vector<float>>
12{
13 using namespace wmtk;
14 wmtk::logger().debug("[load_image_exr_red_channel] start \"{}\"", path.string());
15 assert(std::filesystem::exists(path));
16 const std::string filename_ = path.string();
17 const char* filename = filename_.c_str();
18
19 const auto exr_version = [&filename, &path]() -> EXRVersion { // parse version
20 EXRVersion exr_version_;
21
22 const auto ret = ParseEXRVersionFromFile(&exr_version_, filename);
23 if (ret != TINYEXR_SUCCESS) {
24 wmtk::logger().error("failed LoadImageEXR \"{}\" \"version error\"", path.string());
25 throw std::runtime_error("LoadImageEXRError");
26 }
27
28 if (exr_version_.multipart || exr_version_.non_image) {
29 wmtk::logger().error(
30 "failed LoadImageEXR \"{}\" \"multipart or non image\"",
31 path.string());
32 throw std::runtime_error("LoadImageEXRError");
33 }
34
35 return exr_version_;
36 }();
37
38 auto exr_header_data =
39 [&filename, &path, &exr_version]() -> std::tuple<EXRHeader, int> { // parse header
40 EXRHeader exr_header_;
41 InitEXRHeader(&exr_header_);
42
43 [[maybe_unused]] const char* err = nullptr;
44 const auto ret = ParseEXRHeaderFromFile(&exr_header_, &exr_version, filename, &err);
45 if (ret != TINYEXR_SUCCESS) {
46 wmtk::logger().error("failed LoadImageEXR \"{}\" \"header error\"", path.string());
47 FreeEXRHeader(&exr_header_);
48 throw std::runtime_error("LoadImageEXRError");
49 }
50
51 // sanity check, only support all channels are the same type
52 for (int i = 0; i < exr_header_.num_channels; i++) {
53 if (exr_header_.pixel_types[i] != exr_header_.pixel_types[0] ||
54 exr_header_.requested_pixel_types[i] != exr_header_.pixel_types[i]) {
55 wmtk::logger().error(
56 "failed LoadImageEXR \"{}\" \"inconsistent pixel_types\"",
57 path.string());
58 FreeEXRHeader(&exr_header_);
59 throw std::runtime_error("LoadImageEXRError");
60 }
61 }
62
63 // read HALF channel as FLOAT.
64 for (int i = 0; i < exr_header_.num_channels; i++) {
65 if (exr_header_.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) {
66 exr_header_.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT;
67 }
68 }
69
70 // only FLOAT are supported
71 if (exr_header_.requested_pixel_types[0] != TINYEXR_PIXELTYPE_FLOAT) {
72 wmtk::logger().error(
73 "failed LoadImageEXR \"{}\" \"only float exr are supported\"",
74 path.string());
75 FreeEXRHeader(&exr_header_);
76 throw std::runtime_error("LoadImageEXRError");
77 }
78
79 // only non tiled image are supported
80 if (exr_header_.tiled) {
81 wmtk::logger().error(
82 "failed LoadImageEXR \"{}\" \"only non tiled exr are supported\"",
83 path.string());
84 FreeEXRHeader(&exr_header_);
85 throw std::runtime_error("LoadImageEXRError");
86 }
87
88
89 int index_red_ = -1;
90 for (int i = 0; i < exr_header_.num_channels; i++) {
91 if (strcmp(exr_header_.channels[i].name, "R") == 0) index_red_ = i;
92 }
93 if (index_red_ < 0) {
94 wmtk::logger().warn("Could not find R channel. Looking for Y channel instead.");
95 for (int i = 0; i < exr_header_.num_channels; i++) {
96 if (strcmp(exr_header_.channels[i].name, "Y") == 0) index_red_ = i;
97 }
98 }
99
100 if (index_red_ < 0) {
101 std::vector<std::string> channels;
102 for (int i = 0; i < exr_header_.num_channels; i++) {
103 channels.push_back(exr_header_.channels[i].name);
104 }
105 wmtk::logger().error(
106 "failed LoadImageEXR \"{}\" can't find all expected channels: [{}]",
107 path.string(),
108 fmt::join(channels, ","));
109 FreeEXRHeader(&exr_header_);
110 throw std::runtime_error("LoadImageEXRError");
111 }
112
113 return {exr_header_, index_red_};
114 }();
115 auto& exr_header = std::get<0>(exr_header_data);
116 const auto& index_data = std::get<1>(exr_header_data);
117
118 auto exr_image = [&filename, &path, &exr_header]() -> EXRImage {
119 EXRImage exr_image_;
120 InitEXRImage(&exr_image_);
121
122 [[maybe_unused]] const char* err = nullptr;
123 const auto ret = LoadEXRImageFromFile(&exr_image_, &exr_header, filename, &err);
124 if (ret != TINYEXR_SUCCESS) {
125 wmtk::logger().error(
126 "failed LoadImageEXR \"{}\" \"failed to load image data\"",
127 path.string());
128 FreeEXRHeader(&exr_header);
129 FreeEXRImage(&exr_image_);
130 throw std::runtime_error("LoadImageEXRError");
131 }
132
133 return exr_image_;
134 }();
135
136 wmtk::logger().debug(
137 "[load_image_exr_red_channel] num_channels {} tiled {}",
138 exr_header.num_channels,
139 exr_header.tiled);
140 wmtk::logger().debug("[load_image_exr_red_channel] index_data {}", index_data);
141 assert(index_data >= 0);
142 assert(!exr_header.tiled);
143
144 std::vector<float> data_r;
145 data_r.reserve(static_cast<size_t>(exr_image.width) * static_cast<size_t>(exr_image.height));
146
147 const auto images = reinterpret_cast<float**>(exr_image.images);
148 for (int i = 0; i < exr_image.width * exr_image.height; i++)
149 data_r.emplace_back(images[index_data][i]);
150
151 FreeEXRHeader(&exr_header);
152 FreeEXRImage(&exr_image);
153
154 wmtk::logger().debug("[load_image_exr_red_channel] done \"{}\"", path.string());
155
156 return {
157 static_cast<size_t>(exr_image.width),
158 static_cast<size_t>(exr_image.height),
159 std::move(data_r),
160 };
161}
162
163auto load_image_exr_split_3channels(const std::filesystem::path& path) -> std::
164 tuple<size_t, size_t, int, int, int, std::vector<float>, std::vector<float>, std::vector<float>>
165{
166 using namespace wmtk;
167 wmtk::logger().debug("[load_image_exr_red_channel] start \"{}\"", path.string());
168 assert(std::filesystem::exists(path));
169 const std::string filename_ = path.string();
170 const char* filename = filename_.c_str();
171
172 const auto exr_version = [&filename, &path]() -> EXRVersion { // parse version
173 EXRVersion exr_version_;
174
175 const auto ret = ParseEXRVersionFromFile(&exr_version_, filename);
176 if (ret != TINYEXR_SUCCESS) {
177 wmtk::logger().error("failed LoadImageEXR \"{}\" \"version error\"", path.string());
178 throw std::runtime_error("LoadImageEXRError");
179 }
180
181 if (exr_version_.multipart || exr_version_.non_image) {
182 wmtk::logger().error(
183 "failed LoadImageEXR \"{}\" \"multipart or non image\"",
184 path.string());
185 throw std::runtime_error("LoadImageEXRError");
186 }
187
188 return exr_version_;
189 }();
190
191 auto exr_header_data =
192 [&filename, &path, &exr_version]() -> std::tuple<EXRHeader, int, int, int> { // parse header
193 EXRHeader exr_header_;
194 InitEXRHeader(&exr_header_);
195
196 [[maybe_unused]] const char* err = nullptr;
197 const auto ret = ParseEXRHeaderFromFile(&exr_header_, &exr_version, filename, &err);
198 if (ret != TINYEXR_SUCCESS) {
199 wmtk::logger().error("failed LoadImageEXR \"{}\" \"header error\"", path.string());
200 FreeEXRHeader(&exr_header_);
201 throw std::runtime_error("LoadImageEXRError");
202 }
203
204 // sanity check, only support all channels are the same type
205 for (int i = 0; i < exr_header_.num_channels; i++) {
206 if (exr_header_.pixel_types[i] != exr_header_.pixel_types[0] ||
207 exr_header_.requested_pixel_types[i] != exr_header_.pixel_types[i]) {
208 wmtk::logger().error(
209 "failed LoadImageEXR \"{}\" \"inconsistent pixel_types\"",
210 path.string());
211 FreeEXRHeader(&exr_header_);
212 throw std::runtime_error("LoadImageEXRError");
213 }
214 }
215
216 // read HALF channel as FLOAT.
217 for (int i = 0; i < exr_header_.num_channels; i++) {
218 if (exr_header_.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) {
219 exr_header_.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT;
220 }
221 }
222
223 // only FLOAT are supported
224 if (exr_header_.requested_pixel_types[0] != TINYEXR_PIXELTYPE_FLOAT) {
225 wmtk::logger().error(
226 "failed LoadImageEXR \"{}\" \"only float exr are supported\"",
227 path.string());
228 FreeEXRHeader(&exr_header_);
229 throw std::runtime_error("LoadImageEXRError");
230 }
231
232 // only non tiled image are supported
233 if (exr_header_.tiled) {
234 wmtk::logger().error(
235 "failed LoadImageEXR \"{}\" \"only non tiled exr are supported\"",
236 path.string());
237 FreeEXRHeader(&exr_header_);
238 throw std::runtime_error("LoadImageEXRError");
239 }
240
241
242 int index_red_ = -1;
243 int index_green_ = -1;
244 int index_blue_ = -1;
245 if (exr_header_.num_channels == 1) {
246 wmtk::logger().warn("Treat grayscale image as RGB: {}", path.string());
247 index_red_ = 0;
248 index_green_ = 0;
249 index_blue_ = 0;
250 } else {
251 for (int i = 0; i < exr_header_.num_channels; i++) {
252 if (strcmp(exr_header_.channels[i].name, "R") == 0) index_red_ = i;
253 if (strcmp(exr_header_.channels[i].name, "G") == 0) index_green_ = i;
254 if (strcmp(exr_header_.channels[i].name, "B") == 0) index_blue_ = i;
255 }
256 }
257
258 if (index_red_ < 0) {
259 std::vector<std::string> channels;
260 for (int i = 0; i < exr_header_.num_channels; i++) {
261 channels.push_back(exr_header_.channels[i].name);
262 }
263 wmtk::logger().error(
264 "failed LoadImageEXR \"{}\" can't find all 3 expected channels: [{}]",
265 path.string(),
266 fmt::join(channels, ","));
267 FreeEXRHeader(&exr_header_);
268 throw std::runtime_error("LoadImageEXRError");
269 }
270
271 return {exr_header_, index_red_, index_green_, index_blue_};
272 }();
273 auto& exr_header = std::get<0>(exr_header_data);
274 const auto& index_red = std::get<1>(exr_header_data);
275 const auto& index_green = std::get<2>(exr_header_data);
276 const auto& index_blue = std::get<3>(exr_header_data);
277
278 auto exr_image = [&filename, &path, &exr_header]() -> EXRImage {
279 EXRImage exr_image_;
280 InitEXRImage(&exr_image_);
281
282 [[maybe_unused]] const char* err = nullptr;
283 const auto ret = LoadEXRImageFromFile(&exr_image_, &exr_header, filename, &err);
284 if (ret != TINYEXR_SUCCESS) {
285 wmtk::logger().error(
286 "failed LoadImageEXR \"{}\" \"failed to load image data\"",
287 path.string());
288 FreeEXRHeader(&exr_header);
289 FreeEXRImage(&exr_image_);
290 throw std::runtime_error("LoadImageEXRError");
291 }
292
293 return exr_image_;
294 }();
295
296 wmtk::logger().debug(
297 "[load_image_exr_3channels] num_channels {} tiled {}",
298 exr_header.num_channels,
299 exr_header.tiled);
300 wmtk::logger().debug("[load_image_exr_3channels] index_red {}", index_red);
301 wmtk::logger().debug("[load_image_exr_3channels] index_green {}", index_green);
302 wmtk::logger().debug("[load_image_exr_3channels] index_blue {}", index_blue);
303 assert(index_red >= 0);
304 assert(index_green >= 0);
305 assert(index_blue >= 0);
306 assert(!exr_header.tiled);
307
308 std::vector<float> data_r;
309 std::vector<float> data_g;
310 std::vector<float> data_b;
311 data_r.reserve(static_cast<size_t>(exr_image.width) * static_cast<size_t>(exr_image.height));
312 data_g.reserve(static_cast<size_t>(exr_image.width) * static_cast<size_t>(exr_image.height));
313 data_b.reserve(static_cast<size_t>(exr_image.width) * static_cast<size_t>(exr_image.height));
314
315 const auto images = reinterpret_cast<float**>(exr_image.images);
316 for (int i = 0; i < exr_image.width * exr_image.height; i++) {
317 data_r.emplace_back(images[index_red][i]);
318 data_g.emplace_back(images[index_green][i]);
319 data_b.emplace_back(images[index_blue][i]);
320 }
321 FreeEXRHeader(&exr_header);
322 FreeEXRImage(&exr_image);
323
324 wmtk::logger().debug("[load_image_exr_3channels] done \"{}\"", path.string());
325
326 return {
327 static_cast<size_t>(exr_image.width),
328 static_cast<size_t>(exr_image.height),
329 std::move(index_red),
330 std::move(index_green),
331 std::move(index_blue),
332 std::move(data_r),
333 std::move(data_g),
334 std::move(data_b)};
335}
auto load_image_exr_red_channel(const std::filesystem::path &path) -> std::tuple< size_t, size_t, std::vector< float > >
auto load_image_exr_split_3channels(const std::filesystem::path &path) -> std::tuple< size_t, size_t, int, int, int, std::vector< float >, std::vector< float >, std::vector< float > >
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:58