Blender V4.3
recursive_gaussian_blur.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_math_base.hh"
6#include "BLI_math_vector.hh"
7
8#include "COM_context.hh"
9#include "COM_result.hh"
10
15
17
18/* Compute the Gaussian sigma from the radius, where the radius is in pixels. Blender's filter is
19 * truncated at |x| > 3 * sigma as can be seen in the R_FILTER_GAUSS case of the RE_filter_value
20 * function, so we divide by three to get the approximate sigma value. Further, ensure the radius
21 * is at least 1 since recursive Gaussian implementations can't handle zero radii. */
23{
24 return math::max(float2(1.0f), radius) / 3.0f;
25}
26
27/* Apply a recursive Gaussian blur algorithm on the input based on the general method outlined
28 * in the following paper:
29 *
30 * Hale, Dave. "Recursive gaussian filters." CWP-546 (2006).
31 *
32 * In particular, based on the table in Section 5 Conclusion, for very low radius blur, we use a
33 * direct separable Gaussian convolution. For medium blur radius, we use the fourth order IIR
34 * Deriche filter based on the following paper:
35 *
36 * Deriche, Rachid. Recursively implementating the Gaussian and its derivatives. Diss. INRIA,
37 * 1993.
38 *
39 * For high radius blur, we use the fourth order IIR Van Vliet filter based on the following paper:
40 *
41 * Van Vliet, Lucas J., Ian T. Young, and Piet W. Verbeek. "Recursive Gaussian derivative
42 * filters." Proceedings. Fourteenth International Conference on Pattern Recognition (Cat. No.
43 * 98EX170). Vol. 1. IEEE, 1998.
44 *
45 * That's because direct convolution is faster and more accurate for very low radius, while the
46 * Deriche filter is more accurate for medium blur radius, while Van Vliet is more accurate for
47 * high blur radius. The criteria suggested by the paper is a sigma value threshold of 3 and 32 for
48 * the Deriche and Van Vliet filters respectively, which we apply on the larger of the two
49 * dimensions. */
50void recursive_gaussian_blur(Context &context, Result &input, Result &output, float2 radius)
51{
52 /* The radius is in pixel units, while both recursive implementations expect the sigma value of
53 * the Gaussian function. */
54 const float2 sigma = compute_sigma_from_radius(radius);
55
56 if (math::reduce_max(sigma) < 3.0f) {
57 symmetric_separable_blur(context, input, output, radius);
58 return;
59 }
60
61 if (math::reduce_max(sigma) < 32.0f) {
62 deriche_gaussian_blur(context, input, output, sigma);
63 return;
64 }
65
66 van_vliet_gaussian_blur(context, input, output, sigma);
67}
68
69} // namespace blender::realtime_compositor
T reduce_max(const VecBase< T, Size > &a)
T max(const T &a, const T &b)
void symmetric_separable_blur(Context &context, Result &input, Result &output, float2 radius, int filter_type=R_FILTER_GAUSS, bool extend_bounds=false, bool gamma_correct=false)
void recursive_gaussian_blur(Context &context, Result &input, Result &output, float2 radius)
void van_vliet_gaussian_blur(Context &context, Result &input, Result &output, float2 sigma)
static float2 compute_sigma_from_radius(float2 radius)
void deriche_gaussian_blur(Context &context, Result &input, Result &output, float2 sigma)
VecBase< float, 2 > float2