Compositor: Add High Precision option to Kuwahara #115763

Merged
Omar Emara merged 3 commits from OmarEmaraDev/blender:high-precision-classic-kuwahara into main 2024-01-17 14:30:39 +01:00
6 changed files with 36 additions and 8 deletions

View File

@ -25,6 +25,7 @@ void KuwaharaNode::convert_to_operations(NodeConverter &converter,
switch (data->variation) {
case CMP_NODE_KUWAHARA_CLASSIC: {
KuwaharaClassicOperation *kuwahara_classic = new KuwaharaClassicOperation();
kuwahara_classic->set_data(data);
converter.add_operation(kuwahara_classic);
converter.map_input_socket(get_input_socket(0), kuwahara_classic->get_input_socket(0));
converter.map_input_socket(get_input_socket(1), kuwahara_classic->get_input_socket(1));

View File

@ -54,8 +54,10 @@ void KuwaharaClassicOperation::execute_pixel_sampled(float output[4],
size_reader_->read_sampled(size, x, y, sampler);
const int kernel_size = int(math::max(0.0f, size[0]));
/* Naive implementation is more accurate for small kernel sizes. */
if (kernel_size >= 4) {
/* For high radii, we accelerate the filter using a summed area table, making the filter
* execute in constant time as opposed to having quadratic complexity. Except if high precision
* is enabled, since summed area tables are less precise. */
if (!data_->high_precision && size[0] > 5.0f) {
for (int q = 0; q < 4; q++) {
/* A fancy expression to compute the sign of the quadrant q. */
int2 sign = int2((q % 2) * 2 - 1, ((q / 2) * 2 - 1));
@ -172,10 +174,13 @@ void KuwaharaClassicOperation::update_memory_buffer_partial(MemoryBuffer *output
float4 mean_of_squared_color[4] = {float4(0.0f), float4(0.0f), float4(0.0f), float4(0.0f)};
int quadrant_pixel_count[4] = {0, 0, 0, 0};
const int kernel_size = int(math::max(0.0f, *size_image->get_elem(x, y)));
const float size = *size_image->get_elem(x, y);
const int kernel_size = int(math::max(0.0f, size));
/* Naive implementation is more accurate for small kernel sizes. */
if (kernel_size >= 4) {
/* For high radii, we accelerate the filter using a summed area table, making the filter
* execute in constant time as opposed to having quadratic complexity. Except if high precision
* is enabled, since summed area tables are less precise. */
if (!data_->high_precision && size > 5.0f) {
for (int q = 0; q < 4; q++) {
/* A fancy expression to compute the sign of the quadrant q. */
int2 sign = int2((q % 2) * 2 - 1, ((q / 2) * 2 - 1));

View File

@ -9,6 +9,7 @@
namespace blender::compositor {
class KuwaharaClassicOperation : public MultiThreadedOperation {
const NodeKuwaharaData *data_;
SocketReader *image_reader_;
SocketReader *size_reader_;
SocketReader *sat_reader_;
@ -17,6 +18,11 @@ class KuwaharaClassicOperation : public MultiThreadedOperation {
public:
KuwaharaClassicOperation();
void set_data(const NodeKuwaharaData *data)
{
data_ = data;
}
void init_execution() override;
void deinit_execution() override;
void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;

View File

@ -1067,6 +1067,8 @@ typedef struct NodeKuwaharaData {
int uniformity;
float sharpness;
float eccentricity;
char high_precision;
char _pad[3];
} NodeKuwaharaData;
typedef struct NodeAntiAliasingData {

View File

@ -8582,6 +8582,14 @@ static void def_cmp_kuwahara(StructRNA *srna)
RNA_def_property_ui_text(prop, "", "Variation of Kuwahara filter to use");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "use_high_precision", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "high_precision", 1);
RNA_def_property_ui_text(
prop,
"High Precision",
"Uses a more precise but slower method. Use if the output contains undesirable noise");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "uniformity", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, nullptr, "uniformity");
RNA_def_property_range(prop, 0.0, 50.0);

View File

@ -57,7 +57,10 @@ static void node_composit_buts_kuwahara(uiLayout *layout, bContext * /*C*/, Poin
const int variation = RNA_enum_get(ptr, "variation");
if (variation == CMP_NODE_KUWAHARA_ANISOTROPIC) {
if (variation == CMP_NODE_KUWAHARA_CLASSIC) {
uiItemR(col, ptr, "use_high_precision", UI_ITEM_NONE, nullptr, ICON_NONE);
}
else if (variation == CMP_NODE_KUWAHARA_ANISOTROPIC) {
uiItemR(col, ptr, "uniformity", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(col, ptr, "sharpness", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(col, ptr, "eccentricity", UI_ITEM_NONE, nullptr, ICON_NONE);
@ -88,9 +91,12 @@ class ConvertKuwaharaOperation : public NodeOperation {
void execute_classic()
{
/* For high radii, we accelerate the filter using a summed area table, making the filter
* execute in constant time as opposed to the trivial quadratic complexity. */
* execute in constant time as opposed to having quadratic complexity. Except if high precision
* is enabled, since summed area tables are less precise. */
Result &size_input = get_input("Size");
if (size_input.is_single_value() && size_input.get_float_value() > 5.0f) {
if (!node_storage(bnode()).high_precision &&
(size_input.is_texture() || size_input.get_float_value() > 5.0f))
{
execute_classic_summed_area_table();
return;
}