Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Stockner <lukas.stockner@freenet.de>2019-02-06 14:57:10 +0300
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2019-02-11 15:39:08 +0300
commite379a9ba918dbf27e81fd289e98314197109b54c (patch)
tree053fb40f47cdab5b42ed7f4ab40421c6317e8324 /intern/cycles/blender/blender_python.cpp
parent382fe85e293e3d00bd7e494bd270cd32bec8ecb6 (diff)
Cycles: add animation denoising Python operator.
This adds a cycles.denoise_animation operator, which denoises an animation sequence or individual file. Renders must be saved as multilayer EXR files with denoising data passes. By default file path and frame range come from the current scene, and EXR files are denoised in-place. Alternatively, a different input and/or output file path can be provided. Denoising settings come from the current view layer. Renders can be denoised again with different settings, as the original noisy image is preserved along with other passes and metadata. There is no user interface yet for this feature, that comes later. Code by Lukas with modifications by Brecht. This feature was originally developed for Tangent Animation, thanks for the support! Differential Revision: https://developer.blender.org/D3889
Diffstat (limited to 'intern/cycles/blender/blender_python.cpp')
-rw-r--r--intern/cycles/blender/blender_python.cpp121
1 files changed, 121 insertions, 0 deletions
diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp
index 9dd0cd4c0bc..bf7605ed5b1 100644
--- a/intern/cycles/blender/blender_python.cpp
+++ b/intern/cycles/blender/blender_python.cpp
@@ -18,9 +18,12 @@
#include "blender/CCL_api.h"
+#include "blender/blender_device.h"
#include "blender/blender_sync.h"
#include "blender/blender_session.h"
+#include "render/denoising.h"
+
#include "util/util_debug.h"
#include "util/util_foreach.h"
#include "util/util_logging.h"
@@ -623,6 +626,121 @@ static PyObject *opencl_disable_func(PyObject * /*self*/, PyObject * /*value*/)
}
#endif
+static bool denoise_parse_filepaths(PyObject *pyfilepaths, vector<string>& filepaths)
+{
+
+ if(PyUnicode_Check(pyfilepaths)) {
+ const char *filepath = PyUnicode_AsUTF8(pyfilepaths);
+ filepaths.push_back(filepath);
+ return true;
+ }
+
+ PyObject *sequence = PySequence_Fast(pyfilepaths, "File paths must be a string or sequence of strings");
+ if(sequence == NULL) {
+ return false;
+ }
+
+ for(Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(sequence); i++) {
+ PyObject *item = PySequence_Fast_GET_ITEM(sequence, i);
+ const char *filepath = PyUnicode_AsUTF8(item);
+ if(filepath == NULL) {
+ PyErr_SetString(PyExc_ValueError, "File paths must be a string or sequence of strings.");
+ Py_DECREF(sequence);
+ return false;
+ }
+ filepaths.push_back(filepath);
+ }
+ Py_DECREF(sequence);
+
+ return true;
+}
+
+static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *keywords)
+{
+ static const char *keyword_list[] = {"preferences", "scene", "view_layer",
+ "input", "output",
+ "tile_size", "samples", NULL};
+ PyObject *pypreferences, *pyscene, *pyrenderlayer;
+ PyObject *pyinput, *pyoutput = NULL;
+ int tile_size = 0, samples = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, keywords, "OOOO|Oii", (char**)keyword_list,
+ &pypreferences, &pyscene, &pyrenderlayer,
+ &pyinput, &pyoutput,
+ &tile_size, &samples)) {
+ return NULL;
+ }
+
+ /* Get device specification from preferences and scene. */
+ PointerRNA preferencesptr;
+ RNA_pointer_create(NULL, &RNA_UserPreferences, (void*)PyLong_AsVoidPtr(pypreferences), &preferencesptr);
+ BL::UserPreferences b_preferences(preferencesptr);
+
+ PointerRNA sceneptr;
+ RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
+ BL::Scene b_scene(sceneptr);
+
+ DeviceInfo device = blender_device_info(b_preferences, b_scene, true);
+
+ /* Get denoising parameters from view layer. */
+ PointerRNA renderlayerptr;
+ RNA_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &RNA_SceneRenderLayer, PyLong_AsVoidPtr(pyrenderlayer), &renderlayerptr);
+ PointerRNA crenderlayer = RNA_pointer_get(&renderlayerptr, "cycles");
+
+ DenoiseParams params;
+ params.radius = get_int(crenderlayer, "denoising_radius");
+ params.strength = get_float(crenderlayer, "denoising_strength");
+ params.feature_strength = get_float(crenderlayer, "denoising_feature_strength");
+ params.relative_pca = get_boolean(crenderlayer, "denoising_relative_pca");
+ params.neighbor_frames = get_int(crenderlayer, "denoising_neighbor_frames");
+
+ /* Parse file paths list. */
+ vector<string> input, output;
+
+ if(!denoise_parse_filepaths(pyinput, input)) {
+ return NULL;
+ }
+
+ if(pyoutput) {
+ if(!denoise_parse_filepaths(pyoutput, output)) {
+ return NULL;
+ }
+ }
+ else {
+ output = input;
+ }
+
+ if(input.empty()) {
+ PyErr_SetString(PyExc_ValueError, "No input file paths specified.");
+ return NULL;
+ }
+ if(input.size() != output.size()) {
+ PyErr_SetString(PyExc_ValueError, "Number of input and output file paths does not match.");
+ return NULL;
+ }
+
+ /* Create denoiser. */
+ Denoiser denoiser(device);
+ denoiser.params = params;
+ denoiser.input = input;
+ denoiser.output = output;
+
+ if (tile_size > 0) {
+ denoiser.tile_size = make_int2(tile_size, tile_size);
+ }
+ if (samples > 0) {
+ denoiser.samples_override = samples;
+ }
+
+ /* Run denoiser. */
+ if(!denoiser.run()) {
+ PyErr_SetString(PyExc_ValueError, denoiser.error.c_str());
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
static PyObject *debug_flags_update_func(PyObject * /*self*/, PyObject *args)
{
PyObject *pyscene;
@@ -783,6 +901,9 @@ static PyMethodDef methods[] = {
{"opencl_disable", opencl_disable_func, METH_NOARGS, ""},
#endif
+ /* Standalone denoising */
+ {"denoise", (PyCFunction)denoise_func, METH_VARARGS|METH_KEYWORDS, ""},
+
/* Debugging routines */
{"debug_flags_update", debug_flags_update_func, METH_VARARGS, ""},
{"debug_flags_reset", debug_flags_reset_func, METH_NOARGS, ""},