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