Compositor: add new node: Kuwahara filter #107015
|
@ -3,6 +3,7 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "COM_KuwaharaNode.h"
|
||||
|
||||
#include "COM_FastGaussianBlurOperation.h"
|
||||
#include "COM_KuwaharaAnisotropicOperation.h"
|
||||
#include "COM_KuwaharaClassicOperation.h"
|
||||
|
@ -82,7 +83,7 @@ void KuwaharaNode::convert_to_operations(NodeConverter &converter,
|
|||
converter.add_link(sobel_yy->get_output_socket(0), blur_sobel_yy->get_input_socket(0));
|
||||
converter.add_link(sobel_xy->get_output_socket(0), blur_sobel_xy->get_input_socket(0));
|
||||
|
||||
/* Apply anisotropic Kuwahara filter */
|
||||
/* Apply anisotropic Kuwahara filter. */
|
||||
KuwaharaAnisotropicOperation *aniso = new KuwaharaAnisotropicOperation();
|
||||
aniso->set_kernel_size(data->size + 4);
|
||||
converter.map_input_socket(get_input_socket(0), aniso->get_input_socket(0));
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "COM_KuwaharaAnisotropicOperation.h"
|
||||
|
||||
#include "BLI_math_base.hh"
|
||||
#include "BLI_vector.hh"
|
||||
#include "IMB_colormanagement.h"
|
||||
|
@ -57,8 +58,8 @@ void KuwaharaAnisotropicOperation::execute_pixel_sampled(float output[4],
|
|||
const float q = 3.0;
|
||||
const float EPS = 1.0e-10;
|
||||
|
||||
/* For now use green channel to compute orientation */
|
||||
/* todo: convert to HSV and compute orientation and strength on luminance channel */
|
||||
/* For now use green channel to compute orientation. */
|
||||
/* TODO: convert to HSV and compute orientation and strength on luminance channel */
|
||||
float tmp[4];
|
||||
s_xx_reader_->read(tmp, x, y, nullptr);
|
||||
const float a = tmp[1];
|
||||
|
@ -67,13 +68,13 @@ void KuwaharaAnisotropicOperation::execute_pixel_sampled(float output[4],
|
|||
s_yy_reader_->read(tmp, x, y, nullptr);
|
||||
const float c = tmp[1];
|
||||
|
||||
/* Compute egenvalues of structure tensor */
|
||||
/* Compute egenvalues of structure tensor. */
|
||||
const double tr = a + c;
|
||||
const double discr = sqrt((a - b) * (a - b) + 4 * b * c);
|
||||
const double lambda1 = (tr + discr) / 2;
|
||||
const double lambda2 = (tr - discr) / 2;
|
||||
|
||||
/* Compute orientation and its strength based on structure tensor */
|
||||
/* Compute orientation and its strength based on structure tensor. */
|
||||
const double orientation = 0.5 * atan2(2 * b, a - c);
|
||||
const double strength = (lambda1 == 0 && lambda2 == 0) ?
|
||||
0 :
|
||||
|
@ -146,7 +147,7 @@ void KuwaharaAnisotropicOperation::execute_pixel_sampled(float output[4],
|
|||
output[ch] = val;
|
||||
}
|
||||
|
||||
/* No changes for alpha channel */
|
||||
/* No changes for alpha channel. */
|
||||
image_reader_->read_sampled(tmp, x, y, sampler);
|
||||
output[3] = tmp[3];
|
||||
}
|
||||
|
@ -172,12 +173,10 @@ void KuwaharaAnisotropicOperation::update_memory_buffer_partial(MemoryBuffer *ou
|
|||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs)
|
||||
{
|
||||
/*
|
||||
Implementation based on Kyprianidis, Jan & Kang, Henry & Döllner, Jürgen. (2009).
|
||||
"Image and Video Abstraction by Anisotropic Kuwahara Filtering".
|
||||
Comput. Graph. Forum. 28. 1955-1963. 10.1111/j.1467-8659.2009.01574.x.
|
||||
Used reference implementation from lime image processing library (MIT license).
|
||||
*/
|
||||
/* Implementation based on Kyprianidis, Jan & Kang, Henry & Döllner, Jürgen. (2009).
|
||||
* "Image and Video Abstraction by Anisotropic Kuwahara Filtering".
|
||||
* Comput. Graph. Forum. 28. 1955-1963. 10.1111/j.1467-8659.2009.01574.x.
|
||||
* Used reference implementation from lime image processing library (MIT license). */
|
||||
|
||||
MemoryBuffer *image = inputs[0];
|
||||
MemoryBuffer *s_xx = inputs[1];
|
||||
|
@ -203,8 +202,8 @@ void KuwaharaAnisotropicOperation::update_memory_buffer_partial(MemoryBuffer *ou
|
|||
const int x = it.x;
|
||||
const int y = it.y;
|
||||
|
||||
/* For now use green channel to compute orientation */
|
||||
/* todo: convert to HSV and compute orientation and strength on luminance channel */
|
||||
/* For now use green channel to compute orientation. */
|
||||
/* TODO: convert to HSV and compute orientation and strength on luminance channel. */
|
||||
const float a = s_xx->get_value(x, y, 1);
|
||||
const float b = s_xy->get_value(x, y, 1);
|
||||
const float c = s_yy->get_value(x, y, 1);
|
||||
|
@ -215,7 +214,7 @@ void KuwaharaAnisotropicOperation::update_memory_buffer_partial(MemoryBuffer *ou
|
|||
const double lambda1 = (tr + discr) / 2;
|
||||
const double lambda2 = (tr - discr) / 2;
|
||||
|
||||
/* Compute orientation and its strength based on structure tensor */
|
||||
/* Compute orientation and its strength based on structure tensor. */
|
||||
const double orientation = 0.5 * atan2(2 * b, a - c);
|
||||
const double strength = (lambda1 == 0 && lambda2 == 0) ?
|
||||
0 :
|
||||
|
@ -258,9 +257,9 @@ void KuwaharaAnisotropicOperation::update_memory_buffer_partial(MemoryBuffer *ou
|
|||
const double v = image->get_value(xx, yy, ch);
|
||||
float color[4];
|
||||
image->read_elem(xx, yy, color);
|
||||
/* todo(zazizizou): only compute lum once per region */
|
||||
/* TODO(zazizizou): only compute lum once per region. */
|
||||
const float lum = IMB_colormanagement_get_luminance(color);
|
||||
/* todo(zazizizou): only compute mean for the selected region */
|
||||
/* TODO(zazizizou): only compute mean for the selected region. */
|
||||
mean[t] += g * v;
|
||||
sum[t] += g * lum;
|
||||
var[t] += g * lum * lum;
|
||||
|
@ -268,7 +267,7 @@ void KuwaharaAnisotropicOperation::update_memory_buffer_partial(MemoryBuffer *ou
|
|||
}
|
||||
}
|
||||
|
||||
/* Calculate weighted average */
|
||||
/* Calculate weighted average. */
|
||||
double de = 0.0;
|
||||
double nu = 0.0;
|
||||
for (int i = 0; i < n_div_; i++) {
|
||||
|
@ -288,7 +287,7 @@ void KuwaharaAnisotropicOperation::update_memory_buffer_partial(MemoryBuffer *ou
|
|||
it.out[ch] = val;
|
||||
}
|
||||
|
||||
/* No changes for alpha channel */
|
||||
/* No changes for alpha channel. */
|
||||
it.out[3] = image->get_value(x, y, 3);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,7 @@
|
|||
|
||||
#include "COM_KuwaharaClassicOperation.h"
|
||||
|
||||
zazizizou marked this conversation as resolved
Outdated
|
||||
extern "C" {
|
||||
#include "IMB_colormanagement.h"
|
||||
}
|
||||
|
||||
namespace blender::compositor {
|
||||
|
||||
|
@ -40,7 +38,7 @@ void KuwaharaClassicOperation::execute_pixel_sampled(float output[4],
|
|||
float var[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
int cnt[4] = {0, 0, 0, 0};
|
||||
|
||||
/* Split surroundings of pixel into 4 overlapping regions */
|
||||
/* Split surroundings of pixel into 4 overlapping regions. */
|
||||
for (int dy = -kernel_size_; dy <= kernel_size_; dy++) {
|
||||
for (int dx = -kernel_size_; dx <= kernel_size_; dx++) {
|
||||
|
||||
|
@ -83,7 +81,7 @@ void KuwaharaClassicOperation::execute_pixel_sampled(float output[4],
|
|||
}
|
||||
}
|
||||
|
||||
/* Compute region variances */
|
||||
/* Compute region variances. */
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mean[i] = cnt[i] != 0 ? mean[i] / cnt[i] : 0.0f;
|
||||
sum[i] = cnt[i] != 0 ? sum[i] / cnt[i] : 0.0f;
|
||||
|
@ -92,7 +90,7 @@ void KuwaharaClassicOperation::execute_pixel_sampled(float output[4],
|
|||
var[i] = var[i] > temp ? sqrt(var[i] - temp) : 0.0f;
|
||||
}
|
||||
|
||||
/* Choose the region with lowest variance */
|
||||
/* Choose the region with lowest variance. */
|
||||
float min_var = FLT_MAX;
|
||||
int min_index = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
@ -132,7 +130,7 @@ void KuwaharaClassicOperation::update_memory_buffer_partial(MemoryBuffer *output
|
|||
float var[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
int cnt[4] = {0, 0, 0, 0};
|
||||
|
||||
/* Split surroundings of pixel into 4 overlapping regions */
|
||||
/* Split surroundings of pixel into 4 overlapping regions. */
|
||||
for (int dy = -kernel_size_; dy <= kernel_size_; dy++) {
|
||||
for (int dx = -kernel_size_; dx <= kernel_size_; dx++) {
|
||||
|
||||
|
@ -175,7 +173,7 @@ void KuwaharaClassicOperation::update_memory_buffer_partial(MemoryBuffer *output
|
|||
}
|
||||
}
|
||||
|
||||
/* Compute region variances */
|
||||
/* Compute region variances. */
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mean[i] = cnt[i] != 0 ? mean[i] / cnt[i] : 0.0f;
|
||||
sum[i] = cnt[i] != 0 ? sum[i] / cnt[i] : 0.0f;
|
||||
|
@ -184,7 +182,7 @@ void KuwaharaClassicOperation::update_memory_buffer_partial(MemoryBuffer *output
|
|||
var[i] = var[i] > temp ? sqrt(var[i] - temp) : 0.0f;
|
||||
}
|
||||
|
||||
/* Choose the region with lowest variance */
|
||||
/* Choose the region with lowest variance. */
|
||||
float min_var = FLT_MAX;
|
||||
int min_index = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
|
|
@ -9397,7 +9397,7 @@ static void def_cmp_kuwahara(StructRNA *srna)
|
|||
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_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, "smoothing", PROP_INT, PROP_NONE);
|
||||
|
|
Loading…
Reference in New Issue
No need to `extern "C"`` here, the header does it already.
Generally, we should not be adding such statements around
#include
statements, as it makes it very easy to break things when things move to C++. Some headers might need the linking specializer, and for those it is to be changed in the header itself.