Coverage Report

Created: 2025-11-24 07:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/pic-scale-safe-0.1.5/src/sampler.rs
Line
Count
Source
1
/*
2
 * Copyright (c) Radzivon Bartoshyk, 10/2024. 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
31
use crate::math::bartlett::{bartlett, bartlett_hann};
32
use crate::math::bc_spline::{
33
    b_spline, catmull_rom, hermite_spline, mitchell_netravalli, robidoux, robidoux_sharp,
34
};
35
use crate::math::bilinear::bilinear;
36
use crate::math::blackman::blackman;
37
use crate::math::bohman::bohman;
38
use crate::math::cubic::{bicubic_spline, cubic_spline};
39
use crate::math::gaussian::gaussian;
40
use crate::math::hann::{hamming, hann, hanning};
41
use crate::math::kaiser::kaiser;
42
use crate::math::lagrange::{lagrange2, lagrange3};
43
use crate::math::lanczos::{
44
    lanczos2, lanczos2_jinc, lanczos3, lanczos3_jinc, lanczos4, lanczos4_jinc, lanczos6,
45
    lanczos6_jinc,
46
};
47
use crate::math::quadric::quadric;
48
use crate::math::sinc::sinc;
49
use crate::math::sphinx::sphinx;
50
use crate::math::spline_n::{spline16, spline36, spline64};
51
use crate::math::welch::welch;
52
use crate::math::{ConstPI, ConstSqrt2, Jinc};
53
use num_traits::{AsPrimitive, Float, Signed};
54
use std::ops::{AddAssign, MulAssign, Neg};
55
56
#[inline(always)]
57
0
pub(crate) fn box_weight<V: Copy + 'static>(_: V) -> V
58
0
where
59
0
    f32: AsPrimitive<V>,
60
{
61
0
    1f32.as_()
62
0
}
63
64
#[derive(Debug, Copy, Clone, Default, Ord, PartialOrd, Eq, PartialEq)]
65
/// Describes resampling function that will be used
66
pub 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
    Blackman,
80
    Welch,
81
    Quadric,
82
    Gaussian,
83
    Sphinx,
84
    Bartlett,
85
    Robidoux,
86
    RobidouxSharp,
87
    Spline16,
88
    Spline36,
89
    Spline64,
90
    Kaiser,
91
    BartlettHann,
92
    Box,
93
    Bohman,
94
    Lanczos2,
95
    Lanczos3,
96
    Lanczos4,
97
    Lanczos2Jinc,
98
    Lanczos3Jinc,
99
    Lanczos4Jinc,
100
    Ginseng,
101
    HaasnSoft,
102
    Lagrange2,
103
    Lagrange3,
104
    Lanczos6,
105
    Lanczos6Jinc,
106
    /// This method replicates `INTER_AREA` behaviour from OpenCV
107
    Area,
108
}
109
110
impl From<u32> for ResamplingFunction {
111
0
    fn from(value: u32) -> Self {
112
0
        match value {
113
0
            0 => ResamplingFunction::Bilinear,
114
0
            1 => ResamplingFunction::Nearest,
115
0
            2 => ResamplingFunction::Cubic,
116
0
            3 => ResamplingFunction::MitchellNetravalli,
117
0
            4 => ResamplingFunction::CatmullRom,
118
0
            5 => ResamplingFunction::Hermite,
119
0
            6 => ResamplingFunction::BSpline,
120
0
            7 => ResamplingFunction::Hann,
121
0
            8 => ResamplingFunction::Bicubic,
122
0
            9 => ResamplingFunction::Hamming,
123
0
            10 => ResamplingFunction::Hanning,
124
0
            11 => ResamplingFunction::Blackman,
125
0
            12 => ResamplingFunction::Welch,
126
0
            13 => ResamplingFunction::Quadric,
127
0
            14 => ResamplingFunction::Gaussian,
128
0
            15 => ResamplingFunction::Sphinx,
129
0
            16 => ResamplingFunction::Bartlett,
130
0
            17 => ResamplingFunction::Robidoux,
131
0
            18 => ResamplingFunction::RobidouxSharp,
132
0
            19 => ResamplingFunction::Spline16,
133
0
            20 => ResamplingFunction::Spline36,
134
0
            21 => ResamplingFunction::Spline64,
135
0
            22 => ResamplingFunction::Kaiser,
136
0
            23 => ResamplingFunction::BartlettHann,
137
0
            24 => ResamplingFunction::Box,
138
0
            25 => ResamplingFunction::Bohman,
139
0
            26 => ResamplingFunction::Lanczos2,
140
0
            27 => ResamplingFunction::Lanczos3,
141
0
            28 => ResamplingFunction::Lanczos4,
142
0
            29 => ResamplingFunction::Lanczos2Jinc,
143
0
            30 => ResamplingFunction::Lanczos3Jinc,
144
0
            31 => ResamplingFunction::Lanczos4Jinc,
145
0
            32 => ResamplingFunction::Ginseng,
146
0
            33 => ResamplingFunction::HaasnSoft,
147
0
            34 => ResamplingFunction::Lagrange2,
148
0
            35 => ResamplingFunction::Lagrange3,
149
0
            36 => ResamplingFunction::Lanczos6,
150
0
            37 => ResamplingFunction::Lanczos6Jinc,
151
0
            38 => ResamplingFunction::Area,
152
0
            _ => ResamplingFunction::Bilinear,
153
        }
154
0
    }
155
}
156
157
#[derive(Debug, Copy, Clone)]
158
pub(crate) struct ResamplingWindow<T> {
159
    pub(crate) window: fn(T) -> T,
160
    pub(crate) window_size: f32,
161
    pub(crate) blur: f32,
162
    pub(crate) taper: f32,
163
}
164
165
impl<T> ResamplingWindow<T> {
166
0
    fn new(window: fn(T) -> T, window_size: f32, blur: f32, taper: f32) -> ResamplingWindow<T> {
167
0
        ResamplingWindow {
168
0
            window,
169
0
            window_size,
170
0
            blur,
171
0
            taper,
172
0
        }
173
0
    }
174
}
175
176
#[derive(Debug, Copy, Clone)]
177
pub(crate) struct ResamplingFilter<T> {
178
    pub kernel: fn(T) -> T,
179
    pub window: Option<ResamplingWindow<T>>,
180
    pub min_kernel_size: f32,
181
    pub is_resizable_kernel: bool,
182
    pub is_area_filter: bool,
183
}
184
185
impl<T> ResamplingFilter<T> {
186
0
    fn new(kernel: fn(T) -> T, min_kernel_size: f32) -> ResamplingFilter<T> {
187
0
        ResamplingFilter {
188
0
            kernel,
189
0
            window: None,
190
0
            min_kernel_size,
191
0
            is_resizable_kernel: true,
192
0
            is_area_filter: false,
193
0
        }
194
0
    }
195
196
0
    fn new_area(kernel: fn(T) -> T, min_kernel_size: f32) -> ResamplingFilter<T> {
197
0
        ResamplingFilter {
198
0
            kernel,
199
0
            window: None,
200
0
            min_kernel_size,
201
0
            is_resizable_kernel: true,
202
0
            is_area_filter: true,
203
0
        }
204
0
    }
205
206
0
    fn new_with_window(
207
0
        kernel: fn(T) -> T,
208
0
        window: ResamplingWindow<T>,
209
0
        min_kernel_size: f32,
210
0
    ) -> ResamplingFilter<T> {
211
0
        ResamplingFilter::<T> {
212
0
            kernel,
213
0
            window: Some(window),
214
0
            min_kernel_size,
215
0
            is_resizable_kernel: true,
216
0
            is_area_filter: false,
217
0
        }
218
0
    }
219
220
0
    fn new_with_fixed_kernel(kernel: fn(T) -> T, min_kernel_size: f32) -> ResamplingFilter<T> {
221
0
        ResamplingFilter::<T> {
222
0
            kernel,
223
0
            window: None,
224
0
            min_kernel_size,
225
0
            is_resizable_kernel: false,
226
0
            is_area_filter: false,
227
0
        }
228
0
    }
229
}
230
231
impl ResamplingFunction {
232
0
    pub(crate) fn get_resampling_filter<T>(&self) -> ResamplingFilter<T>
233
0
    where
234
0
        T: Copy
235
0
            + Neg
236
0
            + Signed
237
0
            + Float
238
0
            + 'static
239
0
            + ConstPI
240
0
            + MulAssign<T>
241
0
            + AddAssign<T>
242
0
            + AsPrimitive<f64>
243
0
            + AsPrimitive<usize>
244
0
            + Jinc<T>
245
0
            + ConstSqrt2,
246
0
        f32: AsPrimitive<T>,
247
0
        f64: AsPrimitive<T>,
248
0
        usize: AsPrimitive<T>,
249
    {
250
0
        match self {
251
0
            ResamplingFunction::Bilinear => ResamplingFilter::new(bilinear, 1f32),
252
0
            ResamplingFunction::Area => ResamplingFilter::new_area(box_weight, 0.5f32),
253
            ResamplingFunction::Nearest => {
254
                // Just a stab for nearest
255
0
                ResamplingFilter::new(bilinear, 2f32)
256
            }
257
0
            ResamplingFunction::Cubic => ResamplingFilter::new(cubic_spline, 2f32),
258
            ResamplingFunction::MitchellNetravalli => {
259
0
                ResamplingFilter::new(mitchell_netravalli, 2f32)
260
            }
261
0
            ResamplingFunction::Lanczos3 => ResamplingFilter::new(lanczos3, 3f32),
262
0
            ResamplingFunction::CatmullRom => ResamplingFilter::new(catmull_rom, 2f32),
263
0
            ResamplingFunction::Hermite => ResamplingFilter::new(hermite_spline, 2f32),
264
0
            ResamplingFunction::BSpline => ResamplingFilter::new(b_spline, 2f32),
265
0
            ResamplingFunction::Hann => ResamplingFilter::new(hann, 3f32),
266
0
            ResamplingFunction::Bicubic => ResamplingFilter::new(bicubic_spline, 2f32),
267
0
            ResamplingFunction::Lanczos4 => ResamplingFilter::new(lanczos4, 4f32),
268
0
            ResamplingFunction::Lanczos2 => ResamplingFilter::new(lanczos2, 2f32),
269
0
            ResamplingFunction::Hamming => ResamplingFilter::new(hamming, 1f32),
270
0
            ResamplingFunction::Hanning => ResamplingFilter::new(hanning, 2f32),
271
0
            ResamplingFunction::Welch => ResamplingFilter::new(welch, 2f32),
272
0
            ResamplingFunction::Quadric => ResamplingFilter::new(quadric, 2f32),
273
0
            ResamplingFunction::Gaussian => ResamplingFilter::new(gaussian, 2f32),
274
0
            ResamplingFunction::Sphinx => ResamplingFilter::new(sphinx, 2f32),
275
0
            ResamplingFunction::Bartlett => ResamplingFilter::new(bartlett, 2f32),
276
0
            ResamplingFunction::Robidoux => ResamplingFilter::new(robidoux, 2f32),
277
0
            ResamplingFunction::RobidouxSharp => ResamplingFilter::new(robidoux_sharp, 2f32),
278
0
            ResamplingFunction::Spline16 => ResamplingFilter::new_with_fixed_kernel(spline16, 2f32),
279
0
            ResamplingFunction::Spline36 => ResamplingFilter::new_with_fixed_kernel(spline36, 4f32),
280
0
            ResamplingFunction::Spline64 => ResamplingFilter::new_with_fixed_kernel(spline64, 6f32),
281
0
            ResamplingFunction::Kaiser => ResamplingFilter::new(kaiser, 2f32),
282
0
            ResamplingFunction::BartlettHann => ResamplingFilter::new(bartlett_hann, 2f32),
283
0
            ResamplingFunction::Box => ResamplingFilter::new(box_weight, 2f32),
284
0
            ResamplingFunction::Bohman => ResamplingFilter::new(bohman, 2f32),
285
0
            ResamplingFunction::Lanczos2Jinc => ResamplingFilter::new(lanczos2_jinc, 2f32),
286
0
            ResamplingFunction::Lanczos3Jinc => ResamplingFilter::new(lanczos3_jinc, 3f32),
287
0
            ResamplingFunction::Lanczos4Jinc => ResamplingFilter::new(lanczos4_jinc, 4f32),
288
0
            ResamplingFunction::Blackman => ResamplingFilter::new(blackman, 2f32),
289
0
            ResamplingFunction::Ginseng => ResamplingFilter::new_with_window(
290
0
                sinc,
291
0
                ResamplingWindow::new(T::jinc(), 3f32, 1f32, 0f32),
292
                3f32,
293
            ),
294
0
            ResamplingFunction::HaasnSoft => ResamplingFilter::new_with_window(
295
0
                T::jinc(),
296
0
                ResamplingWindow::new(hanning, 3f32, 1.11f32, 0f32),
297
                3f32,
298
            ),
299
0
            ResamplingFunction::Lagrange2 => ResamplingFilter::new(lagrange2, 2f32),
300
0
            ResamplingFunction::Lagrange3 => ResamplingFilter::new(lagrange3, 3f32),
301
0
            ResamplingFunction::Lanczos6Jinc => ResamplingFilter::new(lanczos6_jinc, 6f32),
302
0
            ResamplingFunction::Lanczos6 => ResamplingFilter::new(lanczos6, 6f32),
303
        }
304
0
    }
305
}