machine_vision_formats/
lib.rs

1//! Types and traits for working with raw image data from machine vision
2//! cameras.
3//!
4//! This crate aims to be a lowest common denominator for working with images
5//! from machine vision cameras from companies such as Basler, FLIR, and AVT.
6//!
7//! - Can be compiled without standard library support (`no_std`).
8//! - Includes strongly-typed pixel formats in the [pixel_format] module (e.g.
9//!   [pixel_format::RGB8] and [pixel_format::Mono8]) to ensure correct API use.
10//! - Includes types to efficiently iterate through images respecting strided
11//!   layouts in the [iter] module.
12//! - Includes structs which reference image data in the [image_ref] module.
13//! - Includes struct which owns image data in the [owned] module.
14//!
15//! Additionally several traits are defined to describe image data:
16//!
17//! - [ImageData] defines the basics, such as image dimensions and the data
18//!   buffer.
19//! - [ImageMutData] is implemented for images with mutable data.
20//! - [Stride] is implemented for images with strided data (i.e. each image row
21//!   is encoded with exactly the same number of bytes, which may including
22//!   padding).
23//! - Compound traits combine these basic traits. [ImageStride] implements both
24//!   [ImageData] and [Stride]. [ImageMutStride] implements [ImageMutData] and
25//!   [Stride]. [OwnedImage] implements [AsImageData], [ImageData], and
26//!   [Into<Vec<`u8`>>]. [OwnedImageStride] implements [AsImageStride],
27//!   [ImageStride], and [Into<Vec<`u8`>>].
28//! - Converter traits: [AsImageData] allows converting to `&dyn ImageData`,
29//!   [AsImageStride] to `&dyn ImageStride`, and [AsImageMutStride] to `&dyn
30//!   ImageMutStride`.
31//!
32//! This crate is used extensively in [Strand
33//! Camera](https://github.com/strawlab/strand-braid).
34#![cfg_attr(not(feature = "std"), no_std)]
35
36#[cfg(not(feature = "std"))]
37extern crate core as std;
38
39#[cfg(feature = "alloc")]
40extern crate alloc;
41
42#[cfg(feature = "alloc")]
43use alloc::vec::Vec;
44
45pub mod image_ref;
46pub mod iter;
47#[cfg(any(feature = "std", feature = "alloc"))]
48pub mod owned;
49
50#[cfg(any(feature = "std", feature = "alloc"))]
51pub mod cow;
52
53#[allow(non_camel_case_types)]
54pub mod pixel_format;
55
56// re-export
57pub use pixel_format::{PixFmt, PixelFormat};
58
59// ------------------------------- ImageBufferRef ----------------------
60
61/// A concrete type with view of image data with pixel format `F`.
62///
63/// This is a zero-size wrapper around a slice of bytes parameterized by the
64/// type `F`. It should cause no additional overhead above passing the raw byte
65/// slice but maintains a compile-time guarantee of the image format.
66#[derive(Clone)]
67pub struct ImageBufferRef<'a, F> {
68    /// The pixel format
69    pub pixel_format: std::marker::PhantomData<F>,
70    /// The raw bytes of the image buffer.
71    pub data: &'a [u8],
72}
73
74impl<F: PixelFormat> std::fmt::Debug for ImageBufferRef<'_, F> {
75    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
76        f.debug_struct("ImageBufferRef").finish_non_exhaustive()
77    }
78}
79
80impl<'a, F> ImageBufferRef<'a, F> {
81    #[inline]
82    pub fn new(data: &'a [u8]) -> Self {
83        Self {
84            pixel_format: std::marker::PhantomData,
85            data,
86        }
87    }
88    /// Copy the data to make a new buffer.
89    #[cfg(any(feature = "std", feature = "alloc"))]
90    #[inline]
91    pub fn to_buffer(&self) -> ImageBuffer<F> {
92        ImageBuffer::new(self.data.to_vec())
93    }
94}
95
96// ------------------------------- ImageBufferMutRef ----------------------
97
98/// A concrete type with view of mutable image data with pixel format `F`.
99///
100/// This is a zero-size wrapper around a slice of bytes parameterized by the
101/// type `F`. It should cause no additional overhead above passing the raw byte
102/// slice but maintains a compile-time guarantee of the image format.
103pub struct ImageBufferMutRef<'a, F> {
104    /// The pixel format
105    pub pixel_format: std::marker::PhantomData<F>,
106    /// The raw bytes of the image buffer.
107    pub data: &'a mut [u8],
108}
109
110impl<F: PixelFormat> std::fmt::Debug for ImageBufferMutRef<'_, F> {
111    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
112        f.debug_struct("ImageBufferMutRef").finish_non_exhaustive()
113    }
114}
115
116impl<'a, F> ImageBufferMutRef<'a, F> {
117    #[inline]
118    pub fn new(data: &'a mut [u8]) -> Self {
119        Self {
120            pixel_format: std::marker::PhantomData,
121            data,
122        }
123    }
124    /// Copy the data to make a new buffer.
125    #[cfg(any(feature = "std", feature = "alloc"))]
126    #[inline]
127    pub fn to_buffer(&self) -> ImageBuffer<F> {
128        ImageBuffer::new(self.data.to_vec())
129    }
130}
131
132// ------------------------------- ImageBuffer ----------------------
133
134/// A concrete type which containing image data with pixel format `F`.
135///
136/// This is a zero-size wrapper around bytes parameterized by the type `F`. It
137/// should cause no additional overhead above passing the raw byte vector but
138/// maintains a compile-time guarantee of the image format.
139#[cfg(any(feature = "std", feature = "alloc"))]
140#[derive(Clone)]
141pub struct ImageBuffer<F> {
142    /// The pixel format
143    pub pixel_format: std::marker::PhantomData<F>,
144    /// The raw bytes of the image buffer.
145    pub data: Vec<u8>,
146}
147
148#[cfg(any(feature = "std", feature = "alloc"))]
149impl<F: PixelFormat> std::fmt::Debug for ImageBuffer<F> {
150    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
151        f.debug_struct("ImageBuffer").finish_non_exhaustive()
152    }
153}
154
155#[cfg(any(feature = "std", feature = "alloc"))]
156impl<F> ImageBuffer<F> {
157    #[inline]
158    pub fn new(data: Vec<u8>) -> Self {
159        Self {
160            pixel_format: std::marker::PhantomData,
161            data,
162        }
163    }
164}
165
166// ------------------------------- simple traits ----------------------
167
168/// An image.
169///
170/// The pixel format is specified as the type `F`.
171pub trait ImageData<F> {
172    /// Number of pixel columns in the image. Note: this is not the stride.
173    fn width(&self) -> u32;
174    /// Number of pixel rows in the image.
175    fn height(&self) -> u32;
176    /// Returns the raw image data as specified by pixel format `F`.
177    ///
178    /// This does not copy the data but returns a view of it.
179    ///
180    /// This method may be deprecated in factor of `buffer_ref`.
181    #[inline]
182    fn image_data(&self) -> &[u8] {
183        self.buffer_ref().data
184    }
185    /// Returns the image buffer specified by pixel format `F`.
186    ///
187    /// Ideally, prefer using this over `image_data()`.
188    ///
189    /// This does not copy the data but returns a view of it.
190    fn buffer_ref(&self) -> ImageBufferRef<'_, F>;
191    /// Returns the image buffer specified by pixel format `F`.
192    ///
193    /// Implementations should move the data without copying it if possible. The
194    /// implementation may copy the data if needed. To guarantee a move with no
195    /// copy, use the `Into<Vec<u8>>` trait required by the OwnedImage trait.
196    #[cfg(any(feature = "std", feature = "alloc"))]
197    fn buffer(self) -> ImageBuffer<F>;
198    // fn pixel_format(&self) -> std::marker::PhantomData<F> {
199    //     std::marker::PhantomData
200    // }
201}
202
203/// A mutable image.
204///
205/// The pixel format is specified as the type `F`.
206pub trait ImageMutData<F>: ImageData<F> {
207    /// Returns the image mutable buffer specified by pixel format `F`.
208    ///
209    /// This does not copy the data but returns a mutable view of it.
210    fn buffer_mut_ref(&mut self) -> ImageBufferMutRef<'_, F>;
211}
212
213/// An image whose data is stored such that successive rows are a stride apart.
214///
215/// This is sometimes also called "pitch".
216pub trait Stride {
217    /// the width (in bytes) of each row of image data
218    ///
219    /// This is sometimes also called "pitch".
220    fn stride(&self) -> usize;
221}
222
223// ------------------------------- compound traits ----------------------
224
225/// Can be converted into `ImageData`.
226pub trait AsImageData<F>: ImageData<F> {
227    fn as_image_data(&self) -> &dyn ImageData<F>;
228}
229impl<S: ImageData<F>, F> AsImageData<F> for S {
230    fn as_image_data(&self) -> &dyn ImageData<F> {
231        self
232    }
233}
234
235#[cfg(any(feature = "std", feature = "alloc"))]
236/// An image which can be moved into `Vec<u8>`.
237// TODO: any breaking release should add Clone as a supertrait
238pub trait OwnedImage<F>: AsImageData<F> + ImageData<F> + Into<Vec<u8>> {}
239
240#[cfg(any(feature = "std", feature = "alloc"))]
241impl<S, F> OwnedImage<F> for S
242where
243    S: AsImageData<F> + ImageData<F>,
244    Vec<u8>: From<S>,
245{
246}
247
248/// An image with a stride.
249pub trait ImageStride<F>: ImageData<F> + Stride {}
250
251impl<S, F> ImageStride<F> for S where S: ImageData<F> + Stride {}
252
253/// Can be converted into `ImageStride`.
254pub trait AsImageStride<F>: ImageStride<F> {
255    fn as_image_stride(&self) -> &dyn ImageStride<F>;
256}
257impl<S: ImageStride<F>, F> AsImageStride<F> for S {
258    fn as_image_stride(&self) -> &dyn ImageStride<F> {
259        self
260    }
261}
262
263/// A mutable image with a stride.
264pub trait ImageMutStride<F>: ImageMutData<F> + Stride {}
265impl<S, F> ImageMutStride<F> for S where S: ImageMutData<F> + Stride {}
266
267/// Can be converted into `ImageMutStride`.
268pub trait AsImageMutStride<F>: ImageMutStride<F> {
269    fn as_image_mut_stride(&self) -> &dyn ImageMutStride<F>;
270}
271impl<S: ImageMutStride<F>, F> AsImageMutStride<F> for S {
272    fn as_image_mut_stride(&self) -> &dyn ImageMutStride<F> {
273        self
274    }
275}
276
277#[cfg(any(feature = "std", feature = "alloc"))]
278/// An image with a stride which can be moved into `Vec<u8>`.
279// TODO: any breaking release should add Clone as a supertrait
280pub trait OwnedImageStride<F>: AsImageStride<F> + ImageStride<F> + Into<Vec<u8>> {}
281#[cfg(any(feature = "std", feature = "alloc"))]
282impl<S, F> OwnedImageStride<F> for S
283where
284    S: AsImageStride<F> + ImageStride<F>,
285    Vec<u8>: From<S>,
286{
287}