diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs
index 1ebd6476e..b80559899 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs
@@ -57,11 +57,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
private readonly float kernelsScale;
- ///
- /// The mapping of initialized complex kernels and parameters, to speed up the initialization of new instances
- ///
- private static readonly ConcurrentDictionary Cache = new ConcurrentDictionary();
-
///
/// Initializes a new instance of the class.
///
@@ -77,24 +72,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
this.componentsCount = definition.Components;
this.gamma = definition.Gamma;
- // Reuse the initialized values from the cache, if possible
- var parameters = new BokehBlurParameters(this.radius, this.componentsCount);
- if (Cache.TryGetValue(parameters, out BokehBlurKernelData info))
- {
- this.kernelParameters = info.Parameters;
- this.kernelsScale = info.Scale;
- this.kernels = info.Kernels;
- }
- else
- {
- // Initialize the complex kernels and parameters with the current arguments
- (this.kernelParameters, this.kernelsScale) = this.GetParameters();
- this.kernels = this.CreateComplexKernels();
- this.NormalizeKernels();
+ // Get the bokeh blur data
+ BokehBlurKernelData data = BokehBlurKernelDataProvider.GetBokehBlurKernelData(this.radius, this.kernelSize, this.componentsCount);
- // Store them in the cache for future use
- Cache.TryAdd(parameters, new BokehBlurKernelData(this.kernelParameters, this.kernelsScale, this.kernels));
- }
+ this.kernelParameters = data.Parameters;
+ this.kernelsScale = data.Scale;
+ this.kernels = data.Kernels;
}
///
@@ -107,163 +90,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
public IReadOnlyList KernelParameters => this.kernelParameters;
- ///
- /// Gets the kernel scales to adjust the component values in each kernel
- ///
- private static IReadOnlyList KernelScales { get; } = new[] { 1.4f, 1.2f, 1.2f, 1.2f, 1.2f, 1.2f };
-
- ///
- /// Gets the available bokeh blur kernel parameters
- ///
- private static IReadOnlyList KernelComponents { get; } = new[]
- {
- // 1 component
- new[] { new Vector4(0.862325f, 1.624835f, 0.767583f, 1.862321f) },
-
- // 2 components
- new[]
- {
- new Vector4(0.886528f, 5.268909f, 0.411259f, -0.548794f),
- new Vector4(1.960518f, 1.558213f, 0.513282f, 4.56111f)
- },
-
- // 3 components
- new[]
- {
- new Vector4(2.17649f, 5.043495f, 1.621035f, -2.105439f),
- new Vector4(1.019306f, 9.027613f, -0.28086f, -0.162882f),
- new Vector4(2.81511f, 1.597273f, -0.366471f, 10.300301f)
- },
-
- // 4 components
- new[]
- {
- new Vector4(4.338459f, 1.553635f, -5.767909f, 46.164397f),
- new Vector4(3.839993f, 4.693183f, 9.795391f, -15.227561f),
- new Vector4(2.791880f, 8.178137f, -3.048324f, 0.302959f),
- new Vector4(1.342190f, 12.328289f, 0.010001f, 0.244650f)
- },
-
- // 5 components
- new[]
- {
- new Vector4(4.892608f, 1.685979f, -22.356787f, 85.91246f),
- new Vector4(4.71187f, 4.998496f, 35.918936f, -28.875618f),
- new Vector4(4.052795f, 8.244168f, -13.212253f, -1.578428f),
- new Vector4(2.929212f, 11.900859f, 0.507991f, 1.816328f),
- new Vector4(1.512961f, 16.116382f, 0.138051f, -0.01f)
- },
-
- // 6 components
- new[]
- {
- new Vector4(5.143778f, 2.079813f, -82.326596f, 111.231024f),
- new Vector4(5.612426f, 6.153387f, 113.878661f, 58.004879f),
- new Vector4(5.982921f, 9.802895f, 39.479083f, -162.028887f),
- new Vector4(6.505167f, 11.059237f, -71.286026f, 95.027069f),
- new Vector4(3.869579f, 14.81052f, 1.405746f, -3.704914f),
- new Vector4(2.201904f, 19.032909f, -0.152784f, -0.107988f)
- }
- };
-
- ///
- /// Gets the kernel parameters and scaling factor for the current count value in the current instance
- ///
- private (Vector4[] Parameters, float Scale) GetParameters()
- {
- // Prepare the kernel components
- int index = Math.Max(0, Math.Min(this.componentsCount - 1, KernelComponents.Count));
- return (KernelComponents[index], KernelScales[index]);
- }
-
- ///
- /// Creates the collection of complex 1D kernels with the specified parameters
- ///
- private Complex64[][] CreateComplexKernels()
- {
- var kernels = new Complex64[this.kernelParameters.Length][];
- ref Vector4 baseRef = ref MemoryMarshal.GetReference(this.kernelParameters.AsSpan());
- for (int i = 0; i < this.kernelParameters.Length; i++)
- {
- ref Vector4 paramsRef = ref Unsafe.Add(ref baseRef, i);
- kernels[i] = this.CreateComplex1DKernel(paramsRef.X, paramsRef.Y);
- }
-
- return kernels;
- }
-
- ///
- /// Creates a complex 1D kernel with the specified parameters
- ///
- /// The exponential parameter for each complex component
- /// The angle component for each complex component
- private Complex64[] CreateComplex1DKernel(float a, float b)
- {
- var kernel = new Complex64[this.kernelSize];
- ref Complex64 baseRef = ref MemoryMarshal.GetReference(kernel.AsSpan());
- int r = this.radius, n = -r;
-
- for (int i = 0; i < this.kernelSize; i++, n++)
- {
- // Incrementally compute the range values
- float value = n * this.kernelsScale * (1f / r);
- value *= value;
-
- // Fill in the complex kernel values
- Unsafe.Add(ref baseRef, i) = new Complex64(
- MathF.Exp(-a * value) * MathF.Cos(b * value),
- MathF.Exp(-a * value) * MathF.Sin(b * value));
- }
-
- return kernel;
- }
-
- ///
- /// Normalizes the kernels with respect to A * real + B * imaginary
- ///
- private void NormalizeKernels()
- {
- // Calculate the complex weighted sum
- float total = 0;
- Span kernelsSpan = this.kernels.AsSpan();
- ref Complex64[] baseKernelsRef = ref MemoryMarshal.GetReference(kernelsSpan);
- ref Vector4 baseParamsRef = ref MemoryMarshal.GetReference(this.kernelParameters.AsSpan());
-
- for (int i = 0; i < this.kernelParameters.Length; i++)
- {
- ref Complex64[] kernelRef = ref Unsafe.Add(ref baseKernelsRef, i);
- int length = kernelRef.Length;
- ref Complex64 valueRef = ref kernelRef[0];
- ref Vector4 paramsRef = ref Unsafe.Add(ref baseParamsRef, i);
-
- for (int j = 0; j < length; j++)
- {
- for (int k = 0; k < length; k++)
- {
- ref Complex64 jRef = ref Unsafe.Add(ref valueRef, j);
- ref Complex64 kRef = ref Unsafe.Add(ref valueRef, k);
- total +=
- (paramsRef.Z * ((jRef.Real * kRef.Real) - (jRef.Imaginary * kRef.Imaginary)))
- + (paramsRef.W * ((jRef.Real * kRef.Imaginary) + (jRef.Imaginary * kRef.Real)));
- }
- }
- }
-
- // Normalize the kernels
- float scalar = 1f / MathF.Sqrt(total);
- for (int i = 0; i < kernelsSpan.Length; i++)
- {
- ref Complex64[] kernelsRef = ref Unsafe.Add(ref baseKernelsRef, i);
- int length = kernelsRef.Length;
- ref Complex64 valueRef = ref kernelsRef[0];
-
- for (int j = 0; j < length; j++)
- {
- Unsafe.Add(ref valueRef, j) *= scalar;
- }
- }
- }
-
///
protected override void OnFrameApply(ImageFrame source)
{