Files
test/source/blender/compositor/operations/COM_KuwaharaAnisotropicStructureTensorOperation.cc
Campbell Barton 5fbcb4c27e Cleanup: remove spaces from commented arguments
Also use local enums for `MA_BM_*` in versioning code.
2023-09-22 12:21:18 +10:00

156 lines
7.3 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "COM_KuwaharaAnisotropicStructureTensorOperation.h"
#include "BLI_math_base.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
#include "BLI_math_vector_types.hh"
namespace blender::compositor {
KuwaharaAnisotropicStructureTensorOperation::KuwaharaAnisotropicStructureTensorOperation()
{
this->add_input_socket(DataType::Color);
this->add_output_socket(DataType::Color);
this->flags_.is_fullframe_operation = true;
}
void KuwaharaAnisotropicStructureTensorOperation::init_execution()
{
image_reader_ = this->get_input_socket_reader(0);
}
void KuwaharaAnisotropicStructureTensorOperation::deinit_execution()
{
image_reader_ = nullptr;
}
/* Computes the structure tensor of the image using a Dirac delta window function as described in
* section "3.2 Local Structure Estimation" of the paper:
*
* Kyprianidis, Jan Eric. "Image and video abstraction by multi-scale anisotropic Kuwahara
* filtering." 2011.
*
* The structure tensor should then be smoothed using a Gaussian function to eliminate high
* frequency details. */
void KuwaharaAnisotropicStructureTensorOperation::execute_pixel_sampled(float output[4],
float x_float,
float y_float,
PixelSampler /*sampler*/)
{
using math::max, math::min, math::dot;
const int x = x_float;
const int y = y_float;
const int width = this->get_width();
const int height = this->get_height();
/* The weight kernels of the filter optimized for rotational symmetry described in section "3.2.1
* Gradient Calculation". */
const float corner_weight = 0.182f;
const float center_weight = 1.0f - 2.0f * corner_weight;
float4 input_color;
float3 x_partial_derivative = float3(0.0f);
image_reader_->read(input_color, max(0, x - 1), min(height - 1, y + 1), nullptr);
x_partial_derivative += input_color.xyz() * -corner_weight;
image_reader_->read(input_color, max(0, x - 1), y, nullptr);
x_partial_derivative += input_color.xyz() * -center_weight;
image_reader_->read(input_color, max(0, x - 1), max(0, y - 1), nullptr);
x_partial_derivative += input_color.xyz() * -corner_weight;
image_reader_->read(input_color, min(width, x + 1), min(height - 1, y + 1), nullptr);
x_partial_derivative += input_color.xyz() * corner_weight;
image_reader_->read(input_color, min(width, x + 1), y, nullptr);
x_partial_derivative += input_color.xyz() * center_weight;
image_reader_->read(input_color, min(width, x + 1), max(0, y - 1), nullptr);
x_partial_derivative += input_color.xyz() * corner_weight;
float3 y_partial_derivative = float3(0.0f);
image_reader_->read(input_color, max(0, x - 1), min(height - 1, y + 1), nullptr);
y_partial_derivative += input_color.xyz() * corner_weight;
image_reader_->read(input_color, x, min(height - 1, y + 1), nullptr);
y_partial_derivative += input_color.xyz() * center_weight;
image_reader_->read(input_color, min(width, x + 1), min(height - 1, y + 1), nullptr);
y_partial_derivative += input_color.xyz() * corner_weight;
image_reader_->read(input_color, max(0, x - 1), max(0, y - 1), nullptr);
y_partial_derivative += input_color.xyz() * -corner_weight;
image_reader_->read(input_color, x, max(0, y - 1), nullptr);
y_partial_derivative += input_color.xyz() * -center_weight;
image_reader_->read(input_color, min(width, x + 1), max(0, y - 1), nullptr);
y_partial_derivative += input_color.xyz() * -corner_weight;
/* We encode the structure tensor in a float4 using a column major storage order. */
float4 structure_tensor = float4(dot(x_partial_derivative, x_partial_derivative),
dot(x_partial_derivative, y_partial_derivative),
dot(x_partial_derivative, y_partial_derivative),
dot(y_partial_derivative, y_partial_derivative));
copy_v4_v4(output, structure_tensor);
}
/* Computes the structure tensor of the image using a Dirac delta window function as described in
* section "3.2 Local Structure Estimation" of the paper:
*
* Kyprianidis, Jan Eric. "Image and video abstraction by multi-scale anisotropic Kuwahara
* filtering." 2011.
*
* The structure tensor should then be smoothed using a Gaussian function to eliminate high
* frequency details. */
void KuwaharaAnisotropicStructureTensorOperation::update_memory_buffer_partial(
MemoryBuffer *output, const rcti &area, Span<MemoryBuffer *> inputs)
{
using math::max, math::min, math::dot;
MemoryBuffer *image = inputs[0];
const int width = image->get_width();
const int height = image->get_height();
/* The weight kernels of the filter optimized for rotational symmetry described in section
* "3.2.1 Gradient Calculation". */
const float corner_weight = 0.182f;
const float center_weight = 1.0f - 2.0f * corner_weight;
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
const int x = it.x;
const int y = it.y;
float3 input_color;
float3 x_partial_derivative = float3(0.0f);
input_color = float3(image->get_elem(max(0, x - 1), min(height - 1, y + 1)));
x_partial_derivative += input_color * -corner_weight;
input_color = float3(image->get_elem(max(0, x - 1), y));
x_partial_derivative += input_color * -center_weight;
input_color = float3(image->get_elem(max(0, x - 1), max(0, y - 1)));
x_partial_derivative += input_color * -corner_weight;
input_color = float3(image->get_elem(min(width - 1, x + 1), min(height - 1, y + 1)));
x_partial_derivative += input_color * corner_weight;
input_color = float3(image->get_elem(min(width - 1, x + 1), y));
x_partial_derivative += input_color * center_weight;
input_color = float3(image->get_elem(min(width - 1, x + 1), max(0, y - 1)));
x_partial_derivative += input_color * corner_weight;
float3 y_partial_derivative = float3(0.0f);
input_color = float3(image->get_elem(max(0, x - 1), min(height - 1, y + 1)));
y_partial_derivative += input_color * corner_weight;
input_color = float3(image->get_elem(x, min(height - 1, y + 1)));
y_partial_derivative += input_color * center_weight;
input_color = float3(image->get_elem(min(width - 1, x + 1), min(height - 1, y + 1)));
y_partial_derivative += input_color * corner_weight;
input_color = float3(image->get_elem(max(0, x - 1), max(0, y - 1)));
y_partial_derivative += input_color * -corner_weight;
input_color = float3(image->get_elem(x, max(0, y - 1)));
y_partial_derivative += input_color * -center_weight;
input_color = float3(image->get_elem(min(width - 1, x + 1), max(0, y - 1)));
y_partial_derivative += input_color * -corner_weight;
/* We encode the structure tensor in a float4 using a column major storage order. */
float4 structure_tensor = float4(dot(x_partial_derivative, x_partial_derivative),
dot(x_partial_derivative, y_partial_derivative),
dot(x_partial_derivative, y_partial_derivative),
dot(y_partial_derivative, y_partial_derivative));
copy_v4_v4(it.out, structure_tensor);
}
}
} // namespace blender::compositor