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::math::gaussian::Exponential;
48use crate::math::sinc::{Sinc, Trigonometry};
49use crate::quadric::quadric;
50use crate::sinc::sinc;
51use crate::sphinx::sphinx;
52use crate::spline_n::{spline16, spline36, spline64};
53use crate::welch::welch;
54use crate::{ConstPI, ConstSqrt2, Jinc};
55use num_traits::{AsPrimitive, Float, Signed};
56use std::ops::{AddAssign, MulAssign, Neg};
57
58#[inline(always)]
59pub(crate) fn box_weight<V: Copy + 'static>(_: V) -> V
60where
61    f32: AsPrimitive<V>,
62{
63    1f32.as_()
64}
65
66#[derive(Debug, Copy, Clone, Default, Ord, PartialOrd, Eq, PartialEq)]
67/// Describes resampling function that will be used
68pub enum ResamplingFunction {
69    Bilinear,
70    Nearest,
71    Cubic,
72    #[default]
73    MitchellNetravalli,
74    CatmullRom,
75    Hermite,
76    BSpline,
77    Hann,
78    Bicubic,
79    Hamming,
80    Hanning,
81    EwaHanning,
82    Blackman,
83    EwaBlackman,
84    Welch,
85    Quadric,
86    EwaQuadric,
87    Gaussian,
88    Sphinx,
89    Bartlett,
90    Robidoux,
91    EwaRobidoux,
92    RobidouxSharp,
93    EwaRobidouxSharp,
94    Spline16,
95    Spline36,
96    Spline64,
97    Kaiser,
98    BartlettHann,
99    Box,
100    Bohman,
101    Lanczos2,
102    Lanczos3,
103    Lanczos4,
104    Lanczos2Jinc,
105    Lanczos3Jinc,
106    Lanczos4Jinc,
107    EwaLanczos3Jinc,
108    Ginseng,
109    EwaGinseng,
110    EwaLanczosSharp,
111    EwaLanczos4Sharpest,
112    EwaLanczosSoft,
113    HaasnSoft,
114    Lagrange2,
115    Lagrange3,
116    Lanczos6,
117    Lanczos6Jinc,
118    /// This method replicates `INTER_AREA` behaviour from OpenCV
119    Area,
120}
121
122impl From<u32> for ResamplingFunction {
123    fn from(value: u32) -> Self {
124        match value {
125            0 => ResamplingFunction::Bilinear,
126            1 => ResamplingFunction::Nearest,
127            2 => ResamplingFunction::Cubic,
128            3 => ResamplingFunction::MitchellNetravalli,
129            4 => ResamplingFunction::CatmullRom,
130            5 => ResamplingFunction::Hermite,
131            6 => ResamplingFunction::BSpline,
132            7 => ResamplingFunction::Hann,
133            8 => ResamplingFunction::Bicubic,
134            9 => ResamplingFunction::Hamming,
135            10 => ResamplingFunction::Hanning,
136            11 => ResamplingFunction::Blackman,
137            12 => ResamplingFunction::Welch,
138            13 => ResamplingFunction::Quadric,
139            14 => ResamplingFunction::Gaussian,
140            15 => ResamplingFunction::Sphinx,
141            16 => ResamplingFunction::Bartlett,
142            17 => ResamplingFunction::Robidoux,
143            18 => ResamplingFunction::RobidouxSharp,
144            19 => ResamplingFunction::Spline16,
145            20 => ResamplingFunction::Spline36,
146            21 => ResamplingFunction::Spline64,
147            22 => ResamplingFunction::Kaiser,
148            23 => ResamplingFunction::BartlettHann,
149            24 => ResamplingFunction::Box,
150            25 => ResamplingFunction::Bohman,
151            26 => ResamplingFunction::Lanczos2,
152            27 => ResamplingFunction::Lanczos3,
153            28 => ResamplingFunction::Lanczos4,
154            29 => ResamplingFunction::Lanczos2Jinc,
155            30 => ResamplingFunction::Lanczos3Jinc,
156            31 => ResamplingFunction::Lanczos4Jinc,
157            32 => ResamplingFunction::EwaHanning,
158            33 => ResamplingFunction::EwaRobidoux,
159            34 => ResamplingFunction::EwaBlackman,
160            35 => ResamplingFunction::EwaQuadric,
161            36 => ResamplingFunction::EwaRobidouxSharp,
162            37 => ResamplingFunction::EwaLanczos3Jinc,
163            38 => ResamplingFunction::Ginseng,
164            39 => ResamplingFunction::EwaGinseng,
165            40 => ResamplingFunction::EwaLanczosSharp,
166            41 => ResamplingFunction::EwaLanczos4Sharpest,
167            42 => ResamplingFunction::EwaLanczosSoft,
168            43 => ResamplingFunction::HaasnSoft,
169            44 => ResamplingFunction::Lagrange2,
170            45 => ResamplingFunction::Lagrange3,
171            46 => ResamplingFunction::Lanczos6,
172            47 => ResamplingFunction::Lanczos6Jinc,
173            48 => ResamplingFunction::Area,
174            _ => ResamplingFunction::Bilinear,
175        }
176    }
177}
178
179/// Resampling window representation
180#[derive(Debug, Copy, Clone)]
181pub(crate) struct ResamplingWindow<T> {
182    pub(crate) window: fn(T) -> T,
183    pub(crate) window_size: f32,
184    pub(crate) blur: f32,
185    pub(crate) taper: f32,
186}
187
188impl<T> ResamplingWindow<T> {
189    fn new(window: fn(T) -> T, window_size: f32, blur: f32, taper: f32) -> ResamplingWindow<T> {
190        ResamplingWindow {
191            window,
192            window_size,
193            blur,
194            taper,
195        }
196    }
197}
198
199/// Resampling filter representation
200#[derive(Debug, Copy, Clone)]
201pub(crate) struct ResamplingFilter<T> {
202    pub kernel: fn(T) -> T,
203    pub window: Option<ResamplingWindow<T>>,
204    pub min_kernel_size: f32,
205    pub is_ewa: bool,
206    pub is_resizable_kernel: bool,
207    pub is_area: bool,
208}
209
210impl<T> ResamplingFilter<T> {
211    fn new(kernel: fn(T) -> T, min_kernel_size: f32, is_ewa: bool) -> ResamplingFilter<T> {
212        ResamplingFilter {
213            kernel,
214            window: None,
215            min_kernel_size,
216            is_ewa,
217            is_resizable_kernel: true,
218            is_area: false,
219        }
220    }
221
222    fn new_with_window(
223        kernel: fn(T) -> T,
224        window: ResamplingWindow<T>,
225        min_kernel_size: f32,
226        is_ewa: bool,
227    ) -> ResamplingFilter<T> {
228        ResamplingFilter::<T> {
229            kernel,
230            window: Some(window),
231            min_kernel_size,
232            is_ewa,
233            is_resizable_kernel: true,
234            is_area: false,
235        }
236    }
237
238    fn new_with_fixed_kernel(
239        kernel: fn(T) -> T,
240        min_kernel_size: f32,
241        is_ewa: bool,
242    ) -> ResamplingFilter<T> {
243        ResamplingFilter::<T> {
244            kernel,
245            window: None,
246            min_kernel_size,
247            is_ewa,
248            is_resizable_kernel: false,
249            is_area: false,
250        }
251    }
252
253    fn new_with_area(kernel: fn(T) -> T, min_kernel_size: f32) -> ResamplingFilter<T> {
254        ResamplingFilter {
255            kernel,
256            window: None,
257            min_kernel_size,
258            is_ewa: false,
259            is_resizable_kernel: true,
260            is_area: true,
261        }
262    }
263}
264
265const JINC_R3: f32 = 3.2383154841662362f32;
266const JINC_R4: f32 = 4.2410628637960699f32;
267
268impl ResamplingFunction {
269    pub(crate) fn get_resampling_filter<T>(&self) -> ResamplingFilter<T>
270    where
271        T: Copy
272            + Neg
273            + Signed
274            + Float
275            + 'static
276            + ConstPI
277            + MulAssign<T>
278            + AddAssign<T>
279            + AsPrimitive<f64>
280            + AsPrimitive<usize>
281            + Jinc<T>
282            + ConstSqrt2
283            + Trigonometry
284            + Exponential
285            + Sinc,
286        f32: AsPrimitive<T>,
287        f64: AsPrimitive<T>,
288        usize: AsPrimitive<T>,
289    {
290        match self {
291            ResamplingFunction::Bilinear => ResamplingFilter::new(bilinear, 2f32, false),
292            ResamplingFunction::Nearest => {
293                // Just a stab for nearest
294                ResamplingFilter::new(bilinear, 2f32, false)
295            }
296            ResamplingFunction::Cubic => ResamplingFilter::new(cubic_spline, 2f32, false),
297            ResamplingFunction::MitchellNetravalli => {
298                ResamplingFilter::new(mitchell_netravalli, 2f32, false)
299            }
300            ResamplingFunction::Lanczos3 => ResamplingFilter::new(lanczos3, 3f32, false),
301            ResamplingFunction::CatmullRom => ResamplingFilter::new(catmull_rom, 2f32, false),
302            ResamplingFunction::Hermite => ResamplingFilter::new(hermite_spline, 2f32, false),
303            ResamplingFunction::BSpline => ResamplingFilter::new(b_spline, 2f32, false),
304            ResamplingFunction::Hann => ResamplingFilter::new(hann, 3f32, false),
305            ResamplingFunction::Bicubic => ResamplingFilter::new(bicubic_spline, 2f32, false),
306            ResamplingFunction::Lanczos4 => ResamplingFilter::new(lanczos4, 4f32, false),
307            ResamplingFunction::Lanczos2 => ResamplingFilter::new(lanczos2, 2f32, false),
308            ResamplingFunction::Hamming => ResamplingFilter::new(hamming, 2f32, false),
309            ResamplingFunction::Hanning => ResamplingFilter::new(hanning, 2f32, false),
310            ResamplingFunction::EwaHanning => ResamplingFilter::new_with_window(
311                T::jinc(),
312                ResamplingWindow::new(hanning, 2f32, 0f32, 0f32),
313                1f32,
314                true,
315            ),
316            ResamplingFunction::Welch => ResamplingFilter::new(welch, 2f32, false),
317            ResamplingFunction::Quadric => ResamplingFilter::new(quadric, 2f32, false),
318            ResamplingFunction::EwaQuadric => ResamplingFilter::new(quadric, 2f32, true),
319            ResamplingFunction::Gaussian => ResamplingFilter::new(gaussian, 2f32, false),
320            ResamplingFunction::Sphinx => ResamplingFilter::new(sphinx, 2f32, false),
321            ResamplingFunction::Bartlett => ResamplingFilter::new(bartlett, 2f32, false),
322            ResamplingFunction::Robidoux => ResamplingFilter::new(robidoux, 2f32, false),
323            ResamplingFunction::EwaRobidoux => ResamplingFilter::new(robidoux, 2f32, true),
324            ResamplingFunction::RobidouxSharp => ResamplingFilter::new(robidoux_sharp, 2f32, false),
325            ResamplingFunction::EwaRobidouxSharp => {
326                ResamplingFilter::new(robidoux_sharp, 2f32, true)
327            }
328            ResamplingFunction::Spline16 => {
329                ResamplingFilter::new_with_fixed_kernel(spline16, 2f32, false)
330            }
331            ResamplingFunction::Spline36 => {
332                ResamplingFilter::new_with_fixed_kernel(spline36, 4f32, false)
333            }
334            ResamplingFunction::Spline64 => {
335                ResamplingFilter::new_with_fixed_kernel(spline64, 6f32, false)
336            }
337            ResamplingFunction::Kaiser => ResamplingFilter::new(kaiser, 2f32, false),
338            ResamplingFunction::BartlettHann => ResamplingFilter::new(bartlett_hann, 2f32, false),
339            ResamplingFunction::Box => ResamplingFilter::new(box_weight, 2f32, false),
340            ResamplingFunction::Area => ResamplingFilter::new_with_area(box_weight, 2f32),
341            ResamplingFunction::Bohman => ResamplingFilter::new(bohman, 2f32, false),
342            ResamplingFunction::Lanczos2Jinc => ResamplingFilter::new(lanczos2_jinc, 2f32, false),
343            ResamplingFunction::Lanczos3Jinc => ResamplingFilter::new(lanczos3_jinc, 3f32, false),
344            ResamplingFunction::EwaLanczos3Jinc => ResamplingFilter::new(lanczos3_jinc, 3f32, true),
345            ResamplingFunction::Lanczos4Jinc => ResamplingFilter::new(lanczos4_jinc, 4f32, false),
346            ResamplingFunction::Blackman => ResamplingFilter::new(blackman, 2f32, false),
347            ResamplingFunction::EwaBlackman => ResamplingFilter::new(blackman, 2f32, true),
348            ResamplingFunction::Ginseng => ResamplingFilter::new_with_window(
349                sinc,
350                ResamplingWindow::new(T::jinc(), 3f32, 1f32, 0f32),
351                3f32,
352                false,
353            ),
354            ResamplingFunction::EwaGinseng => ResamplingFilter::new_with_window(
355                sinc,
356                ResamplingWindow::new(T::jinc(), JINC_R3, 1f32, 0f32),
357                3f32,
358                true,
359            ),
360            ResamplingFunction::EwaLanczosSharp => ResamplingFilter::new_with_window(
361                T::jinc(),
362                ResamplingWindow::new(T::jinc(), JINC_R3, 0.9812505837223707f32, 0f32),
363                3f32,
364                true,
365            ),
366            ResamplingFunction::EwaLanczos4Sharpest => ResamplingFilter::new_with_window(
367                T::jinc(),
368                ResamplingWindow::new(T::jinc(), JINC_R4, 0.8845120932605005f32, 0f32),
369                4f32,
370                true,
371            ),
372            ResamplingFunction::EwaLanczosSoft => ResamplingFilter::new_with_window(
373                T::jinc(),
374                ResamplingWindow::new(T::jinc(), JINC_R3, 1.0164667662867047f32, 0f32),
375                3f32,
376                true,
377            ),
378            ResamplingFunction::HaasnSoft => ResamplingFilter::new_with_window(
379                T::jinc(),
380                ResamplingWindow::new(hanning, 3f32, 1.11f32, 0f32),
381                3f32,
382                false,
383            ),
384            ResamplingFunction::Lagrange2 => ResamplingFilter::new(lagrange2, 2f32, false),
385            ResamplingFunction::Lagrange3 => ResamplingFilter::new(lagrange3, 3f32, false),
386            ResamplingFunction::Lanczos6Jinc => ResamplingFilter::new(lanczos6_jinc, 6f32, false),
387            ResamplingFunction::Lanczos6 => ResamplingFilter::new(lanczos6, 6f32, false),
388        }
389    }
390}