Compositor: add new node: Kuwahara filter #107015

Merged
Habib Gahbiche merged 22 commits from zazizizou/blender:com-kuwahara-filter-node into main 2023-06-08 16:14:51 +02:00
15 changed files with 394 additions and 0 deletions
Showing only changes of commit c1fb210be9 - Show all commits

View File

@ -336,6 +336,7 @@ compositor_node_categories = [
NodeItem("CompositorNodeSunBeams"),
NodeItem("CompositorNodeDenoise"),
NodeItem("CompositorNodeAntiAliasing"),
NodeItem("CompositorNodeKuwahara"),
]),
CompositorNodeCategory("CMP_OP_VECTOR", "Vector", items=[
NodeItem("CompositorNodeNormal"),

View File

@ -1333,6 +1333,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define CMP_NODE_INPAINT 272
#define CMP_NODE_DESPECKLE 273
#define CMP_NODE_ANTIALIASING 274
#define CMP_NODE_KUWAHARA 275
#define CMP_NODE_GLARE 301
#define CMP_NODE_TONEMAP 302

View File

@ -321,6 +321,8 @@ if(WITH_COMPOSITOR_CPU)
nodes/COM_FilterNode.h
nodes/COM_InpaintNode.cc
nodes/COM_InpaintNode.h
nodes/COM_KuwaharaNode.h
nodes/COM_KuwaharaNode.cc
nodes/COM_PosterizeNode.cc
nodes/COM_PosterizeNode.h
@ -348,6 +350,8 @@ if(WITH_COMPOSITOR_CPU)
operations/COM_GaussianXBlurOperation.h
operations/COM_GaussianYBlurOperation.cc
operations/COM_GaussianYBlurOperation.h
operations/COM_KuwaharaOperation.h
operations/COM_KuwaharaOperation.cc
operations/COM_MovieClipAttributeOperation.cc
operations/COM_MovieClipAttributeOperation.h
operations/COM_MovieDistortionOperation.cc

View File

@ -61,6 +61,7 @@
#include "COM_InvertNode.h"
#include "COM_KeyingNode.h"
#include "COM_KeyingScreenNode.h"
#include "COM_KuwaharaNode.h"
#include "COM_LensDistortionNode.h"
#include "COM_LuminanceMatteNode.h"
#include "COM_MapRangeNode.h"
@ -435,6 +436,9 @@ Node *COM_convert_bnode(bNode *b_node)
case CMP_NODE_COMBINE_XYZ:
node = new CombineXYZNode(b_node);
break;
case CMP_NODE_KUWAHARA:
node = new KuwaharaNode(b_node);
break;
}
return node;
}

View File

@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2011 Blender Foundation. */
#include "COM_KuwaharaNode.h"
#include "COM_KuwaharaOperation.h"
namespace blender::compositor {
void KuwaharaNode::convert_to_operations(NodeConverter &converter,
const CompositorContext & /*context*/) const
{
const bNode *node = this->get_bnode();
const NodeKuwaharaData *data = (const NodeKuwaharaData *)node->storage;
KuwaharaOperation *operation = new KuwaharaOperation();
operation->set_kernel_size(data->kernel_size);
operation->set_variation(data->variation);
converter.add_operation(operation);
converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
}
} // namespace blender::compositor

View File

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2011 Blender Foundation. */
#pragma once
#include "COM_Node.h"
namespace blender::compositor {
/**
* \brief KuwaharaNode
* \ingroup Node
*/
class KuwaharaNode : public Node {
public:
KuwaharaNode(bNode *editor_node) : Node(editor_node) {}
void convert_to_operations(NodeConverter &converter,
const CompositorContext &context) const override;
};
} // namespace blender::compositor

View File

@ -0,0 +1,159 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2011 Blender Foundation. */
#include "COM_KuwaharaOperation.h"
namespace blender::compositor {
KuwaharaOperation::KuwaharaOperation()
{
this->add_input_socket(DataType::Color);
this->add_output_socket(DataType::Color);
this->set_kernel_size(4.4f);
this->flags_.is_fullframe_operation = true;
}
void KuwaharaOperation::init_execution()
{
image_reader_ = this->get_input_socket_reader(0);
}
void KuwaharaOperation::deinit_execution()
{
image_reader_ = nullptr;
}
void KuwaharaOperation::execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler)
{
float input_value[4];
image_reader_->read_sampled(input_value, x, y, sampler);
output[0] = input_value[0] + 1.0;
output[1] = input_value[1] + 2.0;
output[2] = input_value[2] + 3.0;
output[3] = input_value[3] + 4.0;
}
void KuwaharaOperation::set_kernel_size(int kernel_size)
{
kernel_size_ = kernel_size;
}
int KuwaharaOperation::get_kernel_size()
{
return kernel_size_;
}
void KuwaharaOperation::set_variation(int variation)
{
variation_ = variation;
}
int KuwaharaOperation::get_variation()
{
return variation_;
}
void KuwaharaOperation::update_memory_buffer(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
MemoryBuffer *image = inputs[0];
const int bwidth = area.xmax - area.xmin;
const int bheight = area.ymax - area.ymin;
// for (int y = 0; y < bheight; y++)
// {
// for (int x = 0; x < bwidth; x++)
// {
// output->get_value(x, y, 3) = 1;
// }
// }
for (int ch = 0; ch < 3; ch++)
{
for (int y = 0; y < bheight; y++)
{
for (int x = 0; x < bwidth; x++)
{
float sum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float var[4] = {0.0f, 0.0f, 0.0f, 0.0f};
int cnt[4] = {0, 0, 0, 0};
for (int dy = -kernel_size_; dy <= kernel_size_; dy++)
{
for (int dx = -kernel_size_; dx <= kernel_size_; dx++)
{
int xx = x + dx;
int yy = y + dy;
if (xx >= 0 && yy >= 0 && xx < area.xmax && yy < area.ymax)
{
//double v = temp.at<float>(yy, xx * dim + c);
float v;
v = image->get_value(xx, yy, ch);
if (dx <= 0 && dy <= 0)
{
sum[0] += v;
var[0] += v * v;
cnt[0]++;
}
if (dx >= 0 && dy <= 0)
{
sum[1] += v;
var[1] += v * v;
cnt[1]++;
}
if (dx <= 0 && dy >= 0)
{
sum[2] += v;
var[2] += v * v;
cnt[2]++;
}
if (dx >= 0 && dy >= 0)
{
sum[3] += v;
var[3] += v * v;
cnt[3]++;
}
}
}
}
std::vector<std::pair<double, int>> vec;
for (int i = 0; i < 4; i++)
{
sum[i] = cnt[i] != 0 ? sum[i] / cnt[i] : 0.0f;
var[i] = cnt[i] != 0 ? var[i] / cnt[i] : 0.0f;
var[i] = sqrt(var[i] - sum[i] * sum[i]);
vec.push_back(std::make_pair(var[i], i));
}
sort(vec.begin(), vec.end());
std::cout << "x: " << x << " y: " << y << std::endl;
for (int i = 0; i < 4; i++)
{
std::cout << "\t" << vec[i].first << " " << vec[i].second << std::endl;
}
//out.at<float>(y, x * dim + c) = static_cast<float>(sum[vec[0].second]);
float res = static_cast<float>(sum[vec[0].second]);
output->get_value(x, y, ch) = res;
}
}
}
}
void KuwaharaOperation::get_area_of_interest(const int /*input_idx*/,
const rcti & /*output_area*/,
rcti &r_input_area)
{
r_input_area = this->get_canvas();
}
} // namespace blender::compositor

View File

@ -0,0 +1,47 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2011 Blender Foundation. */
#pragma once
#include "COM_NodeOperation.h"
namespace blender::compositor {
class KuwaharaOperation : public NodeOperation {
SocketReader *image_reader_;
int kernel_size_;
int variation_;
public:
KuwaharaOperation();
void init_execution() override;
void deinit_execution() override;
void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
void set_kernel_size(int kernel_size);
int get_kernel_size();
void set_variation(int variation);
int get_variation();
void update_memory_buffer(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
void get_area_of_interest(const int input_idx,
const rcti & output_area,
rcti &r_input_area) override;
//
// bool determine_depending_area_of_interest(rcti *input,
// ReadBufferOperation *read_operation,
// rcti *output) override;
//
// void update_memory_buffer_partial(MemoryBuffer *output,
// const rcti &area,
// Span<MemoryBuffer *> inputs) override;
};
} // namespace blender::compositor

View File

@ -876,6 +876,12 @@ typedef struct NodeBilateralBlurData {
char _pad[2];
} NodeBilateralBlurData;
typedef struct NodeKuwaharaData {
short kernel_size;
short variation;
char _pad[4];
} NodeKuwaharaData;
typedef struct NodeAntiAliasingData {
float threshold;
float contrast_limit;

View File

@ -9242,6 +9242,31 @@ static void def_cmp_denoise(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_cmp_kuwahara(StructRNA *srna)
{
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "NodeKuwaharaData", "storage");
static const EnumPropertyItem variation_items[] = {
{0, "CLASSIC", 0, "Classic", "Fast but less accurate variation"},
{1, "ANISOTROPIC", 0, "Anisotropic", "Accurate but slower variation"},
{0, NULL, 0, NULL, NULL},
};
prop = RNA_def_property(srna, "kernel_size", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "kernel_size");
RNA_def_property_ui_text(
prop, "Kernel Size", "Kernel size of filter. The larger the stronger the effect");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "variation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "variation");
RNA_def_property_enum_items(prop, variation_items);
RNA_def_property_ui_text(prop, "", "Variation of Kuwahara filter to use.");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_cmp_antialiasing(StructRNA *srna)
{
PropertyRNA *prop;

View File

@ -223,6 +223,7 @@ DefNode(CompositorNode, CMP_NODE_COMBINE_XYZ, 0, "COMBIN
DefNode(CompositorNode, CMP_NODE_SEPARATE_XYZ, 0, "SEPARATE_XYZ", SeparateXYZ, "Separate XYZ", "" )
DefNode(CompositorNode, CMP_NODE_SEPARATE_COLOR, def_cmp_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "" )
DefNode(CompositorNode, CMP_NODE_COMBINE_COLOR, def_cmp_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "" )
DefNode(CompositorNode, CMP_NODE_KUWAHARA, def_cmp_kuwahara, "KUWAHARA", Kuwahara, "Kuwahara", "" )
DefNode(TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" )
DefNode(TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" )

View File

@ -76,6 +76,7 @@ set(SRC
nodes/node_composite_invert.cc
nodes/node_composite_keying.cc
nodes/node_composite_keyingscreen.cc
nodes/node_composite_kuwahara.cc
nodes/node_composite_lensdist.cc
nodes/node_composite_levels.cc
nodes/node_composite_luma_matte.cc

View File

@ -62,6 +62,7 @@ void register_composite_nodes()
register_node_type_cmp_invert();
register_node_type_cmp_keying();
register_node_type_cmp_keyingscreen();
register_node_type_cmp_kuwahara();
register_node_type_cmp_lensdist();
register_node_type_cmp_luma_matte();
register_node_type_cmp_map_range();

View File

@ -58,6 +58,7 @@ void register_node_type_cmp_inpaint();
void register_node_type_cmp_invert();
void register_node_type_cmp_keying();
void register_node_type_cmp_keyingscreen();
void register_node_type_cmp_kuwahara();
void register_node_type_cmp_lensdist();
void register_node_type_cmp_luma_matte();
void register_node_type_cmp_map_range();

View File

@ -0,0 +1,97 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2020 Blender Foundation */
/** \file
* \ingroup cmpnodes
*/
//#include "COM_shader_node.hh"
#include "COM_node_operation.hh"
#include "node_composite_util.hh"
/* **************** Kuwahara ******************** */
namespace blender::nodes::node_composite_kuwahara_cc {
NODE_STORAGE_FUNCS(NodeKuwaharaData)
static void cmp_node_kuwahara_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>(N_("Image"))
.default_value({1.0f, 1.0f, 1.0f, 1.0f})
.compositor_domain_priority(0);
b.add_output<decl::Color>(N_("Image"));
}
static void node_composit_init_kuwahara(bNodeTree * /*ntree*/, bNode *node)
{
NodeKuwaharaData *data = MEM_cnew<NodeKuwaharaData>(__func__);
node->storage = data;
data->kernel_size = 4.1f;
}
static void node_composit_buts_kuwahara(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiLayout *col;
col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "variation", 0, nullptr, ICON_NONE);
uiItemR(col, ptr, "kernel_size", 0, nullptr, ICON_NONE);
}
//using namespace blender::realtime_compositor;
//
//class KuwaharaShaderNode : public NodeOperation {
// public:
// using NodeOperation::NodeOperation;
//
// void execute() override
// {
// get_input("Image").pass_through(get_result("Image"));
// context().set_info_message("Viewport compositor setup not fully supported");
// }
// using ShaderNode::ShaderNode;
//
// void compile(GPUMaterial *material) override
// {
// GPUNodeStack *inputs = get_inputs_array();
// GPUNodeStack *outputs = get_outputs_array();
//
// GPU_stack_link(material, &bnode(), "node_composite_kuwahara", inputs, outputs);
// }
//};
//
//static NodeOperation *get_compositor_operation(Context *context, DNode node)
//{
// return new KuwaharaOperation(context, node);
//}
//static ShaderNode *get_compositor_shader_node(DNode node)
//{
// return new KuwaharaShaderNode(node);
//}
} // namespace blender::nodes::node_composite_kuwahara_cc
void register_node_type_cmp_kuwahara()
{
namespace file_ns = blender::nodes::node_composite_kuwahara_cc;
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_KUWAHARA, "Kuwahara", NODE_CLASS_OP_COLOR);
ntype.declare = file_ns::cmp_node_kuwahara_declare;
ntype.draw_buttons = file_ns::node_composit_buts_kuwahara;
ntype.initfunc = file_ns::node_composit_init_kuwahara;
node_type_storage(
&ntype, "NodeKuwaharaData", node_free_standard_storage, node_copy_standard_storage);
// ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
nodeRegisterType(&ntype);
}