use crate::util::{CorrMatchError, CorrMatchResult};
pub(crate) mod integral;
#[cfg(feature = "image-io")]
pub mod io;
pub mod pyramid;
#[derive(Copy, Clone)]
pub struct ImageView<'a, T> {
data: &'a [T],
width: usize,
height: usize,
stride: usize,
}
impl<'a, T> ImageView<'a, T> {
pub fn from_slice(data: &'a [T], width: usize, height: usize) -> CorrMatchResult<Self> {
Self::new(data, width, height, width)
}
pub fn new(data: &'a [T], width: usize, height: usize, stride: usize) -> CorrMatchResult<Self> {
let needed = required_len(width, height, stride)?;
if data.len() < needed {
return Err(CorrMatchError::BufferTooSmall {
needed,
got: data.len(),
});
}
Ok(Self {
data,
width,
height,
stride,
})
}
pub fn width(&self) -> usize {
self.width
}
pub fn height(&self) -> usize {
self.height
}
pub fn stride(&self) -> usize {
self.stride
}
pub fn as_slice(&self) -> &'a [T] {
self.data
}
pub fn get(&self, x: usize, y: usize) -> Option<&'a T> {
if x >= self.width || y >= self.height {
return None;
}
let idx = y.checked_mul(self.stride)?.checked_add(x)?;
self.data.get(idx)
}
pub fn row(&self, y: usize) -> Option<&'a [T]> {
if y >= self.height {
return None;
}
let start = y.checked_mul(self.stride)?;
let end = start.checked_add(self.width)?;
self.data.get(start..end)
}
pub fn roi(
&self,
x: usize,
y: usize,
width: usize,
height: usize,
) -> CorrMatchResult<ImageView<'a, T>> {
if width == 0 || height == 0 {
return Err(CorrMatchError::InvalidDimensions { width, height });
}
let img_width = self.width;
let img_height = self.height;
if x >= img_width || y >= img_height {
return Err(CorrMatchError::RoiOutOfBounds {
x,
y,
width,
height,
img_width,
img_height,
});
}
let end_x = x.checked_add(width).ok_or(CorrMatchError::RoiOutOfBounds {
x,
y,
width,
height,
img_width,
img_height,
})?;
let end_y = y
.checked_add(height)
.ok_or(CorrMatchError::RoiOutOfBounds {
x,
y,
width,
height,
img_width,
img_height,
})?;
if end_x > img_width || end_y > img_height {
return Err(CorrMatchError::RoiOutOfBounds {
x,
y,
width,
height,
img_width,
img_height,
});
}
let start = y
.checked_mul(self.stride)
.and_then(|v| v.checked_add(x))
.ok_or(CorrMatchError::InvalidDimensions {
width: img_width,
height: img_height,
})?;
let data = self
.data
.get(start..)
.ok_or(CorrMatchError::BufferTooSmall {
needed: start.saturating_add(1),
got: self.data.len(),
})?;
ImageView::new(data, width, height, self.stride)
}
}
fn required_len(width: usize, height: usize, stride: usize) -> CorrMatchResult<usize> {
if width == 0 || height == 0 {
return Err(CorrMatchError::InvalidDimensions { width, height });
}
if stride < width {
return Err(CorrMatchError::InvalidStride { width, stride });
}
let needed = (height - 1)
.checked_mul(stride)
.and_then(|v| v.checked_add(width))
.ok_or(CorrMatchError::InvalidDimensions { width, height })?;
Ok(needed)
}
pub struct OwnedImage {
data: Vec<u8>,
width: usize,
height: usize,
stride: usize,
}
impl OwnedImage {
pub fn new(data: Vec<u8>, width: usize, height: usize) -> CorrMatchResult<Self> {
if width == 0 || height == 0 {
return Err(CorrMatchError::InvalidDimensions { width, height });
}
let needed = width
.checked_mul(height)
.ok_or(CorrMatchError::InvalidDimensions { width, height })?;
if data.len() < needed {
return Err(CorrMatchError::BufferTooSmall {
needed,
got: data.len(),
});
}
if data.len() > needed {
return Err(CorrMatchError::InvalidDimensions { width, height });
}
Ok(Self {
data,
width,
height,
stride: width,
})
}
pub(crate) fn from_view(view: ImageView<'_, u8>) -> CorrMatchResult<Self> {
let width = view.width();
let height = view.height();
let needed = width
.checked_mul(height)
.ok_or(CorrMatchError::InvalidDimensions { width, height })?;
let mut data = vec![0u8; needed];
for y in 0..height {
let row = view.row(y).ok_or_else(|| {
let needed = (y + 1)
.checked_mul(view.stride())
.and_then(|v| v.checked_add(view.width()))
.unwrap_or(usize::MAX);
CorrMatchError::BufferTooSmall {
needed,
got: view.as_slice().len(),
}
})?;
let start = y * width;
let end = start + width;
data[start..end].copy_from_slice(row);
}
Self::new(data, width, height)
}
pub fn view(&self) -> ImageView<'_, u8> {
ImageView {
data: &self.data,
width: self.width,
height: self.height,
stride: self.stride,
}
}
pub fn data(&self) -> &[u8] {
&self.data
}
pub fn width(&self) -> usize {
self.width
}
pub fn height(&self) -> usize {
self.height
}
pub fn stride(&self) -> usize {
self.stride
}
}