tpt-cv-core 0.1.0

Zero-copy image buffers, color spaces, and pixel math (no_std)
Documentation
  • Coverage
  • 100%
    121 out of 121 items documented1 out of 110 items with examples
  • Size
  • Source code size: 77.5 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 2.4 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 4s Average build duration of successful builds.
  • all releases: 4s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • tpt-solutions/tpt-cv
    1 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • PhillipC05

tpt-cv-core

Zero-copy image buffers, color spaces, and pixel math for the tpt-cv computer-vision framework.

100% pure Rust, no_std-capable, zero FFI, permissively licensed (MIT or Apache-2.0). This is the foundation every other tpt-cv crate builds on.

Why

no_std support is not an afterthought: the core math has no alloc dependency on the no_std path. Allocating types (owned images, vectors) are gated behind the alloc/std features, so the same code runs on a bare-metal microcontroller and in a web browser.

All sample buffers are plain, contiguous, cache-friendly slices. Pipeline operations take caller-provided destination buffers, so a frame-processing graph never allocates per frame. Row-pitch (stride) support enables sub-image views and ROI processing without copying.

Features

Feature Default Description
std yes Enable std-only helpers (e.g. file-backed buffers).
alloc yes Enable owned buffers (ImageBuf) and allocation-based utilities.
portable-simd no Nightly-only SIMD fast path. A scalar fallback is always present.

Build with no_std:

cargo build -p tpt-cv-core --no-default-features

Build for a thumb (bare-metal) target:

cargo build -p tpt-cv-core --no-default-features --target thumbv7em-none-eabihf

Quick start

use tpt_cv_core::image::{Image, ImageBuf};
use tpt_cv_core::pixel::Pixel;

// Borrow an existing byte slice as a 2×1 RGB image.
let data = [10u8, 20, 30, 40, 50, 60];
let img = Image::<_, 3>::new(&data, 2, 1).unwrap();
assert_eq!(img.pixel(1, 0).channels, [40, 50, 60]);

// Owned, heap-allocated image (requires `alloc`).
let mut buf = ImageBuf::<u8, 1>::new(4, 4);
buf.as_image_mut().set_pixel(2, 2, Pixel::new([255]));
assert_eq!(buf.as_image().pixel(2, 2).scalar(), 255);

What's inside

image — zero-copy image buffers

  • Image<'a, T, C> — immutable borrowed view over a &[T] with row-stride support. sub_image / row / iter are all zero-copy.
  • ImageMut<'a, T, C> — mutable borrowed view; writes into the caller's buffer.
  • ImageBuf<T, C> (alloc) — owned, heap-allocated image that can be created once and reused across frames.
  • Iterators: iter (pixels), iter_rows / rows (pixel rows), sub_image for ROIs.

pixel — the Sample trait and Pixel<T, C>

Sample is implemented for u8, u16, and f32, providing saturating / wrapping arithmetic, normalized [0,1] conversions, and per-channel math. The same generic code works across all three sample types.

color — color-space conversions

RGB↔BGR, RGB↔grayscale, RGB↔HSV, and RGB↔YUV (full-range BT.601). Same-channel conversions run in place; channel-count changes write into a caller-provided destination. All math is done in normalized [0,1] space internally, so u8, u16, and f32 use the same matrices.

use tpt_cv_core::color;
use tpt_cv_core::image::{ImageBuf, ImageMut};

let mut buf = ImageBuf::<u8, 3>::new(1, 1);
buf.as_image_mut().set_pixel(0, 0, tpt_cv_core::pixel::Pixel::new([255, 0, 0]));
color::rgb_to_gray(&buf.as_image(), &mut ImageBuf::<u8, 1>::new(1, 1).as_image_mut());

ops — pixel-wise arithmetic

add_sat / sub_sat / mul_sat, add_wrap / sub_wrap / mul_wrap, scale_sat / scale_wrap, blend (alpha mix), clamp, and absdiff. All write into a caller-provided destination and return false on size mismatch.

use tpt_cv_core::image::ImageBuf;
use tpt_cv_core::ops;

let a = ImageBuf::<u8, 1>::with_value(2, 1, 250);
let b = ImageBuf::<u8, 1>::with_value(2, 1, 10);
let mut dst = ImageBuf::<u8, 1>::new(2, 1);
assert!(ops::add_sat(&a.as_image(), &b.as_image(), &mut dst.as_image_mut()));
assert_eq!(dst.as_image().pixel(0, 0).scalar(), 255); // saturating, not 260

no_std / WASM / embedded

The crate builds with --no-default-features for no_std targets, and the full workspace compiles to wasm32-unknown-unknown. The portable-simd feature requires nightly but degrades to the scalar path on stable.

License

Dual-licensed under MIT OR Apache-2.0. Copyright (c) 2026 TPT Solutions. See LICENSE-MIT and LICENSE-APACHE.