12#include <OpenImageIO/filesystem.h>
22 const size_t pos =
in.rfind(
".");
23 if (
pos == string::npos) {
26 suffix =
in.substr(
pos + 1);
36 string name,
string &renderlayer,
string &pass,
string &channel,
bool multiview_channels)
50 if (multiview_channels) {
51 renderlayer +=
"." +
view;
66 for (
const char *chan = channels.c_str(); *chan; chan++) {
67 map.push_back({
pos++,
name +
"." + *chan});
108 const size_t input_channel = mapping.channel;
109 const size_t layer_channel =
i -
channels.begin();
123 const size_t output_channel = mapping.channel;
124 const size_t layer_channel =
i -
channels.begin();
140 const std::vector<string> &neighbor_channelnames)
149 const std::vector<string>::const_iterator frame_channel = find(
150 neighbor_channelnames.begin(), neighbor_channelnames.end(), channel);
152 if (frame_channel == neighbor_channelnames.end()) {
156 mapping[
i] = frame_channel - neighbor_channelnames.begin();
181 float *buffer_data =
buffers.buffer.data();
182 image.read_pixels(image_layer,
buffers.params, buffer_data);
185 if (
frame > 0 && !
image.read_previous_pixels(image_layer,
buffers.params, buffer_data)) {
186 error =
"Failed to read neighbor frame pixels";
191 buffers.buffer.copy_to_device();
203 pass->set_type(type);
204 pass->set_mode(mode);
221 if (
image.layers.empty()) {
222 error =
"No image layers found to denoise in " + center_filepath;
277 buffers.buffer.copy_from_device();
285 for (
int y = 0;
y <
image.height;
y++) {
289 const int image_channel = output_to_image_channel[j];
341 const std::vector<string> &channels =
in_spec.channelnames;
342 const ParamValue *multiview =
in_spec.find_attribute(
"multiView");
343 const bool multiview_channels = (multiview && multiview->type().basetype == TypeDesc::STRING &&
344 multiview->type().arraylen >= 2);
351 map<string, DenoiseImageLayer> file_layers;
352 for (
int i = 0;
i < channels.size();
i++) {
357 file_layers[layer].channels.push_back(pass +
"." + channel);
358 file_layers[layer].layer_to_image_channel.push_back(
i);
364 for (map<string, DenoiseImageLayer>::iterator
i = file_layers.begin();
i != file_layers.end();
367 const string &
name =
i->first;
381 const string sample_string =
in_spec.get_string_attribute(
"cycles." +
name +
".samples",
"");
382 if (!sample_string.empty()) {
383 if (!sscanf(sample_string.c_str(),
"%d", &layer.
samples)) {
384 error =
"Failed to parse samples metadata: " + sample_string;
392 "No sample number specified in the file for layer %s or on the command line",
412 for (
int j = 0; j < 3; ++j) {
415 input_pixels[
i *
params.pass_stride + offset + j] =
418 for (
int j = 0; j < 3; ++j) {
421 input_pixels[
i *
params.pass_stride + offset + j] =
424 for (
int j = 0; j < 3; ++j) {
427 input_pixels[
i *
params.pass_stride + offset + j] =
430 for (
int j = 0; j < 4; ++j) {
432 const int image_channel = input_to_image_channel[
INPUT_MOTION + j];
433 input_pixels[
i *
params.pass_stride + offset + j] =
445 const size_t num_pixels = (size_t)
width * (
size_t)
height;
457 for (
int j = 0; j < 3; ++j) {
459 const int image_channel = output_to_image_channel[j];
460 input_pixels[
i *
params.pass_stride + offset + j] =
470 if (!Filesystem::is_regular(in_filepath)) {
471 error =
"Couldn't find file: " + in_filepath;
477 error =
"Couldn't open file: " + in_filepath;
491 error =
"Could not find a render layer containing denoising data and motion vector passes";
495 const size_t num_pixels = (size_t)
width * (
size_t)
height;
501 error =
"Failed to read image: " + in_filepath;
510 if (!Filesystem::is_regular(filepath)) {
511 error =
"Couldn't find neighbor frame: " + filepath;
517 error =
"Couldn't open neighbor frame: " + filepath;
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;
528 if (!layer.match_channels(
in_spec.channelnames, neighbor_spec.channelnames)) {
529 error =
"Neighbor frame misses denoising data passes: " + filepath;
545 for (
int i = 0;
i <
layers.size();
i++) {
546 const string name =
"cycles." +
layers[
i].name +
".samples";
547 if (!out_spec.find_attribute(
name, TypeDesc::STRING)) {
558 const string extension = OIIO::Filesystem::extension(out_filepath);
559 const string unique_name =
".denoise-tmp-" + OIIO::Filesystem::unique_path();
560 const string tmp_filepath = out_filepath +
unique_name + extension;
564 error =
"Failed to open temporary file " + tmp_filepath +
" for writing";
569 if (!
out->open(tmp_filepath, out_spec)) {
570 error =
"Failed to open file " + tmp_filepath +
" for writing: " +
out->geterror();
575 if (!
out->write_image(TypeDesc::FLOAT,
pixels.data())) {
576 error =
"Failed to write to file " + tmp_filepath +
": " +
out->geterror();
581 error =
"Failed to save to file " + tmp_filepath +
": " +
out->geterror();
589 if (ok && !OIIO::Filesystem::rename(tmp_filepath, out_filepath, rename_error)) {
590 error =
"Failed to move denoised image to " + out_filepath +
": " + rename_error;
595 OIIO::Filesystem::remove(tmp_filepath);
633 const int num_frames =
output.size();
636 error =
"Failed to create denoiser";
640 for (
int frame = 0; frame < num_frames; frame++) {
642 if (
output[frame].empty()) {
void read_pixels(const DenoiseImageLayer &layer, const BufferParams ¶ms, float *input_pixels)
bool parse_channels(const ImageSpec &in_spec, string &error)
vector< DenoiseImageLayer > layers
bool read_previous_pixels(const DenoiseImageLayer &layer, const BufferParams ¶ms, float *input_pixels)
bool load(const string &in_filepath, string &error)
unique_ptr< ImageInput > in_previous
bool load_previous(const string &in_filepath, string &error)
bool save_output(const string &out_filepath, string &error)
DenoiserPipeline * denoiser
bool load_input_pixels(const int layer)
DenoiseTask(Device *device, DenoiserPipeline *denoiser, const int frame)
std::unique_ptr< Denoiser > denoiser
DenoiserPipeline(DeviceInfo &denoiser_device_info, const DenoiseParams ¶ms)
unique_ptr< Device > cpu_device
unique_ptr< Device > device
static unique_ptr< Denoiser > create(Device *denoiser_device, Device *cpu_fallback_device, const DenoiseParams ¶ms, const GraphicsInteropDevice &interop_device)
static unique_ptr< Device > create(const DeviceInfo &info, Stats &stats, Profiler &profiler, bool headless)
static void init(const int num_threads=0)
void push_back(unique_ptr< T > &&value)
static const int INPUT_NOISY_IMAGE
static const int OUTPUT_NUM_CHANNELS
static void fill_mapping(vector< ChannelMapping > &map, int pos, string name, string channels)
static bool parse_channel_name(string name, string &renderlayer, string &pass, string &channel, bool multiview_channels)
static CCL_NAMESPACE_BEGIN bool split_last_dot(string &in, string &suffix)
static const int INPUT_DENOISING_ALBEDO
static vector< ChannelMapping > output_channels()
static const int INPUT_DENOISING_NORMAL
static const int INPUT_NUM_CHANNELS
static const int INPUT_MOTION
static void add_pass(unique_ptr_vector< Pass > &passes, PassType type, PassMode mode=PassMode::NOISY)
static vector< ChannelMapping > input_channels()
void device_cpu_info(vector< DeviceInfo > &devices)
CCL_NAMESPACE_BEGIN unique_ptr< Device > device_cpu_create(const DeviceInfo &info, Stats &stats, Profiler &profiler, bool headless)
#define KERNEL_FEATURE_DENOISING
#define CCL_NAMESPACE_END
#define assert(assertion)
@ PASS_DENOISING_PREVIOUS
static void error(const char *str)
static void unique_name(bNode *node)
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
vector< int > previous_output_to_image_channel
vector< int > input_to_image_channel
bool match_channels(const std::vector< string > &channelnames, const std::vector< string > &neighbor_channelnames)
bool detect_denoising_channels()
vector< int > output_to_image_channel
vector< string > channels
vector< int > layer_to_image_channel