Blender V4.3
denoising.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "session/denoising.h"
6#include "device/cpu/device.h"
7
8#include "util/map.h"
9#include "util/system.h"
10#include "util/task.h"
11#include "util/time.h"
12
13#include <OpenImageIO/filesystem.h>
14
16
17/* Utility Functions */
18
19/* Splits in at its last dot, setting suffix to the part after the dot and in to the part before
20 * it. Returns whether a dot was found. */
21static bool split_last_dot(string &in, string &suffix)
22{
23 size_t pos = in.rfind(".");
24 if (pos == string::npos) {
25 return false;
26 }
27 suffix = in.substr(pos + 1);
28 in = in.substr(0, pos);
29 return true;
30}
31
32/* Separate channel names as generated by Blender.
33 * If views is true:
34 * Inputs are expected in the form RenderLayer.Pass.View.Channel, sets renderlayer to
35 * "RenderLayer.View" Otherwise: Inputs are expected in the form RenderLayer.Pass.Channel */
37 string name, string &renderlayer, string &pass, string &channel, bool multiview_channels)
38{
39 if (!split_last_dot(name, channel)) {
40 return false;
41 }
42 string view;
43 if (multiview_channels && !split_last_dot(name, view)) {
44 return false;
45 }
46 if (!split_last_dot(name, pass)) {
47 return false;
48 }
49 renderlayer = name;
50
51 if (multiview_channels) {
52 renderlayer += "." + view;
53 }
54
55 return true;
56}
57
58/* Channel Mapping */
59
62 string name;
63};
64
65static void fill_mapping(vector<ChannelMapping> &map, int pos, string name, string channels)
66{
67 for (const char *chan = channels.c_str(); *chan; chan++) {
68 map.push_back({pos++, name + "." + *chan});
69 }
70}
71
72static const int INPUT_NUM_CHANNELS = 13;
73static const int INPUT_NOISY_IMAGE = 0;
74static const int INPUT_DENOISING_NORMAL = 3;
75static const int INPUT_DENOISING_ALBEDO = 6;
76static const int INPUT_MOTION = 9;
78{
80 fill_mapping(map, INPUT_NOISY_IMAGE, "Combined", "RGB");
81 fill_mapping(map, INPUT_DENOISING_NORMAL, "Denoising Normal", "XYZ");
82 fill_mapping(map, INPUT_DENOISING_ALBEDO, "Denoising Albedo", "RGB");
83 fill_mapping(map, INPUT_MOTION, "Vector", "XYZW");
84 return map;
85}
86
87static const int OUTPUT_NUM_CHANNELS = 3;
89{
91 fill_mapping(map, 0, "Combined", "RGB");
92 return map;
93}
94
95/* Render-layer Handling. */
96
98{
99 /* Map device input to image channels. */
102
103 for (const ChannelMapping &mapping : input_channels()) {
104 vector<string>::iterator i = find(channels.begin(), channels.end(), mapping.name);
105 if (i == channels.end()) {
106 return false;
107 }
108
109 size_t input_channel = mapping.channel;
110 size_t layer_channel = i - channels.begin();
111 input_to_image_channel[input_channel] = layer_to_image_channel[layer_channel];
112 }
113
114 /* Map device output to image channels. */
117
118 for (const ChannelMapping &mapping : output_channels()) {
119 vector<string>::iterator i = find(channels.begin(), channels.end(), mapping.name);
120 if (i == channels.end()) {
121 return false;
122 }
123
124 size_t output_channel = mapping.channel;
125 size_t layer_channel = i - channels.begin();
126 output_to_image_channel[output_channel] = layer_to_image_channel[layer_channel];
127 }
128
129 /* Check that all buffer channels are correctly set. */
130 for (int i = 0; i < INPUT_NUM_CHANNELS; i++) {
131 assert(input_to_image_channel[i] >= 0);
132 }
133 for (int i = 0; i < OUTPUT_NUM_CHANNELS; i++) {
134 assert(output_to_image_channel[i] >= 0);
135 }
136
137 return true;
138}
139
140bool DenoiseImageLayer::match_channels(const std::vector<string> &channelnames,
141 const std::vector<string> &neighbor_channelnames)
142{
144
145 assert(mapping.size() == 0);
146 mapping.resize(output_to_image_channel.size(), -1);
147
148 for (int i = 0; i < output_to_image_channel.size(); i++) {
149 const string &channel = channelnames[output_to_image_channel[i]];
150 std::vector<string>::const_iterator frame_channel = find(
151 neighbor_channelnames.begin(), neighbor_channelnames.end(), channel);
152
153 if (frame_channel == neighbor_channelnames.end()) {
154 return false;
155 }
156
157 mapping[i] = frame_channel - neighbor_channelnames.begin();
158 }
159
160 return true;
161}
162
163/* Denoise Task */
164
166 : denoiser(denoiser), device(device), frame(frame), current_layer(0), buffers(device)
167{
168}
169
174
175/* Denoiser Operations */
176
178{
179 /* Load center image */
180 DenoiseImageLayer &image_layer = image.layers[layer];
181
182 float *buffer_data = buffers.buffer.data();
183 image.read_pixels(image_layer, buffers.params, buffer_data);
184
185 /* Load previous image */
186 if (frame > 0 && !image.read_previous_pixels(image_layer, buffers.params, buffer_data)) {
187 error = "Failed to read neighbor frame pixels";
188 return false;
189 }
190
191 /* Copy to device */
193
194 return true;
195}
196
197/* Task stages */
198
199static void add_pass(vector<Pass *> &passes, PassType type, PassMode mode = PassMode::NOISY)
200{
201 Pass *pass = new Pass();
202 pass->set_type(type);
203 pass->set_mode(mode);
204
205 passes.push_back(pass);
206}
207
209{
210 string center_filepath = denoiser->input[frame];
211 if (!image.load(center_filepath, error)) {
212 return false;
213 }
214
215 /* Use previous frame output as input for subsequent frames. */
216 if (frame > 0 && !image.load_previous(denoiser->output[frame - 1], error)) {
217 return false;
218 }
219
220 if (image.layers.empty()) {
221 error = "No image layers found to denoise in " + center_filepath;
222 return false;
223 }
224
225 /* Enable temporal denoising for frames after the first (which will use the output from the
226 * previous frames). */
227 DenoiseParams params = denoiser->denoiser->get_params();
228 params.temporally_stable = frame > 0;
229 denoiser->denoiser->set_params(params);
230
231 /* Allocate device buffer. */
232 vector<Pass *> passes;
233 add_pass(passes, PassType::PASS_COMBINED);
234 add_pass(passes, PassType::PASS_DENOISING_ALBEDO);
235 add_pass(passes, PassType::PASS_DENOISING_NORMAL);
236 add_pass(passes, PassType::PASS_MOTION);
237 add_pass(passes, PassType::PASS_DENOISING_PREVIOUS);
238 add_pass(passes, PassType::PASS_COMBINED, PassMode::DENOISED);
239
240 BufferParams buffer_params;
241 buffer_params.width = image.width;
242 buffer_params.height = image.height;
243 buffer_params.full_x = 0;
244 buffer_params.full_y = 0;
245 buffer_params.full_width = image.width;
246 buffer_params.full_height = image.height;
247 buffer_params.update_passes(passes);
248
249 for (Pass *pass : passes) {
250 delete pass;
251 }
252
253 buffers.reset(buffer_params);
254
255 /* Read pixels for first layer. */
256 current_layer = 0;
258 return false;
259 }
260
261 return true;
262}
263
265{
266 for (current_layer = 0; current_layer < image.layers.size(); current_layer++) {
267 /* Read pixels for secondary layers, first was already loaded. */
268 if (current_layer > 0) {
270 return false;
271 }
272 }
273
274 /* Run task on device. */
275 denoiser->denoiser->denoise_buffer(buffers.params, &buffers, 1, true);
276
277 /* Copy denoised pixels from device. */
279
280 float *result = buffers.buffer.data(), *out = image.pixels.data();
281
282 const DenoiseImageLayer &layer = image.layers[current_layer];
283 const int *output_to_image_channel = layer.output_to_image_channel.data();
284
285 for (int y = 0; y < image.height; y++) {
286 for (int x = 0; x < image.width; x++, result += buffers.params.pass_stride) {
287 for (int j = 0; j < OUTPUT_NUM_CHANNELS; j++) {
289 int image_channel = output_to_image_channel[j];
290 out[image.num_channels * x + image_channel] = result[offset + j];
291 }
292 }
293 out += image.num_channels * image.width;
294 }
295
296 printf("\n");
297 }
298
299 return true;
300}
301
303{
304 bool ok = image.save_output(denoiser->output[frame], error);
305 free();
306 return ok;
307}
308
310{
311 image.free();
313}
314
315/* Denoise Image Storage */
316
318{
319 width = 0;
320 height = 0;
321 num_channels = 0;
322 samples = 0;
323}
324
329
331{
332 in_previous.reset();
333}
334
336{
337 close_input();
338 pixels.clear();
339}
340
341bool DenoiseImage::parse_channels(const ImageSpec &in_spec, string &error)
342{
343 const std::vector<string> &channels = in_spec.channelnames;
344 const ParamValue *multiview = in_spec.find_attribute("multiView");
345 const bool multiview_channels = (multiview && multiview->type().basetype == TypeDesc::STRING &&
346 multiview->type().arraylen >= 2);
347
348 layers.clear();
349
350 /* Loop over all the channels in the file, parse their name and sort them
351 * by RenderLayer.
352 * Channels that can't be parsed are directly passed through to the output. */
353 map<string, DenoiseImageLayer> file_layers;
354 for (int i = 0; i < channels.size(); i++) {
355 string layer, pass, channel;
356 if (parse_channel_name(channels[i], layer, pass, channel, multiview_channels)) {
357 file_layers[layer].channels.push_back(pass + "." + channel);
358 file_layers[layer].layer_to_image_channel.push_back(i);
359 }
360 }
361
362 /* Loop over all detected RenderLayers, check whether they contain a full set of input channels.
363 * Any channels that won't be processed internally are also passed through. */
364 for (map<string, DenoiseImageLayer>::iterator i = file_layers.begin(); i != file_layers.end();
365 ++i)
366 {
367 const string &name = i->first;
368 DenoiseImageLayer &layer = i->second;
369
370 /* Check for full pass set. */
371 if (!layer.detect_denoising_channels()) {
372 continue;
373 }
374
375 layer.name = name;
376 layer.samples = samples;
377
378 /* If the sample value isn't set yet, check if there is a layer-specific one in the input file.
379 */
380 if (layer.samples < 1) {
381 string sample_string = in_spec.get_string_attribute("cycles." + name + ".samples", "");
382 if (sample_string != "") {
383 if (!sscanf(sample_string.c_str(), "%d", &layer.samples)) {
384 error = "Failed to parse samples metadata: " + sample_string;
385 return false;
386 }
387 }
388 }
389
390 if (layer.samples < 1) {
392 "No sample number specified in the file for layer %s or on the command line",
393 name.c_str());
394 return false;
395 }
396
397 layers.push_back(layer);
398 }
399
400 return true;
401}
402
404 const BufferParams &params,
405 float *input_pixels)
406{
407 /* Pixels from center file have already been loaded into pixels.
408 * We copy a subset into the device input buffer with channels reshuffled. */
409 const int *input_to_image_channel = layer.input_to_image_channel.data();
410
411 for (int i = 0; i < width * height; i++) {
412 for (int j = 0; j < 3; ++j) {
413 int offset = params.get_pass_offset(PASS_COMBINED);
414 int image_channel = input_to_image_channel[INPUT_NOISY_IMAGE + j];
415 input_pixels[i * params.pass_stride + offset + j] =
416 pixels[((size_t)i) * num_channels + image_channel];
417 }
418 for (int j = 0; j < 3; ++j) {
419 int offset = params.get_pass_offset(PASS_DENOISING_NORMAL);
420 int image_channel = input_to_image_channel[INPUT_DENOISING_NORMAL + j];
421 input_pixels[i * params.pass_stride + offset + j] =
422 pixels[((size_t)i) * num_channels + image_channel];
423 }
424 for (int j = 0; j < 3; ++j) {
425 int offset = params.get_pass_offset(PASS_DENOISING_ALBEDO);
426 int image_channel = input_to_image_channel[INPUT_DENOISING_ALBEDO + j];
427 input_pixels[i * params.pass_stride + offset + j] =
428 pixels[((size_t)i) * num_channels + image_channel];
429 }
430 for (int j = 0; j < 4; ++j) {
431 int offset = params.get_pass_offset(PASS_MOTION);
432 int image_channel = input_to_image_channel[INPUT_MOTION + j];
433 input_pixels[i * params.pass_stride + offset + j] =
434 pixels[((size_t)i) * num_channels + image_channel];
435 }
436 }
437}
438
440 const BufferParams &params,
441 float *input_pixels)
442{
443 /* Load pixels from neighboring frames, and copy them into device buffer
444 * with channels reshuffled. */
445 const size_t num_pixels = (size_t)width * (size_t)height;
446 const int num_channels = in_previous->spec().nchannels;
447
448 array<float> neighbor_pixels(num_pixels * num_channels);
449
450 if (!in_previous->read_image(0, 0, 0, num_channels, TypeDesc::FLOAT, neighbor_pixels.data())) {
451 return false;
452 }
453
454 const int *output_to_image_channel = layer.previous_output_to_image_channel.data();
455
456 for (int i = 0; i < width * height; i++) {
457 for (int j = 0; j < 3; ++j) {
458 int offset = params.get_pass_offset(PASS_DENOISING_PREVIOUS);
459 int image_channel = output_to_image_channel[j];
460 input_pixels[i * params.pass_stride + offset + j] =
461 neighbor_pixels[((size_t)i) * num_channels + image_channel];
462 }
463 }
464
465 return true;
466}
467
468bool DenoiseImage::load(const string &in_filepath, string &error)
469{
470 if (!Filesystem::is_regular(in_filepath)) {
471 error = "Couldn't find file: " + in_filepath;
472 return false;
473 }
474
475 unique_ptr<ImageInput> in(ImageInput::open(in_filepath));
476 if (!in) {
477 error = "Couldn't open file: " + in_filepath;
478 return false;
479 }
480
481 in_spec = in->spec();
482 width = in_spec.width;
483 height = in_spec.height;
484 num_channels = in_spec.nchannels;
485
487 return false;
488 }
489
490 if (layers.empty()) {
491 error = "Could not find a render layer containing denoising data and motion vector passes";
492 return false;
493 }
494
495 size_t num_pixels = (size_t)width * (size_t)height;
496 pixels.resize(num_pixels * num_channels);
497
498 /* Read all channels into buffer. Reading all channels at once is faster
499 * than individually due to interleaved EXR channel storage. */
500 if (!in->read_image(0, 0, 0, num_channels, TypeDesc::FLOAT, pixels.data())) {
501 error = "Failed to read image: " + in_filepath;
502 return false;
503 }
504
505 return true;
506}
507
508bool DenoiseImage::load_previous(const string &filepath, string &error)
509{
510 if (!Filesystem::is_regular(filepath)) {
511 error = "Couldn't find neighbor frame: " + filepath;
512 return false;
513 }
514
515 unique_ptr<ImageInput> in_neighbor(ImageInput::open(filepath));
516 if (!in_neighbor) {
517 error = "Couldn't open neighbor frame: " + filepath;
518 return false;
519 }
520
521 const ImageSpec &neighbor_spec = in_neighbor->spec();
522 if (neighbor_spec.width != width || neighbor_spec.height != height) {
523 error = "Neighbor frame has different dimensions: " + filepath;
524 return false;
525 }
526
527 for (DenoiseImageLayer &layer : layers) {
528 if (!layer.match_channels(in_spec.channelnames, neighbor_spec.channelnames)) {
529 error = "Neighbor frame misses denoising data passes: " + filepath;
530 return false;
531 }
532 }
533
534 in_previous = std::move(in_neighbor);
535
536 return true;
537}
538
539bool DenoiseImage::save_output(const string &out_filepath, string &error)
540{
541 /* Save image with identical dimensions, channels and metadata. */
542 ImageSpec out_spec = in_spec;
543
544 /* Ensure that the output frame contains sample information even if the input didn't. */
545 for (int i = 0; i < layers.size(); i++) {
546 string name = "cycles." + layers[i].name + ".samples";
547 if (!out_spec.find_attribute(name, TypeDesc::STRING)) {
548 out_spec.attribute(name, TypeDesc::STRING, string_printf("%d", layers[i].samples));
549 }
550 }
551
552 /* We don't need input anymore at this point, and will possibly
553 * overwrite the same file. */
554 close_input();
555
556 /* Write to temporary file path, so we denoise images in place and don't
557 * risk destroying files when something goes wrong in file saving. */
558 string extension = OIIO::Filesystem::extension(out_filepath);
559 string unique_name = ".denoise-tmp-" + OIIO::Filesystem::unique_path();
560 string tmp_filepath = out_filepath + unique_name + extension;
561 unique_ptr<ImageOutput> out(ImageOutput::create(tmp_filepath));
562
563 if (!out) {
564 error = "Failed to open temporary file " + tmp_filepath + " for writing";
565 return false;
566 }
567
568 /* Open temporary file and write image buffers. */
569 if (!out->open(tmp_filepath, out_spec)) {
570 error = "Failed to open file " + tmp_filepath + " for writing: " + out->geterror();
571 return false;
572 }
573
574 bool ok = true;
575 if (!out->write_image(TypeDesc::FLOAT, pixels.data())) {
576 error = "Failed to write to file " + tmp_filepath + ": " + out->geterror();
577 ok = false;
578 }
579
580 if (!out->close()) {
581 error = "Failed to save to file " + tmp_filepath + ": " + out->geterror();
582 ok = false;
583 }
584
585 out.reset();
586
587 /* Copy temporary file to output filepath. */
588 string rename_error;
589 if (ok && !OIIO::Filesystem::rename(tmp_filepath, out_filepath, rename_error)) {
590 error = "Failed to move denoised image to " + out_filepath + ": " + rename_error;
591 ok = false;
592 }
593
594 if (!ok) {
595 OIIO::Filesystem::remove(tmp_filepath);
596 }
597
598 return ok;
599}
600
601/* File pattern handling and outer loop over frames */
602
604{
605 /* Initialize task scheduler. */
607
608 /* Initialize device. */
609 device = Device::create(denoiser_device_info, stats, profiler, true);
611
612 vector<DeviceInfo> cpu_devices;
613 device_cpu_info(cpu_devices);
614 cpu_device = device_cpu_create(cpu_devices[0], device->stats, device->profiler, true);
615
617 denoiser->load_kernels(nullptr);
618}
619
621{
622 denoiser.reset();
623 delete device;
625}
626
628{
629 assert(input.size() == output.size());
630
631 int num_frames = output.size();
632
633 for (int frame = 0; frame < num_frames; frame++) {
634 /* Skip empty output paths. */
635 if (output[frame].empty()) {
636 continue;
637 }
638
639 /* Execute task. */
640 DenoiseTask task(device, this, frame);
641 if (!task.load()) {
642 error = task.error;
643 return false;
644 }
645
646 if (!task.exec()) {
647 error = task.error;
648 return false;
649 }
650
651 if (!task.save()) {
652 error = task.error;
653 return false;
654 }
655
656 task.free();
657 }
658
659 return true;
660}
661
static AppView * view
int pass_stride
Definition buffers.h:94
int full_width
Definition buffers.h:87
int get_pass_offset(PassType type, PassMode mode=PassMode::NOISY) const
Definition buffers.cpp:167
int full_height
Definition buffers.h:88
NODE_DECLARE int width
Definition buffers.h:72
void update_passes()
Definition buffers.cpp:120
void read_pixels(const DenoiseImageLayer &layer, const BufferParams &params, float *input_pixels)
bool parse_channels(const ImageSpec &in_spec, string &error)
void close_input()
vector< DenoiseImageLayer > layers
Definition denoising.h:107
bool read_previous_pixels(const DenoiseImageLayer &layer, const BufferParams &params, float *input_pixels)
int num_channels
Definition denoising.h:94
bool load(const string &in_filepath, string &error)
unique_ptr< ImageInput > in_previous
Definition denoising.h:104
bool load_previous(const string &in_filepath, string &error)
bool save_output(const string &out_filepath, string &error)
ImageSpec in_spec
Definition denoising.h:103
DenoiserPipeline * denoiser
Definition denoising.h:155
RenderBuffers buffers
Definition denoising.h:165
string error
Definition denoising.h:151
DenoiseTask(Device *device, DenoiserPipeline *denoiser, int frame)
bool load_input_pixels(int layer)
int current_layer
Definition denoising.h:163
std::unique_ptr< Denoiser > denoiser
Definition denoising.h:50
Device * cpu_device
Definition denoising.h:49
DenoiserPipeline(DeviceInfo &denoiser_device_info, const DenoiseParams &params)
Device * device
Definition denoising.h:48
vector< string > input
Definition denoising.h:37
Profiler profiler
Definition denoising.h:47
vector< string > output
Definition denoising.h:41
static unique_ptr< Denoiser > create(Device *denoise_device, Device *cpu_fallback_device, const DenoiseParams &params)
Definition denoiser.cpp:141
Profiler & profiler
Stats & stats
virtual bool load_kernels(uint)
static Device * create(const DeviceInfo &info, Stats &stats, Profiler &profiler, bool headless)
Definition pass.h:49
device_vector< float > buffer
Definition buffers.h:160
BufferParams params
Definition buffers.h:157
void reset(const BufferParams &params)
Definition buffers.cpp:274
static void exit()
Definition task.cpp:82
static void init(int num_threads=0)
Definition task.cpp:61
#define printf
static const int INPUT_NOISY_IMAGE
Definition denoising.cpp:73
static const int OUTPUT_NUM_CHANNELS
Definition denoising.cpp:87
static void fill_mapping(vector< ChannelMapping > &map, int pos, string name, string channels)
Definition denoising.cpp:65
static bool parse_channel_name(string name, string &renderlayer, string &pass, string &channel, bool multiview_channels)
Definition denoising.cpp:36
static CCL_NAMESPACE_BEGIN bool split_last_dot(string &in, string &suffix)
Definition denoising.cpp:21
static const int INPUT_DENOISING_ALBEDO
Definition denoising.cpp:75
static vector< ChannelMapping > output_channels()
Definition denoising.cpp:88
static const int INPUT_DENOISING_NORMAL
Definition denoising.cpp:74
static const int INPUT_NUM_CHANNELS
Definition denoising.cpp:72
static const int INPUT_MOTION
Definition denoising.cpp:76
static void add_pass(vector< Pass * > &passes, PassType type, PassMode mode=PassMode::NOISY)
static vector< ChannelMapping > input_channels()
Definition denoising.cpp:77
CCL_NAMESPACE_BEGIN Device * device_cpu_create(const DeviceInfo &info, Stats &stats, Profiler &profiler, bool headless)
void device_cpu_info(vector< DeviceInfo > &devices)
#define CCL_NAMESPACE_END
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
PassType
@ PASS_DENOISING_NORMAL
@ PASS_MOTION
@ PASS_COMBINED
@ PASS_DENOISING_ALBEDO
@ PASS_DENOISING_PREVIOUS
#define KERNEL_FEATURE_DENOISING
static void error(const char *str)
static void unique_name(bNode *node)
PassMode
Definition pass.h:20
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
Definition string.cpp:23
vector< int > previous_output_to_image_channel
Definition denoising.h:73
vector< int > input_to_image_channel
Definition denoising.h:66
bool match_channels(const std::vector< string > &channelnames, const std::vector< string > &neighbor_channelnames)
bool detect_denoising_channels()
Definition denoising.cpp:97
vector< int > output_to_image_channel
Definition denoising.h:70
vector< int > layer_to_image_channel
Definition denoising.h:60
char * buffers[2]