pic_scale/
sampler.rs

1/*
2 * Copyright (c) Radzivon Bartoshyk. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1.  Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * 2.  Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * 3.  Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29#![allow(clippy::excessive_precision)]
30
31use crate::bartlett::{bartlett, bartlett_hann};
32use crate::bc_spline::{
33    b_spline, catmull_rom, hermite_spline, mitchell_netravalli, robidoux, robidoux_sharp,
34};
35use crate::bilinear::bilinear;
36use crate::blackman::blackman;
37use crate::bohman::bohman;
38use crate::cubic::{bicubic_spline, cubic_spline};
39use crate::gaussian::gaussian;
40use crate::hann::{hamming, hann, hanning};
41use crate::kaiser::kaiser;
42use crate::lagrange::{lagrange2, lagrange3};
43use crate::lanczos::{
44    lanczos2, lanczos2_jinc, lanczos3, lanczos3_jinc, lanczos4, lanczos4_jinc, lanczos6,
45    lanczos6_jinc,
46};
47use crate::quadric::quadric;
48use crate::sinc::sinc;
49use crate::sphinx::sphinx;
50use crate::spline_n::{spline16, spline36, spline64};
51use crate::welch::welch;
52use crate::{ConstPI, ConstSqrt2, Jinc};
53use num_traits::{AsPrimitive, Float, Signed};
54use std::ops::{AddAssign, MulAssign, Neg};
55
56#[inline(always)]
57pub(crate) fn box_weight<V: Copy + 'static>(_: V) -> V
58where
59    f32: AsPrimitive<V>,
60{
61    1f32.as_()
62}
63
64#[derive(Debug, Copy, Clone, Default, Ord, PartialOrd, Eq, PartialEq)]
65/// Describes resampling function that will be used
66pub enum ResamplingFunction {
67    Bilinear,
68    Nearest,
69    Cubic,
70    #[default]
71    MitchellNetravalli,
72    CatmullRom,
73    Hermite,
74    BSpline,
75    Hann,
76    Bicubic,
77    Hamming,
78    Hanning,
79    EwaHanning,
80    Blackman,
81    EwaBlackman,
82    Welch,
83    Quadric,
84    EwaQuadric,
85    Gaussian,
86    Sphinx,
87    Bartlett,
88    Robidoux,
89    EwaRobidoux,
90    RobidouxSharp,
91    EwaRobidouxSharp,
92    Spline16,
93    Spline36,
94    Spline64,
95    Kaiser,
96    BartlettHann,
97    Box,
98    Bohman,
99    Lanczos2,
100    Lanczos3,
101    Lanczos4,
102    Lanczos2Jinc,
103    Lanczos3Jinc,
104    Lanczos4Jinc,
105    EwaLanczos3Jinc,
106    Ginseng,
107    EwaGinseng,
108    EwaLanczosSharp,
109    EwaLanczos4Sharpest,
110    EwaLanczosSoft,
111    HaasnSoft,
112    Lagrange2,
113    Lagrange3,
114    Lanczos6,
115    Lanczos6Jinc,
116    /// This method replicates `INTER_AREA` behaviour from OpenCV
117    Area,
118}
119
120impl From<u32> for ResamplingFunction {
121    fn from(value: u32) -> Self {
122        match value {
123            0 => ResamplingFunction::Bilinear,
124            1 => ResamplingFunction::Nearest,
125            2 => ResamplingFunction::Cubic,
126            3 => ResamplingFunction::MitchellNetravalli,
127            4 => ResamplingFunction::CatmullRom,
128            5 => ResamplingFunction::Hermite,
129            6 => ResamplingFunction::BSpline,
130            7 => ResamplingFunction::Hann,
131            8 => ResamplingFunction::Bicubic,
132            9 => ResamplingFunction::Hamming,
133            10 => ResamplingFunction::Hanning,
134            11 => ResamplingFunction::Blackman,
135            12 => ResamplingFunction::Welch,
136            13 => ResamplingFunction::Quadric,
137            14 => ResamplingFunction::Gaussian,
138            15 => ResamplingFunction::Sphinx,
139            16 => ResamplingFunction::Bartlett,
140            17 => ResamplingFunction::Robidoux,
141            18 => ResamplingFunction::RobidouxSharp,
142            19 => ResamplingFunction::Spline16,
143            20 => ResamplingFunction::Spline36,
144            21 => ResamplingFunction::Spline64,
145            22 => ResamplingFunction::Kaiser,
146            23 => ResamplingFunction::BartlettHann,
147            24 => ResamplingFunction::Box,
148            25 => ResamplingFunction::Bohman,
149            26 => ResamplingFunction::Lanczos2,
150            27 => ResamplingFunction::Lanczos3,
151            28 => ResamplingFunction::Lanczos4,
152            29 => ResamplingFunction::Lanczos2Jinc,
153            30 => ResamplingFunction::Lanczos3Jinc,
154            31 => ResamplingFunction::Lanczos4Jinc,
155            32 => ResamplingFunction::EwaHanning,
156            33 => ResamplingFunction::EwaRobidoux,
157            34 => ResamplingFunction::EwaBlackman,
158            35 => ResamplingFunction::EwaQuadric,
159            36 => ResamplingFunction::EwaRobidouxSharp,
160            37 => ResamplingFunction::EwaLanczos3Jinc,
161            38 => ResamplingFunction::Ginseng,
162            39 => ResamplingFunction::EwaGinseng,
163            40 => ResamplingFunction::EwaLanczosSharp,
164            41 => ResamplingFunction::EwaLanczos4Sharpest,
165            42 => ResamplingFunction::EwaLanczosSoft,
166            43 => ResamplingFunction::HaasnSoft,
167            44 => ResamplingFunction::Lagrange2,
168            45 => ResamplingFunction::Lagrange3,
169            46 => ResamplingFunction::Lanczos6,
170            47 => ResamplingFunction::Lanczos6Jinc,
171            48 => ResamplingFunction::Area,
172            _ => ResamplingFunction::Bilinear,
173        }
174    }
175}
176
177/// Resampling window representation
178#[derive(Debug, Copy, Clone)]
179pub(crate) struct ResamplingWindow<T> {
180    pub(crate) window: fn(T) -> T,
181    pub(crate) window_size: f32,
182    pub(crate) blur: f32,
183    pub(crate) taper: f32,
184}
185
186impl<T> ResamplingWindow<T> {
187    fn new(window: fn(T) -> T, window_size: f32, blur: f32, taper: f32) -> ResamplingWindow<T> {
188        ResamplingWindow {
189            window,
190            window_size,
191            blur,
192            taper,
193        }
194    }
195}
196
197/// Resampling filter representation
198#[derive(Debug, Copy, Clone)]
199pub(crate) struct ResamplingFilter<T> {
200    pub kernel: fn(T) -> T,
201    pub window: Option<ResamplingWindow<T>>,
202    pub min_kernel_size: f32,
203    pub is_ewa: bool,
204    pub is_resizable_kernel: bool,
205    pub is_area: bool,
206}
207
208impl<T> ResamplingFilter<T> {
209    fn new(kernel: fn(T) -> T, min_kernel_size: f32, is_ewa: bool) -> ResamplingFilter<T> {
210        ResamplingFilter {
211            kernel,
212            window: None,
213            min_kernel_size,
214            is_ewa,
215            is_resizable_kernel: true,
216            is_area: false,
217        }
218    }
219
220    fn new_with_window(
221        kernel: fn(T) -> T,
222        window: ResamplingWindow<T>,
223        min_kernel_size: f32,
224        is_ewa: bool,
225    ) -> ResamplingFilter<T> {
226        ResamplingFilter::<T> {
227            kernel,
228            window: Some(window),
229            min_kernel_size,
230            is_ewa,
231            is_resizable_kernel: true,
232            is_area: false,
233        }
234    }
235
236    fn new_with_fixed_kernel(
237        kernel: fn(T) -> T,
238        min_kernel_size: f32,
239        is_ewa: bool,
240    ) -> ResamplingFilter<T> {
241        ResamplingFilter::<T> {
242            kernel,
243            window: None,
244            min_kernel_size,
245            is_ewa,
246            is_resizable_kernel: false,
247            is_area: false,
248        }
249    }
250
251    fn new_with_area(kernel: fn(T) -> T, min_kernel_size: f32) -> ResamplingFilter<T> {
252        ResamplingFilter {
253            kernel,
254            window: None,
255            min_kernel_size,
256            is_ewa: false,
257            is_resizable_kernel: true,
258            is_area: true,
259        }
260    }
261}
262
263const JINC_R3: f32 = 3.2383154841662362f32;
264const JINC_R4: f32 = 4.2410628637960699f32;
265
266impl ResamplingFunction {
267    pub(crate) fn get_resampling_filter<T>(&self) -> ResamplingFilter<T>
268    where
269        T: Copy
270            + Neg
271            + Signed
272            + Float
273            + 'static
274            + ConstPI
275            + MulAssign<T>
276            + AddAssign<T>
277            + AsPrimitive<f64>
278            + AsPrimitive<usize>
279            + Jinc<T>
280            + ConstSqrt2,
281        f32: AsPrimitive<T>,
282        f64: AsPrimitive<T>,
283        usize: AsPrimitive<T>,
284    {
285        match self {
286            ResamplingFunction::Bilinear => ResamplingFilter::new(bilinear, 2f32, false),
287            ResamplingFunction::Nearest => {
288                // Just a stab for nearest
289                ResamplingFilter::new(bilinear, 2f32, false)
290            }
291            ResamplingFunction::Cubic => ResamplingFilter::new(cubic_spline, 2f32, false),
292            ResamplingFunction::MitchellNetravalli => {
293                ResamplingFilter::new(mitchell_netravalli, 2f32, false)
294            }
295            ResamplingFunction::Lanczos3 => ResamplingFilter::new(lanczos3, 3f32, false),
296            ResamplingFunction::CatmullRom => ResamplingFilter::new(catmull_rom, 2f32, false),
297            ResamplingFunction::Hermite => ResamplingFilter::new(hermite_spline, 2f32, false),
298            ResamplingFunction::BSpline => ResamplingFilter::new(b_spline, 2f32, false),
299            ResamplingFunction::Hann => ResamplingFilter::new(hann, 3f32, false),
300            ResamplingFunction::Bicubic => ResamplingFilter::new(bicubic_spline, 2f32, false),
301            ResamplingFunction::Lanczos4 => ResamplingFilter::new(lanczos4, 4f32, false),
302            ResamplingFunction::Lanczos2 => ResamplingFilter::new(lanczos2, 2f32, false),
303            ResamplingFunction::Hamming => ResamplingFilter::new(hamming, 2f32, false),
304            ResamplingFunction::Hanning => ResamplingFilter::new(hanning, 2f32, false),
305            ResamplingFunction::EwaHanning => ResamplingFilter::new_with_window(
306                T::jinc(),
307                ResamplingWindow::new(hanning, 2f32, 0f32, 0f32),
308                1f32,
309                true,
310            ),
311            ResamplingFunction::Welch => ResamplingFilter::new(welch, 2f32, false),
312            ResamplingFunction::Quadric => ResamplingFilter::new(quadric, 2f32, false),
313            ResamplingFunction::EwaQuadric => ResamplingFilter::new(quadric, 2f32, true),
314            ResamplingFunction::Gaussian => ResamplingFilter::new(gaussian, 2f32, false),
315            ResamplingFunction::Sphinx => ResamplingFilter::new(sphinx, 2f32, false),
316            ResamplingFunction::Bartlett => ResamplingFilter::new(bartlett, 2f32, false),
317            ResamplingFunction::Robidoux => ResamplingFilter::new(robidoux, 2f32, false),
318            ResamplingFunction::EwaRobidoux => ResamplingFilter::new(robidoux, 2f32, true),
319            ResamplingFunction::RobidouxSharp => ResamplingFilter::new(robidoux_sharp, 2f32, false),
320            ResamplingFunction::EwaRobidouxSharp => {
321                ResamplingFilter::new(robidoux_sharp, 2f32, true)
322            }
323            ResamplingFunction::Spline16 => {
324                ResamplingFilter::new_with_fixed_kernel(spline16, 2f32, false)
325            }
326            ResamplingFunction::Spline36 => {
327                ResamplingFilter::new_with_fixed_kernel(spline36, 4f32, false)
328            }
329            ResamplingFunction::Spline64 => {
330                ResamplingFilter::new_with_fixed_kernel(spline64, 6f32, false)
331            }
332            ResamplingFunction::Kaiser => ResamplingFilter::new(kaiser, 2f32, false),
333            ResamplingFunction::BartlettHann => ResamplingFilter::new(bartlett_hann, 2f32, false),
334            ResamplingFunction::Box => ResamplingFilter::new(box_weight, 2f32, false),
335            ResamplingFunction::Area => ResamplingFilter::new_with_area(box_weight, 2f32),
336            ResamplingFunction::Bohman => ResamplingFilter::new(bohman, 2f32, false),
337            ResamplingFunction::Lanczos2Jinc => ResamplingFilter::new(lanczos2_jinc, 2f32, false),
338            ResamplingFunction::Lanczos3Jinc => ResamplingFilter::new(lanczos3_jinc, 3f32, false),
339            ResamplingFunction::EwaLanczos3Jinc => ResamplingFilter::new(lanczos3_jinc, 3f32, true),
340            ResamplingFunction::Lanczos4Jinc => ResamplingFilter::new(lanczos4_jinc, 4f32, false),
341            ResamplingFunction::Blackman => ResamplingFilter::new(blackman, 2f32, false),
342            ResamplingFunction::EwaBlackman => ResamplingFilter::new(blackman, 2f32, true),
343            ResamplingFunction::Ginseng => ResamplingFilter::new_with_window(
344                sinc,
345                ResamplingWindow::new(T::jinc(), 3f32, 1f32, 0f32),
346                3f32,
347                false,
348            ),
349            ResamplingFunction::EwaGinseng => ResamplingFilter::new_with_window(
350                sinc,
351                ResamplingWindow::new(T::jinc(), JINC_R3, 1f32, 0f32),
352                3f32,
353                true,
354            ),
355            ResamplingFunction::EwaLanczosSharp => ResamplingFilter::new_with_window(
356                T::jinc(),
357                ResamplingWindow::new(T::jinc(), JINC_R3, 0.9812505837223707f32, 0f32),
358                3f32,
359                true,
360            ),
361            ResamplingFunction::EwaLanczos4Sharpest => ResamplingFilter::new_with_window(
362                T::jinc(),
363                ResamplingWindow::new(T::jinc(), JINC_R4, 0.8845120932605005f32, 0f32),
364                4f32,
365                true,
366            ),
367            ResamplingFunction::EwaLanczosSoft => ResamplingFilter::new_with_window(
368                T::jinc(),
369                ResamplingWindow::new(T::jinc(), JINC_R3, 1.0164667662867047f32, 0f32),
370                3f32,
371                true,
372            ),
373            ResamplingFunction::HaasnSoft => ResamplingFilter::new_with_window(
374                T::jinc(),
375                ResamplingWindow::new(hanning, 3f32, 1.11f32, 0f32),
376                3f32,
377                false,
378            ),
379            ResamplingFunction::Lagrange2 => ResamplingFilter::new(lagrange2, 2f32, false),
380            ResamplingFunction::Lagrange3 => ResamplingFilter::new(lagrange3, 3f32, false),
381            ResamplingFunction::Lanczos6Jinc => ResamplingFilter::new(lanczos6_jinc, 6f32, false),
382            ResamplingFunction::Lanczos6 => ResamplingFilter::new(lanczos6, 6f32, false),
383        }
384    }
385}