Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
run: cargo test --workspace --features ndarray

no-std-build:
name: no_std Build (core + imgproc, issues #83/#84)
name: no_std Build (core + imgproc + calib3d + video, issues #83/#84/#85)
runs-on: ubuntu-latest

steps:
Expand Down
25 changes: 22 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,31 @@ purecv = "0.5"

| Flag | Default | Description |
|------|---------|-------------|
| `std` | ✅ | Standard library support |
| `parallel` | ✅ | Multi-core parallelism via **Rayon** |
| `std` | ✅ | Standard library support (disable for `no_std` — see below) |
| `parallel` | ✅ | Multi-core parallelism via **Rayon** (implies `std`) |
| `ndarray` | ❌ | Interop with the `ndarray` crate (zero-cost views & ownership transfers) |
| `simd` | ❌ | SIMD acceleration via [`pulp`](https://crates.io/crates/pulp) (x86 SSE/AVX, ARM NEON, WASM `simd128`) |
| `simd` | ❌ | SIMD acceleration via [`pulp`](https://crates.io/crates/pulp) (x86 SSE/AVX, ARM NEON, WASM `simd128`) — implies `std` |
| `wasm` | ❌ | WebAssembly-specific optimizations |

### `no_std` / embedded support

Build with `--no-default-features` to run on bare-metal targets such as the
ESP32 (`purecv = { version = "0.6", default-features = false }`). Only `core`
and `alloc` are required (an allocator must be provided by the target).

| Module | `no_std` | Notes |
|--------|----------|-------|
| `core` | ✅ | Full support. `get_tick_count`/`get_tick_frequency` and the thread-local RNG (`randu`/`randn`/`rand_shuffle`) require `std`. |
| `imgproc` | ✅ | Scalar fallbacks. `hough_lines_p` requires `std` (uses the thread-local RNG); `hough_lines` works without. |
| `calib3d` | ✅ | Full support (RANSAC uses a self-contained PRNG). |
| `video` | ✅ | Full support. Optical-flow pyramids are heap-heavy — size images for your device's RAM. |
| `features2d` | ❌ | Requires `std` for now. |

`parallel`, `simd`, `fft`, and `ndarray` require `std`; disabling default
features gives the scalar, single-threaded code paths. See
[`webarkit/purecv-esp32-examples`](https://github.com/webarkit/purecv-esp32-examples)
for runnable ESP32-S3 demos.

To enable the `ndarray` feature:

```toml
Expand Down
24 changes: 24 additions & 0 deletions crates/no-std-smoke/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@
extern crate alloc;

use alloc::vec;
use purecv::calib3d::rodrigues;
use purecv::core::error::Result;
use purecv::core::types::{BorderTypes, Size2i};
use purecv::core::{add, determinant, mean, Matrix};
use purecv::imgproc::gaussian_blur;
use purecv::video::build_optical_flow_pyramid;

/// Exercises matrix construction, arithmetic, statistics, and linear algebra.
pub fn smoke() -> Result<f64> {
Expand Down Expand Up @@ -83,3 +85,25 @@ pub fn smoke_imgproc() -> Result<f32> {
)?;
Ok(blurred.data[4])
}

/// Exercises the Phase 3 calib3d path: `rodrigues` (rotation vector -> matrix).
pub fn smoke_calib3d() -> Result<f64> {
let rvec = Matrix::<f64>::from_vec(3, 1, 1, vec![0.1, 0.2, 0.3]);
let mut rmat = Matrix::<f64>::new(3, 3, 1);
rodrigues(&rvec, &mut rmat)?;
Ok(rmat.data[0])
}

/// Exercises the Phase 3 video path: build a Lucas-Kanade optical-flow pyramid.
pub fn smoke_video() -> Result<usize> {
let img = Matrix::<u8>::from_vec(8, 8, 1, vec![0u8; 64]);
let pyr = build_optical_flow_pyramid(
&img,
Size2i::new(3, 3),
1,
false,
BorderTypes::Reflect101,
BorderTypes::Reflect101,
)?;
Ok(pyr.levels.len())
}
4 changes: 4 additions & 0 deletions src/calib3d/fundamental.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
*
*/

use alloc::{string::ToString, vec, vec::Vec};
#[allow(unused_imports)]
use num_traits::Float;

use super::linalg::{mat3_mul, null_space_vector, svd_3x3, Lcg};
use crate::core::error::{PureCvError, Result};
use crate::core::types::Point2f;
Expand Down
6 changes: 5 additions & 1 deletion src/calib3d/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
//! Converts between a *rotation vector* (compact axis-angle representation,
//! sometimes called an *Rodrigues vector*) and a 3×3 *rotation matrix*.

use alloc::{string::ToString, vec};
#[allow(unused_imports)]
use num_traits::Float;

use crate::core::error::{PureCvError, Result};
use crate::core::Matrix;

Expand Down Expand Up @@ -166,7 +170,7 @@ pub(super) fn rmat_to_rvec(m: &[f64; 9]) -> [f64; 3] {
}

// Near π the formula becomes numerically unstable; use an alternative.
if (theta - std::f64::consts::PI).abs() < 1e-4 {
if (theta - core::f64::consts::PI).abs() < 1e-4 {
return rmat_to_rvec_near_pi(m, theta);
}

Expand Down
6 changes: 5 additions & 1 deletion src/calib3d/homography.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
//! point normalization, plus an optional RANSAC wrapper for robustness
//! against outliers.

use alloc::{format, string::ToString, vec, vec::Vec};
#[allow(unused_imports)]
use num_traits::Float;

use crate::core::error::{PureCvError, Result};
use crate::core::types::Point2f;
use crate::core::Matrix;
Expand Down Expand Up @@ -359,7 +363,7 @@ fn normalize_points(pts: &[Point2f]) -> (Vec<f64>, [f64; 9]) {
let s = if mean_dist < 1e-12 {
1.0
} else {
std::f64::consts::SQRT_2 / mean_dist
core::f64::consts::SQRT_2 / mean_dist
};

let mut out = vec![0.0f64; pts.len() * 2];
Expand Down
8 changes: 6 additions & 2 deletions src/calib3d/linalg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
//!
//! All functions operate on flat, row-major `f64` slices/arrays.

use alloc::{vec, vec::Vec};
#[allow(unused_imports)]
use num_traits::Float;

// ---------------------------------------------------------------------------
// Matrix utilities
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -204,7 +208,7 @@ pub(super) fn null_space_vector(a: &[f64], rows: usize, cols: usize) -> Vec<f64>
.min_by(|&i, &j| {
ata[i * cols + i]
.partial_cmp(&ata[j * cols + j])
.unwrap_or(std::cmp::Ordering::Equal)
.unwrap_or(core::cmp::Ordering::Equal)
})
.unwrap_or(cols - 1);

Expand Down Expand Up @@ -241,7 +245,7 @@ pub(super) fn svd_3x3(a: &[f64; 9]) -> ([f64; 9], [f64; 3], [f64; 9]) {
idx.sort_by(|&i, &j| {
ata[j * 3 + j]
.partial_cmp(&ata[i * 3 + i])
.unwrap_or(std::cmp::Ordering::Equal)
.unwrap_or(core::cmp::Ordering::Equal)
});

// Reorder V columns (right singular vectors).
Expand Down
4 changes: 4 additions & 0 deletions src/calib3d/pose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
//! camera intrinsic matrix, these functions estimate the object pose
//! (rotation and translation vectors) in the camera coordinate system.

use alloc::{format, string::ToString, vec, vec::Vec};
#[allow(unused_imports)]
use num_traits::Float;

use crate::core::error::{PureCvError, Result};
use crate::core::logging::tags;
use crate::core::types::{Point2f, Point3f};
Expand Down
4 changes: 4 additions & 0 deletions src/calib3d/undistort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
*
*/

use alloc::string::ToString;
#[allow(unused_imports)]
use num_traits::Float;

use crate::core::error::{PureCvError, Result};
use crate::core::types::Size2i;
use crate::core::Matrix;
Expand Down
8 changes: 2 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,8 @@ pub use alloc::format as __format;

// Global modules
//
// `core`, `imgproc`, and `version` build without `std`; the remaining modules
// are gated until their own no_std phases land (see issue #82).
#[cfg(feature = "std")]
// `core`, `imgproc`, `calib3d`, `video`, and `version` build without `std`; the
// `features`/`features2d` modules remain std-gated (see issue #82).
pub mod calib3d;
pub mod core;
#[cfg(feature = "std")]
Expand All @@ -58,12 +57,10 @@ pub mod features;
pub mod features2d;
pub mod imgproc;
pub mod version;
#[cfg(feature = "std")]
pub mod video;

/// Prelude to easily import common structures
pub mod prelude {
#[cfg(feature = "std")]
pub use crate::calib3d::{
find_fundamental_mat, find_homography, init_undistort_rectify_map, rodrigues, solve_pnp,
solve_pnp_ransac, FundamentalMatMethod, HomographyMethod, SolvePnPMethod,
Expand Down Expand Up @@ -91,7 +88,6 @@ pub mod prelude {
pub use crate::imgproc::{
cvt_color, remap, warp_perspective, ColorConversionCode, InterpolationFlags,
};
#[cfg(feature = "std")]
pub use crate::video::optical_flow::{
build_optical_flow_pyramid, calc_optical_flow_pyramid_lk, OpticalFlowPyramid,
OPTFLOW_LK_GET_MIN_EIGENVALS, OPTFLOW_USE_INITIAL_FLOW,
Expand Down
7 changes: 7 additions & 0 deletions src/video/optical_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@
//! | `calcOpticalFlowPyrLK` `nextPts` is `InputOutputArray` | initial guess passed via `initial_next_pts: Option<&[Point2f]>` |
//! | `tryReuseInputImage` optimisation flag | not implemented (correctness only) |

use alloc::{string::ToString, vec::Vec};
// `vec!` is only used by the SIMD-only windowed kernel below.
#[cfg(feature = "simd")]
use alloc::vec;
#[allow(unused_imports)]
use num_traits::Float;

use crate::core::error::{PureCvError, Result};
use crate::core::logging::tags;
use crate::core::types::{BorderTypes, Point2f, Size2i, TermCriteria, TermType};
Expand Down
3 changes: 3 additions & 0 deletions src/video/simd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@
//! kernels operate *after* the gather, on the pre-collected contiguous `f32`
//! buffers, where auto-vectorisation applies cleanly.

#[allow(unused_imports)]
use num_traits::Float;

// ---------------------------------------------------------------------------
// H matrix accumulation
// ---------------------------------------------------------------------------
Expand Down