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];
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);
353 map<string, DenoiseImageLayer> file_layers;
354 for (
int i = 0;
i < channels.size();
i++) {
359 file_layers[layer].channels.push_back(pass +
"." + channel);
360 file_layers[layer].layer_to_image_channel.push_back(
i);
366 for (map<string, DenoiseImageLayer>::iterator
i = file_layers.begin();
i != file_layers.end();
369 const string &name =
i->first;
383 const string sample_string =
in_spec.get_string_attribute(
"cycles." + name +
".samples",
"");
384 if (!sample_string.empty()) {
385 if (!sscanf(sample_string.c_str(),
"%d", &layer.
samples)) {
386 error =
"Failed to parse samples metadata: " + sample_string;
394 "No sample number specified in the file for layer %s or on the command line",
414 for (
int j = 0; j < 3; ++j) {
417 input_pixels[
i *
params.pass_stride + offset + j] =
420 for (
int j = 0; j < 3; ++j) {
423 input_pixels[
i *
params.pass_stride + offset + j] =
426 for (
int j = 0; j < 3; ++j) {
429 input_pixels[
i *
params.pass_stride + offset + j] =
432 for (
int j = 0; j < 4; ++j) {
434 const int image_channel = input_to_image_channel[
INPUT_MOTION + j];
435 input_pixels[
i *
params.pass_stride + offset + j] =
447 const size_t num_pixels = (size_t)
width * (
size_t)
height;
459 for (
int j = 0; j < 3; ++j) {
461 const int image_channel = output_to_image_channel[j];
462 input_pixels[
i *
params.pass_stride + offset + j] =
472 if (!Filesystem::is_regular(in_filepath)) {
473 error =
"Couldn't find file: " + in_filepath;
479 error =
"Couldn't open file: " + in_filepath;
493 error =
"Could not find a render layer containing denoising data and motion vector passes";
497 const size_t num_pixels = (size_t)
width * (
size_t)
height;
503 error =
"Failed to read image: " + in_filepath;
512 if (!Filesystem::is_regular(filepath)) {
513 error =
"Couldn't find neighbor frame: " + filepath;
519 error =
"Couldn't open neighbor frame: " + filepath;
523 const ImageSpec &neighbor_spec = in_neighbor->spec();
524 if (neighbor_spec.width !=
width || neighbor_spec.height !=
height) {
525 error =
"Neighbor frame has different dimensions: " + filepath;
530 if (!layer.match_channels(
in_spec.channelnames, neighbor_spec.channelnames)) {
531 error =
"Neighbor frame misses denoising data passes: " + filepath;
547 for (
int i = 0;
i <
layers.size();
i++) {
548 const string name =
"cycles." +
layers[
i].name +
".samples";
549 if (!out_spec.find_attribute(name, TypeDesc::STRING)) {
560 const string extension = OIIO::Filesystem::extension(out_filepath);
561 const string unique_name =
".denoise-tmp-" + OIIO::Filesystem::unique_path();
562 const string tmp_filepath = out_filepath +
unique_name + extension;
566 error =
"Failed to open temporary file " + tmp_filepath +
" for writing";
571 if (!
out->open(tmp_filepath, out_spec)) {
572 error =
"Failed to open file " + tmp_filepath +
" for writing: " +
out->geterror();
577 if (!
out->write_image(TypeDesc::FLOAT,
pixels.data())) {
578 error =
"Failed to write to file " + tmp_filepath +
": " +
out->geterror();
583 error =
"Failed to save to file " + tmp_filepath +
": " +
out->geterror();
591 if (ok && !OIIO::Filesystem::rename(tmp_filepath, out_filepath, rename_error)) {
592 error =
"Failed to move denoised image to " + out_filepath +
": " + rename_error;
597 OIIO::Filesystem::remove(tmp_filepath);
635 const int num_frames =
output.size();
638 error =
"Failed to create denoiser";
642 for (
int frame = 0; frame < num_frames; frame++) {
644 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