Skip to content

Commit a6beac2

Browse files
committed
Add Padding implementation
Added no padding and constant padding
1 parent 245df40 commit a6beac2

File tree

2 files changed

+154
-2
lines changed

2 files changed

+154
-2
lines changed

src/core/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
2-
/// This module deals with different colour models and conversions between
1+
/// This module deals with different colour models and conversions between
32
/// colour models.
43
pub mod colour_models;
54
/// Core image type and simple operations on it
65
pub mod image;
6+
/// Image padding operations to increase the image size
7+
pub mod padding;
78
/// Essential traits for the functionality of `ndarray-vision`
89
pub mod traits;
910

1011
pub use colour_models::*;
1112
pub use image::*;
13+
pub use padding::*;
1214
pub use traits::*;

src/core/padding.rs

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
use crate::core::{ColourModel, Image};
2+
use ndarray::{prelude::*, s};
3+
use std::marker::PhantomData;
4+
5+
/// Defines a method for padding the data of an image applied directly to the
6+
/// ndarray type internally. Padding is symmetric
7+
pub trait PaddingStrategy<T>
8+
where
9+
T: Copy,
10+
{
11+
/// Taking in the image data and the margin to apply to rows and columns
12+
/// returns a padded image
13+
fn pad(&self, image: ArrayView3<T>, padding: (usize, usize)) -> Array3<T>;
14+
}
15+
16+
/// Doesn't apply any padding to the image returning it unaltered regardless
17+
/// of padding value
18+
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
19+
pub struct NoPadding;
20+
21+
/// Pad the image with a constant value
22+
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
23+
pub struct ConstantPadding<T>(T)
24+
where
25+
T: Copy;
26+
27+
impl<T> PaddingStrategy<T> for NoPadding
28+
where
29+
T: Copy + Sized,
30+
{
31+
fn pad(&self, image: ArrayView3<T>, _padding: (usize, usize)) -> Array3<T> {
32+
image.to_owned()
33+
}
34+
}
35+
36+
impl<T> PaddingStrategy<T> for ConstantPadding<T>
37+
where
38+
T: Copy + Sized,
39+
{
40+
fn pad(&self, image: ArrayView3<T>, padding: (usize, usize)) -> Array3<T> {
41+
let shape = (
42+
image.shape()[0] + padding.0 * 2,
43+
image.shape()[1] + padding.1 * 2,
44+
image.shape()[2],
45+
);
46+
47+
let mut result = Array::from_elem(shape, self.0);
48+
result
49+
.slice_mut(s![
50+
padding.0..shape.0 - padding.0,
51+
padding.1..shape.1 - padding.1,
52+
..
53+
])
54+
.assign(&image);
55+
56+
result
57+
}
58+
}
59+
60+
/// Padding extension for images
61+
pub trait PaddingExt
62+
where
63+
Self: Sized,
64+
{
65+
/// Data type for container
66+
type Data;
67+
/// Pad the object with the given padding and strategy
68+
fn pad(&self, padding: (usize, usize), strategy: &dyn PaddingStrategy<Self::Data>) -> Self;
69+
}
70+
71+
impl<T> PaddingExt for Array3<T>
72+
where
73+
T: Copy + Sized,
74+
{
75+
type Data = T;
76+
77+
fn pad(&self, padding: (usize, usize), strategy: &dyn PaddingStrategy<Self::Data>) -> Self {
78+
strategy.pad(self.view(), padding)
79+
}
80+
}
81+
82+
impl<T, C> PaddingExt for Image<T, C>
83+
where
84+
T: Copy + Sized,
85+
C: ColourModel,
86+
{
87+
type Data = T;
88+
89+
fn pad(&self, padding: (usize, usize), strategy: &dyn PaddingStrategy<Self::Data>) -> Self {
90+
Self {
91+
data: strategy.pad(self.data.view(), padding),
92+
model: PhantomData,
93+
}
94+
}
95+
}
96+
97+
#[cfg(test)]
98+
mod tests {
99+
use super::*;
100+
use crate::core::colour_models::{Gray, RGB};
101+
102+
#[test]
103+
fn constant_padding() {
104+
let i = Image::<u8, Gray>::from_shape_data(3, 3, vec![1, 2, 3, 4, 5, 6, 7, 8, 9]);
105+
106+
let p = i.pad((1, 1), &ConstantPadding(0));
107+
108+
let exp = Image::<u8, Gray>::from_shape_data(
109+
5,
110+
5,
111+
vec![
112+
0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 4, 5, 6, 0, 0, 7, 8, 9, 0, 0, 0, 0, 0, 0,
113+
],
114+
);
115+
assert_eq!(p, exp);
116+
117+
let p = i.pad((1, 1), &ConstantPadding(2));
118+
119+
let exp = Image::<u8, Gray>::from_shape_data(
120+
5,
121+
5,
122+
vec![
123+
2, 2, 2, 2, 2, 2, 1, 2, 3, 2, 2, 4, 5, 6, 2, 2, 7, 8, 9, 2, 2, 2, 2, 2, 2,
124+
],
125+
);
126+
assert_eq!(p, exp);
127+
128+
let p = i.pad((2, 0), &ConstantPadding(0));
129+
130+
let exp = Image::<u8, Gray>::from_shape_data(
131+
7,
132+
3,
133+
vec![
134+
0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
135+
],
136+
);
137+
assert_eq!(p, exp);
138+
}
139+
140+
#[test]
141+
fn no_padding() {
142+
let i = Image::<u8, RGB>::new(5, 5);
143+
let p = i.pad((10, 10), &NoPadding {});
144+
145+
assert_eq!(i, p);
146+
147+
let p = i.pad((0, 0), &NoPadding {});
148+
assert_eq!(i, p);
149+
}
150+
}

0 commit comments

Comments
 (0)