#computer #vision #photogrammetry

no-std cam-geom

Geometric models of cameras for photogrammetry

8 unstable releases (3 breaking)

0.4.0 Oct 26, 2020
0.3.0 Oct 3, 2020
0.2.1 Mar 16, 2020
0.1.3 Feb 27, 2020

#2 in Robotics

Download history 7/week @ 2020-08-07 22/week @ 2020-08-14 4/week @ 2020-08-21 55/week @ 2020-08-28 47/week @ 2020-09-04 193/week @ 2020-09-11 204/week @ 2020-09-18 59/week @ 2020-09-25 427/week @ 2020-10-02 378/week @ 2020-10-09 152/week @ 2020-10-16 460/week @ 2020-10-23 235/week @ 2020-10-30 311/week @ 2020-11-06 241/week @ 2020-11-13 95/week @ 2020-11-20

607 downloads per month
Used in opencv-ros-camera

MIT/Apache

110KB
2K SLoC

Crate cam_geom for the Rust language

Crates.io Documentation Crate License Dependency status build

📷 📐 Geometric models of cameras for photogrammetry

pinhole model image

(3D model by Adan, CC by 4.0)

About

The crate implements geometric models of cameras which may be useful for photogrammetry.

The crate provides a couple camera models, the pinhole perspective camera and the orthographic camera. Adding another camera model entails implementing the IntrinsicParameters trait. See the opencv_ros_camera crate for one example.

Also provided is the function best_intersection_of_rays() which determines the best 3D point corresponding to the intersection of multiple rays. Thus, this crate is also useful for multiple view geometry.

Characteristics:

  • Extensive use of static typing to ensure no unpleasant runtime surprises with coordinate system, matrix dimensions, and so on.
  • Serialization and deserialization using serde. Enable with the serde-serialize cargo feature.
  • Linear algebra and types from the nalgebra crate.
  • Possible to create new camera models by implementing the IntrinsicParameters trait. While the camera models implemented in this crate are linear, there is no requirement that implementations are linear. For example, the opencv_ros_camera crate exhibits distortion.
  • ExtrinsicParameters based on the nalgebra::Isometry3 type to handle the camera pose.
  • No standard library is required (disable the default features to disable use of std) and no heap allocations. In other words, this can run on a bare-metal microcontroller with no OS.
  • Extensive documentation and tests.
  • Requires rust version 1.40 or greater.

Testing

Unit tests

To run the basic unit tests:

cargo test

To run all unit tests:

cargo test --features serde-serialize

Test for no_std

Since the thumbv7em-none-eabihf target does not have std available, we can build for it to check that our crate does not inadvertently pull in std. The unit tests require std, so cannot be run on a no_std platform. The following will fail if a std dependency is present:

# install target with: "rustup target add thumbv7em-none-eabihf"
cargo build --no-default-features --target thumbv7em-none-eabihf

Examples

Example - projecting 3D world coordinates to 2D pixel coordinates.

use cam_geom::*;
use nalgebra::{Matrix2x3, Unit, Vector3};

// Create two points in the world coordinate frame.
let world_coords = Points::new(Matrix2x3::new(
    1.0, 0.0, 0.0, // point 1
    0.0, 1.0, 0.0, // point 2
));

// perepective parameters - focal length of 100, no skew, pixel center at (640,480)
let intrinsics = IntrinsicParametersPerspective::from(PerspectiveParams {
    fx: 100.0,
    fy: 100.0,
    skew: 0.0,
    cx: 640.0,
    cy: 480.0,
});

// Set extrinsic parameters - camera at (10,0,0), looing at (0,0,0), up (0,0,1)
let camcenter = Vector3::new(10.0, 0.0, 0.0);
let lookat = Vector3::new(0.0, 0.0, 0.0);
let up = Unit::new_normalize(Vector3::new(0.0, 0.0, 1.0));
let pose = ExtrinsicParameters::from_view(&camcenter, &lookat, &up);

// Create a `Camera` with both intrinsic and extrinsic parameters.
let camera = Camera::new(intrinsics, pose);

// Project the original 3D coordinates to 2D pixel coordinates.
let pixel_coords = camera.world_to_pixel(&world_coords);

// Print the results.
for i in 0..world_coords.data.nrows() {
    let wc = world_coords.data.row(i);
    let pix = pixel_coords.data.row(i);
    println!("{} -> {}", wc, pix);
}

This will print:

  ┌       ┐
  │ 1 0 0 │
  └       ┘

 ->
  ┌         ┐
  │ 640 480 │
  └         ┘



  ┌       ┐
  │ 0 1 0 │
  └       ┘

 ->
  ┌         ┐
  │ 650 480 │
  └         ┘

Example - intersection of rays

use cam_geom::*;
use nalgebra::RowVector3;

// Create the first ray.
    let ray1 = Ray::<WorldFrame, _>::new(
    RowVector3::new(1.0, 0.0, 0.0), // origin
    RowVector3::new(0.0, 1.0, 0.0), // direction
);

// Create the second ray.
let ray2 = Ray::<WorldFrame, _>::new(
    RowVector3::new(0.0, 1.0, 0.0), // origin
    RowVector3::new(1.0, 0.0, 0.0), // direction
);

// Compute the best intersection.
let result = best_intersection_of_rays(&[ray1, ray2]).unwrap();

// Print the result.
println!("result: {}", result.data);

This will print:

result:
  ┌       ┐
  │ 1 1 0 │
  └       ┘

Altenatives

You may also be interested in rust-cv/cv-core, which also contains camera models for photogrammetry. The two crates were developed independently without knowledge of each other.

Regenerate README.md

The README.md file can be regenerated with:

cargo readme > README.md

Code of conduct

Anyone who interacts with this software in any space, including but not limited to this GitHub repository, must follow our code of conduct.

License

Licensed under either of these:

Dependencies

~3.5MB
~76K SLoC