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#[derive(Debug, Copy, Clone)]
178pub struct ResamplingWindow<T> {
179    pub(crate) window: fn(T) -> T,
180    pub(crate) window_size: f32,
181    pub(crate) blur: f32,
182    pub(crate) taper: f32,
183}
184
185impl<T> ResamplingWindow<T> {
186    fn new(window: fn(T) -> T, window_size: f32, blur: f32, taper: f32) -> ResamplingWindow<T> {
187        ResamplingWindow {
188            window,
189            window_size,
190            blur,
191            taper,
192        }
193    }
194}
195
196#[derive(Debug, Copy, Clone)]
197pub struct ResamplingFilter<T> {
198    pub kernel: fn(T) -> T,
199    pub window: Option<ResamplingWindow<T>>,
200    pub min_kernel_size: f32,
201    pub is_ewa: bool,
202    pub is_resizable_kernel: bool,
203    pub is_area: bool,
204}
205
206impl<T> ResamplingFilter<T> {
207    fn new(kernel: fn(T) -> T, min_kernel_size: f32, is_ewa: bool) -> ResamplingFilter<T> {
208        ResamplingFilter {
209            kernel,
210            window: None,
211            min_kernel_size,
212            is_ewa,
213            is_resizable_kernel: true,
214            is_area: false,
215        }
216    }
217
218    fn new_with_window(
219        kernel: fn(T) -> T,
220        window: ResamplingWindow<T>,
221        min_kernel_size: f32,
222        is_ewa: bool,
223    ) -> ResamplingFilter<T> {
224        ResamplingFilter::<T> {
225            kernel,
226            window: Some(window),
227            min_kernel_size,
228            is_ewa,
229            is_resizable_kernel: true,
230            is_area: false,
231        }
232    }
233
234    fn new_with_fixed_kernel(
235        kernel: fn(T) -> T,
236        min_kernel_size: f32,
237        is_ewa: bool,
238    ) -> ResamplingFilter<T> {
239        ResamplingFilter::<T> {
240            kernel,
241            window: None,
242            min_kernel_size,
243            is_ewa,
244            is_resizable_kernel: false,
245            is_area: false,
246        }
247    }
248
249    fn new_with_area(kernel: fn(T) -> T, min_kernel_size: f32) -> ResamplingFilter<T> {
250        ResamplingFilter {
251            kernel,
252            window: None,
253            min_kernel_size,
254            is_ewa: false,
255            is_resizable_kernel: true,
256            is_area: true,
257        }
258    }
259}
260
261const JINC_R3: f32 = 3.2383154841662362f32;
262const JINC_R4: f32 = 4.2410628637960699f32;
263
264impl ResamplingFunction {
265    pub fn get_resampling_filter<T>(&self) -> ResamplingFilter<T>
266    where
267        T: Copy
268            + Neg
269            + Signed
270            + Float
271            + 'static
272            + ConstPI
273            + MulAssign<T>
274            + AddAssign<T>
275            + AsPrimitive<f64>
276            + AsPrimitive<usize>
277            + Jinc<T>
278            + ConstSqrt2,
279        f32: AsPrimitive<T>,
280        f64: AsPrimitive<T>,
281        usize: AsPrimitive<T>,
282    {
283        match self {
284            ResamplingFunction::Bilinear => ResamplingFilter::new(bilinear, 2f32, false),
285            ResamplingFunction::Nearest => {
286                // Just a stab for nearest
287                ResamplingFilter::new(bilinear, 2f32, false)
288            }
289            ResamplingFunction::Cubic => ResamplingFilter::new(cubic_spline, 2f32, false),
290            ResamplingFunction::MitchellNetravalli => {
291                ResamplingFilter::new(mitchell_netravalli, 2f32, false)
292            }
293            ResamplingFunction::Lanczos3 => ResamplingFilter::new(lanczos3, 3f32, false),
294            ResamplingFunction::CatmullRom => ResamplingFilter::new(catmull_rom, 2f32, false),
295            ResamplingFunction::Hermite => ResamplingFilter::new(hermite_spline, 2f32, false),
296            ResamplingFunction::BSpline => ResamplingFilter::new(b_spline, 2f32, false),
297            ResamplingFunction::Hann => ResamplingFilter::new(hann, 3f32, false),
298            ResamplingFunction::Bicubic => ResamplingFilter::new(bicubic_spline, 2f32, false),
299            ResamplingFunction::Lanczos4 => ResamplingFilter::new(lanczos4, 4f32, false),
300            ResamplingFunction::Lanczos2 => ResamplingFilter::new(lanczos2, 2f32, false),
301            ResamplingFunction::Hamming => ResamplingFilter::new(hamming, 2f32, false),
302            ResamplingFunction::Hanning => ResamplingFilter::new(hanning, 2f32, false),
303            ResamplingFunction::EwaHanning => ResamplingFilter::new_with_window(
304                T::jinc(),
305                ResamplingWindow::new(hanning, 2f32, 0f32, 0f32),
306                1f32,
307                true,
308            ),
309            ResamplingFunction::Welch => ResamplingFilter::new(welch, 2f32, false),
310            ResamplingFunction::Quadric => ResamplingFilter::new(quadric, 2f32, false),
311            ResamplingFunction::EwaQuadric => ResamplingFilter::new(quadric, 2f32, true),
312            ResamplingFunction::Gaussian => ResamplingFilter::new(gaussian, 2f32, false),
313            ResamplingFunction::Sphinx => ResamplingFilter::new(sphinx, 2f32, false),
314            ResamplingFunction::Bartlett => ResamplingFilter::new(bartlett, 2f32, false),
315            ResamplingFunction::Robidoux => ResamplingFilter::new(robidoux, 2f32, false),
316            ResamplingFunction::EwaRobidoux => ResamplingFilter::new(robidoux, 2f32, true),
317            ResamplingFunction::RobidouxSharp => ResamplingFilter::new(robidoux_sharp, 2f32, false),
318            ResamplingFunction::EwaRobidouxSharp => {
319                ResamplingFilter::new(robidoux_sharp, 2f32, true)
320            }
321            ResamplingFunction::Spline16 => {
322                ResamplingFilter::new_with_fixed_kernel(spline16, 2f32, false)
323            }
324            ResamplingFunction::Spline36 => {
325                ResamplingFilter::new_with_fixed_kernel(spline36, 4f32, false)
326            }
327            ResamplingFunction::Spline64 => {
328                ResamplingFilter::new_with_fixed_kernel(spline64, 6f32, false)
329            }
330            ResamplingFunction::Kaiser => ResamplingFilter::new(kaiser, 2f32, false),
331            ResamplingFunction::BartlettHann => ResamplingFilter::new(bartlett_hann, 2f32, false),
332            ResamplingFunction::Box => ResamplingFilter::new(box_weight, 2f32, false),
333            ResamplingFunction::Area => ResamplingFilter::new_with_area(box_weight, 2f32),
334            ResamplingFunction::Bohman => ResamplingFilter::new(bohman, 2f32, false),
335            ResamplingFunction::Lanczos2Jinc => ResamplingFilter::new(lanczos2_jinc, 2f32, false),
336            ResamplingFunction::Lanczos3Jinc => ResamplingFilter::new(lanczos3_jinc, 3f32, false),
337            ResamplingFunction::EwaLanczos3Jinc => ResamplingFilter::new(lanczos3_jinc, 3f32, true),
338            ResamplingFunction::Lanczos4Jinc => ResamplingFilter::new(lanczos4_jinc, 4f32, false),
339            ResamplingFunction::Blackman => ResamplingFilter::new(blackman, 2f32, false),
340            ResamplingFunction::EwaBlackman => ResamplingFilter::new(blackman, 2f32, true),
341            ResamplingFunction::Ginseng => ResamplingFilter::new_with_window(
342                sinc,
343                ResamplingWindow::new(T::jinc(), 3f32, 1f32, 0f32),
344                3f32,
345                false,
346            ),
347            ResamplingFunction::EwaGinseng => ResamplingFilter::new_with_window(
348                sinc,
349                ResamplingWindow::new(T::jinc(), JINC_R3, 1f32, 0f32),
350                3f32,
351                true,
352            ),
353            ResamplingFunction::EwaLanczosSharp => ResamplingFilter::new_with_window(
354                T::jinc(),
355                ResamplingWindow::new(T::jinc(), JINC_R3, 0.9812505837223707f32, 0f32),
356                3f32,
357                true,
358            ),
359            ResamplingFunction::EwaLanczos4Sharpest => ResamplingFilter::new_with_window(
360                T::jinc(),
361                ResamplingWindow::new(T::jinc(), JINC_R4, 0.8845120932605005f32, 0f32),
362                4f32,
363                true,
364            ),
365            ResamplingFunction::EwaLanczosSoft => ResamplingFilter::new_with_window(
366                T::jinc(),
367                ResamplingWindow::new(T::jinc(), JINC_R3, 1.0164667662867047f32, 0f32),
368                3f32,
369                true,
370            ),
371            ResamplingFunction::HaasnSoft => ResamplingFilter::new_with_window(
372                T::jinc(),
373                ResamplingWindow::new(hanning, 3f32, 1.11f32, 0f32),
374                3f32,
375                false,
376            ),
377            ResamplingFunction::Lagrange2 => ResamplingFilter::new(lagrange2, 2f32, false),
378            ResamplingFunction::Lagrange3 => ResamplingFilter::new(lagrange3, 3f32, false),
379            ResamplingFunction::Lanczos6Jinc => ResamplingFilter::new(lanczos6_jinc, 6f32, false),
380            ResamplingFunction::Lanczos6 => ResamplingFilter::new(lanczos6, 6f32, false),
381        }
382    }
383}