diff --git a/src/lanczos/lanczos_opencv.jl b/src/lanczos/lanczos_opencv.jl index 62f350df..e1a3d11d 100644 --- a/src/lanczos/lanczos_opencv.jl +++ b/src/lanczos/lanczos_opencv.jl @@ -50,11 +50,13 @@ export Lanczos4OpenCV Alternative implementation of Lanczos resampling using algorithm `lanczos4` function of OpenCV: https://github.com/opencv/opencv/blob/de15636724967faf62c2d1bce26f4335e4b359e5/modules/imgproc/src/resize.cpp#L917-L946 """ -struct Lanczos4OpenCV <: AbstractLanczos end +struct Lanczos4OpenCV{T} <: AbstractLanczos end +Lanczos4OpenCV() = Lanczos4OpenCV{Float64}() degree(::Lanczos4OpenCV) = 4 -value_weights(::Lanczos4OpenCV, δx) = _lanczos4_opencv(δx) +value_weights(::Lanczos4OpenCV{T}, δx) where {T} = + _lanczos4_opencv(float(T), float(T).(l4_2d_cs), δx) # s45 = sqrt(2)/2 const s45 = 0.70710678118654752440084436210485 @@ -65,20 +67,18 @@ const s45 = 0.70710678118654752440084436210485 const l4_2d_cs = SA[1 0; -s45 -s45; 0 1; s45 -s45; -1 0; s45 s45; 0 -1; -s45 s45] -function _lanczos4_opencv(δx) - p_4 = π / 4 - y0 = -(δx + 3) * p_4 +function _lanczos4_opencv(::Type{F}, l4_2d_cs, δx) where {F} + p_4 = π * F(0.25) + y0 = -(δx + F(3)) * p_4 s0, c0 = sincos(y0) cs = ntuple(8) do i - y = (δx + 4 - i) * p_4 - # Improve precision of Lanczos OpenCV4 #451, avoid NaN - if iszero(y) - y = eps(oneunit(y))/8 + y = δx + 4 - i + if abs(y) >= F(1e-6) + y *= p_4 + (F(l4_2d_cs[i, 1]) * s0 + F(l4_2d_cs[i, 2]) * c0) / y^2 + else + F(1e30) end - # Numerator is the sin subtraction identity - # It is equivalent to the following - # f(δx,i) = sin( π/4*( 5*(i-1)-δx-3 ) ) - (l4_2d_cs[i, 1] * s0 + l4_2d_cs[i, 2] * c0) / y^2 end sum_cs = sum(cs) normed_cs = ntuple(i -> cs[i] / sum_cs, Val(8))