Compositor: add new node: Kuwahara filter #107015
|
@ -336,6 +336,7 @@ compositor_node_categories = [
|
|||
NodeItem("CompositorNodeSunBeams"),
|
||||
NodeItem("CompositorNodeDenoise"),
|
||||
NodeItem("CompositorNodeAntiAliasing"),
|
||||
NodeItem("CompositorNodeKuwahara"),
|
||||
]),
|
||||
CompositorNodeCategory("CMP_OP_VECTOR", "Vector", items=[
|
||||
NodeItem("CompositorNodeNormal"),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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", "" )
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue