Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
688c849
bump version 0.6.1
kalwalt Jul 8, 2026
1333d4d
Merge branch 'main' into dev
kalwalt Jul 8, 2026
954fa05
chore(core): make std an explicit opt-in feature, set MSRV 1.88
kalwalt Jul 13, 2026
b264b56
feat(core): compile the core module without the standard library
kalwalt Jul 13, 2026
08ad7bc
test(core): add build-only no_std smoke-test crate
kalwalt Jul 13, 2026
db2f7cc
chore(ci): add no_std build job
kalwalt Jul 13, 2026
9399197
fix(wasm): re-enable purecv std feature for the wasm crate
kalwalt Jul 13, 2026
d543f96
feat(core): add OpenCV-style logging facade (#80)
kalwalt Jul 16, 2026
f36ed7a
feat(core): add basic logger and migrate example applications to logg…
kalwalt Jul 18, 2026
87b2f53
chore(core): fix formatting in logging.rs (#80)
kalwalt Jul 18, 2026
eb3717a
feat(video): add debug logging inside calc_optical_flow_pyramid_lk (#80)
kalwalt Jul 18, 2026
550595a
feat(core): add warning logs for solve and solve_pnp_ransac failure c…
kalwalt Jul 18, 2026
f22c5d4
feat(core): add cv_bail!/cv_err! log-and-return macros (#80)
kalwalt Jul 19, 2026
7274010
feat(core): log input-validation failures in arithm and matrix (#80)
kalwalt Jul 21, 2026
39a1f47
doc(core): add module-level docs for core, imgproc and features (#80)
kalwalt Jul 21, 2026
86f197e
feat(core): log input-validation failures across remaining core modul…
kalwalt Jul 21, 2026
6ff5823
doc(core): document the logging facility in the README (#80)
kalwalt Jul 23, 2026
919d574
refactor(core): gate the stdout logger behind the std feature (#80)
kalwalt Jul 23, 2026
7746643
Merge remote-tracking branch 'origin/dev' into feat/no-std-core-phase1
kalwalt Jul 23, 2026
db5a6ca
Merge pull request #86 from webarkit/feat/no-std-core-phase1
kalwalt Aug 3, 2026
b274af3
feat(imgproc): compile the imgproc module without the standard library
kalwalt Aug 3, 2026
0e9f6bd
refactor(imgproc): use core::/alloc:: paths for no_std
kalwalt Aug 3, 2026
fba86eb
test(imgproc): exercise gaussian_blur from the no_std smoke crate
kalwalt Aug 3, 2026
d110e51
feat(video,calib3d): compile both modules without the standard library
kalwalt Aug 5, 2026
33ff7b0
refactor(video,calib3d): use core::/alloc:: paths for no_std
kalwalt Aug 5, 2026
bc01bec
test(video,calib3d): smoke-test both modules + document no_std support
kalwalt Aug 5, 2026
ae5dc35
doc: document no_std/embedded support and refresh the README
kalwalt Aug 5, 2026
e6883ef
Merge pull request #90 from webarkit/feat/no_std
kalwalt Aug 7, 2026
52dc212
chore(release): prepare for v0.7.0
kalwalt Aug 7, 2026
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
28 changes: 28 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,34 @@ jobs:
- name: Run tests (with ndarray feature)
run: cargo test --workspace --features ndarray

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

steps:
- uses: actions/checkout@v6

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: clippy
targets: thumbv7em-none-eabihf

- name: Rust Cache
uses: Swatinem/rust-cache@v2

- name: Build without default features (host)
run: cargo build --no-default-features

- name: Lint without default features
run: cargo clippy --no-default-features -- -D warnings

- name: Build for bare-metal target
run: cargo build --no-default-features --target thumbv7em-none-eabihf

- name: Build no_std smoke-test consumer
run: cargo build --manifest-path crates/no-std-smoke/Cargo.toml --target thumbv7em-none-eabihf

wasm-build:
name: WASM Dual Build
runs-on: ubuntu-latest
Expand Down
43 changes: 43 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,49 @@

All notable changes to this project will be documented in this file.

## [0.7.0] - 2026-08-07

### ⚙️ Miscellaneous Tasks

- *(core)* Make std an explicit opt-in feature, set MSRV 1.88
- *(ci)* Add no_std build job
- *(core)* Fix formatting in logging.rs (#80)

### 🐛 Bug Fixes

- *(wasm)* Re-enable purecv std feature for the wasm crate

### 📚 Documentation

- Document no_std/embedded support and refresh the README
- *(core)* Document the logging facility in the README (#80)
- *(core)* Add module-level docs for core, imgproc and features (#80)

### 🚀 Features

- *(core)* Compile the core module without the standard library
- *(imgproc)* Compile the imgproc module without the standard library
- *(video,calib3d)* Compile both modules without the standard library
- *(core)* Add OpenCV-style logging facade (#80)
- *(core)* Add basic logger and migrate example applications to logging macros (#80)
- *(core)* Add cv_bail!/cv_err! log-and-return macros (#80)
- *(core)* Add warning logs for solve and solve_pnp_ransac failure cases (#80)
- *(core)* Log input-validation failures in arithm and matrix (#80)
- *(core)* Log input-validation failures across remaining core modules (#80)
- *(video)* Add debug logging inside calc_optical_flow_pyramid_lk (#80)

### 🚜 Refactor

- *(core)* Gate the stdout logger behind the std feature (#80)
- *(imgproc)* Use core::/alloc:: paths for no_std
- *(video,calib3d)* Use core::/alloc:: paths for no_std

### 🧪 Testing

- *(core)* Add build-only no_std smoke-test crate
- *(imgproc)* Exercise gaussian_blur from the no_std smoke crate
- *(video,calib3d)* Smoke-test both modules + document no_std support

## [0.6.1] - 2026-07-08

### 🎨 Styling
Expand Down
23 changes: 14 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
[package]
name = "purecv"
version = "0.6.1"
version = "0.7.0"
authors = ["Walter Perdan <https://github.com/kalwalt>"]
edition = "2021"
rust-version = "1.88"
description = "A pure Rust, high-performance computer vision library focused on safety and portability."
license = "LGPL-2.1-or-later"
repository = "https://github.com/webarkit/purecv"
Expand All @@ -16,23 +17,24 @@ path = "src/lib.rs"
[dependencies]
rayon = { version = "1.10", optional = true }
ndarray = { version = "0.17", optional = true }
num-traits = "0.2"
num-traits = { version = "0.2", default-features = false, features = ["libm"] }
pulp = { version = "0.22", optional = true }
rustfft = { version = "6", optional = true }
num-complex = { version = "0.4", optional = true }
log = "0.4"
log = { version = "0.4", default-features = false }

[dev-dependencies]
image = "0.25"
criterion = "0.8"

[features]
default = ["std", "parallel"]
std = []
parallel = ["rayon"]
ndarray = ["dep:ndarray"]
simd = ["dep:pulp"]
fft = ["dep:rustfft", "dep:num-complex"]
std = ["num-traits/std"]
# The features below require `std` until their own no_std phases land (see issue #82).
parallel = ["dep:rayon", "std"]
ndarray = ["dep:ndarray", "std"]
simd = ["dep:pulp", "std"]
fft = ["dep:rustfft", "dep:num-complex", "std"]
transforms = ["fft"]

[[bench]]
Expand Down Expand Up @@ -79,9 +81,12 @@ panic = "abort"

[workspace]
members = ["crates/wasm"]
# Built separately against bare-metal targets (see the no-std CI job); keeping it
# out of the workspace lets `cargo build --workspace` stay host-only.
exclude = ["crates/no-std-smoke"]

[workspace.package]
version = "0.6.1"
version = "0.7.0"
authors = ["Walter Perdan <https://github.com/kalwalt>"]
edition = "2021"
description = "A pure Rust, high-performance computer vision library focused on safety and portability."
Expand Down
103 changes: 93 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
[![GitHub Stars](https://img.shields.io/github/stars/webarkit/purecv.svg?style=social)](https://github.com/webarkit/purecv/stargazers)
[![GitHub Forks](https://img.shields.io/github/forks/webarkit/purecv.svg?style=social)](https://github.com/webarkit/purecv/network/members)

A high-performance, **pure Rust** computer vision library focusing on the `core` and `imgproc` modules of OpenCV. **PureCV** is built from the ground up to be memory-safe, thread-safe, and highly portable without the overhead of C++ FFI.
A high-performance, **pure Rust** computer vision library reimplementing the `core`, `imgproc`, `features2d`, `video`, and `calib3d` modules of OpenCV. **PureCV** is built from the ground up to be memory-safe, thread-safe, and highly portable — from desktop and WebAssembly down to `no_std` microcontrollers — without the overhead of C++ FFI.

> This project is currently a **Work in Progress**. While most core and imgproc features have been implemented, the library is not yet stable, and bugs may occur. We are actively optimizing and expanding the feature set.
> This project is currently a **Work in Progress**. While most features across the core, imgproc, features2d, video, and calib3d modules have been implemented, the library is not yet stable, and bugs may occur. We are actively optimizing and expanding the feature set.

## 🎯 Philosophy

Expand All @@ -21,6 +21,7 @@ Unlike existing wrappers, **PureCV** is a native rewrite. It aims to provide:
* **Memory Safety:** Elimination of segmentation faults and buffer overflows via Rust's ownership model.
* **Modern Parallelism:** Native integration with **Rayon** for effortless multi-core processing.
* **Portable SIMD:** Optional SIMD acceleration via [`pulp`](https://crates.io/crates/pulp) — auto-detects x86 SSE/AVX, ARM NEON, and WASM `simd128` at runtime. Zero `unsafe`, zero `#[cfg(target_arch)]`.
* **Embedded-ready:** Builds under `no_std` + `alloc` for bare-metal targets such as the ESP32 — the `core`, `imgproc`, `calib3d`, and `video` modules run without the standard library ([see below](#no_std--embedded-support)).

## ✨ Features

Expand All @@ -42,7 +43,8 @@ Unlike existing wrappers, **PureCV** is a native rewrite. It aims to provide:
- **Random Number Generation:** `randu` (uniform distribution), `randn` (normal/Gaussian distribution), `set_rng_seed`.
- **Channel Management:** `split`, `merge`, `mix_channels`.
- **Utilities:** `add_weighted`, `check_range`, `absdiff`, `get_tick_count`, `get_tick_frequency`.
- **Mathematical Constants:** OpenCV-compatible constants — `CV_PI`, `CV_PI_2`, `CV_2PI`, `CV_PI_4`, `CV_LOG2`, `CV_LN2`, `CV_E`, `CV_LN10`, `CV_SQRT2` — backed by `std::f64::consts` for maximum precision.
- **Logging** (OpenCV-style): a `cv::utils::logging`-compatible facade over the [`log`](https://crates.io/crates/log) crate — a 7-level `LogLevel` with `set_log_level`/`get_log_level`, per-subsystem `tags`, `cv_log_*!` macros, and `cv_bail!`/`cv_err!` log-and-return helpers used throughout `core` to report invalid input (wrong dimensions, channel mismatches, …). Bring your own backend (`env_logger`, `tracing`, …) or call `init_basic_logger()` for quick stdout output.
- **Mathematical Constants:** OpenCV-compatible constants — `CV_PI`, `CV_PI_2`, `CV_2PI`, `CV_PI_4`, `CV_LOG2`, `CV_LN2`, `CV_E`, `CV_LN10`, `CV_SQRT2` — backed by `core::f64::consts` for maximum precision (available under `no_std`).
- **ndarray Interop:** Optional, zero-cost conversions to/from `ndarray::Array3` via the `ndarray` feature flag.
- **SIMD Acceleration** (`simd` feature): Trait-based dispatch via `pulp` for `f32`, `f64`, and `u8` types. Accelerated operations include `add`, `sub`, `mul`, `div`, `min`, `max`, `sqrt`, `dot`, `sum`, `add_weighted`, `convert_scale_abs`, `magnitude`, `simd_row_min_max`, `simd_min_max_col`, `simd_gaussian_5tap_h/v`, and `simd_remap_bilinear_row`/`simd_remap_nearest_row`. Falls back to scalar loops at zero cost when disabled.

Expand Down Expand Up @@ -83,31 +85,77 @@ Add the following to your `Cargo.toml`:

```toml
[dependencies]
purecv = "0.5"
purecv = "0.6"
```

PureCV's minimum supported Rust version (MSRV) is **1.88**.

### Feature Flags

| 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.

```toml
[dependencies]
purecv = { version = "0.6", default-features = false }
```

```rust
#![no_std]
extern crate alloc; // an allocator must be provided by your target

use alloc::vec;
use purecv::core::{add, Matrix};
use purecv::imgproc::gaussian_blur;
use purecv::core::types::{BorderTypes, Size2i};

// core arithmetic, no std
let a = Matrix::<f32>::from_vec(2, 2, 1, vec![1.0, 2.0, 3.0, 4.0]);
let b = Matrix::<f32>::from_vec(2, 2, 1, vec![5.0, 6.0, 7.0, 8.0]);
let sum = add(&a, &b)?;

// imgproc under no_std (scalar fallback)
let blurred = gaussian_blur(&sum, Size2i::new(3, 3), 0.0, 0.0, BorderTypes::Reflect101)?;
```

See [`webarkit/purecv-esp32-examples`](https://github.com/webarkit/purecv-esp32-examples)
for runnable ESP32-S3 demos (matrix arithmetic, Gaussian blur, and `solve_pnp`
camera pose estimation).

To enable the `ndarray` feature:

```toml
[dependencies]
purecv = { version = "0.5", features = ["ndarray"] }
purecv = { version = "0.6", features = ["ndarray"] }
```

To enable SIMD + Parallel for maximum performance:

```toml
[dependencies]
purecv = { version = "0.5", features = ["parallel", "simd"] }
purecv = { version = "0.6", features = ["parallel", "simd"] }
```

### Usage Example
Expand Down Expand Up @@ -162,6 +210,40 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
```

### Logging

PureCV mirrors OpenCV's `cv::utils::logging` on top of the [`log`](https://crates.io/crates/log)
facade, so the output backend stays your choice (`env_logger`, `tracing`,
`console_log` on WASM, …). For a quick start, `init_basic_logger()` installs a
simple stdout logger. Internally, `core` logs a warning whenever a function
rejects invalid input:

```rust
use purecv::core::arithm;
use purecv::core::logging::{self, LogLevel};
use purecv::core::Matrix;

fn main() {
// Install the built-in stdout logger and let warnings through.
logging::init_basic_logger().ok();
logging::set_log_level(LogLevel::Warning);

// Mismatched dimensions -> logs a warning AND returns Err(..)
let a = Matrix::<f32>::new(4, 4, 3);
let b = Matrix::<f32>::new(2, 2, 1);
let _ = arithm::add(&a, &b);
// [WARN] purecv::core - add: matrices must have the same dimensions (src1 4×4×3, src2 2×2×1)
}
```

You can also emit your own messages with the `cv_log_*!` macros and filter per
subsystem via the standard `RUST_LOG` syntax (e.g. `RUST_LOG=purecv::core=warn`):

```rust
use purecv::core::logging::tags;
purecv::cv_log_info!(tags::IMGPROC, "gaussian blur, ksize = {}", 5);
```

### ndarray Interoperability

With the `ndarray` feature enabled, you can convert between `Matrix<T>` and `ndarray::Array3<T>`:
Expand Down Expand Up @@ -261,7 +343,7 @@ cargo run --example rectification
## 🧪 Testing & Benchmarking

### Running Tests
PureCV uses a comprehensive suite of unit tests to ensure correctness and parity with OpenCV. The test suite currently includes **281 unit tests** (plus **31 doc-tests**) covering:
PureCV uses a comprehensive suite of unit tests to ensure correctness and parity with OpenCV. The test suite currently includes **308 unit tests** (plus **40 doc-tests**) covering:

- **Core module:** Matrix factories, scalar arithmetic variants, bitwise scalar ops, min/max, comparison ops (`compare`, `in_range`), reduction (`reduce`, `count_non_zero`), polar/cartesian conversions, linear algebra (`determinant`, `invert`, `solve`), channel ops (`extract_channel`, `insert_channel`), `DynamicMatrix`, transforms, sorting, clustering, and RNG.
- **Imgproc module:** Filters, derivatives, edge detection, color conversions (including gray-to-RGB/BGR/RGBA/BGRA), thresholding, morphology (`erode`, `dilate`), pyramids (`pyr_down`, `pyr_up`), and kernel helpers (`get_gaussian_kernel`, `get_sobel_kernels`).
Expand Down Expand Up @@ -315,6 +397,7 @@ RUSTFLAGS="-C target-cpu=native" cargo bench --features parallel
## 🗺 Roadmap

- [x] [**Milestone 7: Geometric Rectification & Calibration**](https://github.com/webarkit/purecv/milestone/7) - Expand purecv to support camera intrinsic correction and geometric transformation, essential for robust 3D pose estimation and AR surface tracking.
- [x] **Embedded / `no_std` support** - The `core`, `imgproc`, `calib3d`, and `video` modules compile without the standard library for microcontrollers such as the ESP32. See [`purecv-esp32-examples`](https://github.com/webarkit/purecv-esp32-examples).

## 📄 License

Expand Down
13 changes: 13 additions & 0 deletions crates/no-std-smoke/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "purecv-no-std-smoke"
version = "0.0.0"
edition = "2021"
publish = false
description = "Build-only smoke test: consumes the purecv public API from a no_std crate (see issue #83)."

[dependencies]
purecv = { path = "../..", default-features = false }

# Standalone workspace root: keeps this build-only crate out of both the
# purecv workspace and any enclosing one.
[workspace]
Loading