Rust OpenCV bindings

Github Actions Documentation Package

Experimental Rust bindings for OpenCV 3 and 4.

The API is usable, but unstable and not very battle-tested; use at your own risk.

Changelog

Quickstart

Make sure the supported OpenCV version (3.4 or 4.x) and Clang (part of LLVM, needed for automatic binding generation) are installed in your system.

Update your Cargo.toml toml opencv = "0.76.3"

Import prelude rust use opencv::prelude::*;

Getting OpenCV

Linux

Arch Linux:

OpenCV package in Arch is suitable for this:

pacman -S clang qt5-base opencv

and additionally to support more OpenCV modules:

pacman -S vtk glew fmt openmpi

Ubuntu:

apt install libopencv-dev clang libclang-dev

Other Linux:

You have several options of getting the OpenCV library:

Additionally, please make sure to install clang package or its derivative that contains libclang.so and clang binary. * Gentoo, Fedora: clang * Debian, Ubuntu: clang and libclang-dev

Windows package

Installing OpenCV is easy through the following sources:

macOS package

Get OpenCV from homebrew:

Manual build

You can of course always compile OpenCV of the version you prefer manually. This is also supported, but it requires some additional configuration.

You need to set up the following environment variables to point to the installed files of your OpenCV build: OPENCV_LINK_LIBS, OPENCV_LINK_PATHS and OPENCV_INCLUDE_PATHS (see below for details).

Static build

Static linking to OpenCV is supported and tested at least on Linux. For some hints on building OpenCV statically please check this comment. Also, some you can get information on how to perform the build in CI scripts: install-focal.sh and script.sh, search for non_static_version variable.

Troubleshooting

  1. One of the common problems is link errors in the end of the build.

    Be sure to set up the relevant environment variables that will allow the linker to find the libraries it needs (see below).

  2. You're getting runtime errors like: thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { code: -215, message: "OpenCV(4.2.0) /build/opencv/src/opencv-4.2.0/modules/highgui/src/window.cpp:384: error: (-215:Assertion failed) size.width>0 && size.height>0 in function \'imshow\'\n" }', src/libcore/result.rs:1188:5 thread 'extraction::tests::test_contour_matching' panicked at 'called `Result::unwrap()` on an `Err` value: Error { code: -215, message: "OpenCV(4.1.1) /tmp/opencv-20190908-41416-17rm3ol/opencv-4.1.1/modules/core/src/matrix_wrap.cpp:79: error: (-215:Assertion failed) 0 <= i && i < (int)vv.size() in function \'getMat_\'\n" }', src/libcore/result.rs:1165:5

    These errors (note the .cpp source file and Error return value) are coming from OpenCV itself, not from the crate. It means that you're using the OpenCV API incorrectly, e.g. passing incompatible or unexpected arguments. Please refer to the OpenCV documentation for details.

  3. You're getting errors that methods don't exist or not implemented for specific structs, but you can see them in the documentation and in the crate source.

    Be sure to import use opencv::prelude::*;. The crate contains a lot of traits that need to be imported first.

  4. On Windows, you're getting the (exit code: 0xc0000135, STATUS_DLL_NOT_FOUND) error when running the compiled binary.

    That often means that Windows can't find the OpenCV library dll. Be sure to set up PATH environment variable correctly or copy the dll next to the binary you're trying to run. Check that guide too.

  5. On Windows with VCPKG you're getting a lot of linking errors in multiple files like in this issue.

    Unless you're doing a very specific build, you want to have environment variable VCPKGRS_DYNAMIC set to "1".

  6. On Windows with OpenCV 4.6.0 you're getting linking errors related to img_hash module like in this issue.

    Be sure to add opencv_img_hash460 to your OPENCV_LINK_LIBS environment variable because it's being built as a separate file.

  7. On macOS you're getting the dyld: Library not loaded: @rpath/libclang.dylib error during the build process.

    OS can't find libclang.dylib dynamic library because it resides in a non-standard path, set up the DYLD_FALLBACK_LIBRARY_PATH environment variable to point to the path where libclang.dylib can be found, e.g. for Command Line Tools: export DYLD_FALLBACK_LIBRARY_PATH="$(xcode-select --print-path)/usr/lib/"

    or XCode: export DYLD_FALLBACK_LIBRARY_PATH="$(xcode-select --print-path)/Toolchains/XcodeDefault.xctoolchain/usr/lib/"

    You might be running into the issue on the recent macOS versions where this environment variable remains empty after setting, please check this issue for some workarounds.

  8. You're getting the panic: a `libclang` shared library is not loaded on this thread.

    Enable the clang-runtime feature or use crate version 0.66 and newer. The reason for the issue is that some crates (like bindgen) depend on clang-sys with hard-enabled runtime feature and because of that cargo makes this feature also enabled for every other crate that depends on clang-sys (opencv in this case). During binding generation phase opencv crate tries to use multiple threads and clang-sys with runtime feature enabled doesn't like that (hence the panic). Enabling clang-runtime feature switches to using multiple processes instead of multiple threads. This makes the build a bit longer because of the need to build the helper binary, but the end result is the same. Additionally since crate version 0.66 this behavior is now the default.

Reporting issues

If you still have trouble using the crate after going through the Troubleshooting steps please fill free to report it to the bugtracker.

When reporting an issue please state: 1. Operating system 2. The way you installed OpenCV: package, official binary distribution, manual compilation, etc. 3. OpenCV version 4. Attach the full output of the following command from your project directory: shell script RUST_BACKTRACE=full cargo build -vv

Environment variables

The following variables must be set when building without pkg_config, cmake or vcpkg. You can set them on any platform, the specified values will override those automatically discovered.

The following variables are rarely used, but you might need them under some circumstances:

The following variables affect the building the of the opencv crate, but belong to external components:

Cargo features

API details

API Documentation is automatically translated from OpenCV's doxygen docs. Most likely you'll still want to refer to the official OpenCV C++ documentation as well.

OpenCV version support

The following OpenCV versions are supported at the moment: * 3.4 * 4.x

Minimum rustc version (MSRV)

Currently, version 1.59.0 is required.

Platform support

Currently, the main development and testing of the crate is performed on Linux, but other major platforms are also supported: macOS and Windows.

For some more details please refer to the CI build scripts: Linux OpenCV install, macOS OpenCV install as framework, macOS OpenCV install via brew, Windows OpenCV install via Chocolatey, Windows OpenCV install via vcpkg, Test runner script.

Functionality

Generally the crate tries to only wrap OpenCV API and provide some convenience functions to be able to use it in Rust easier. We try to avoid adding any functionality besides that.

Errors

Most functions return a Result to expose a potential C++ exception. Although some methods like property reads or functions that are marked CV_NOEXCEPT in the OpenCV headers are infallible and return a naked value.

Properties

Properties of OpenCV classes are accessible through setters and getters. Those functions are infallible, they return the value directly instead of Result.

C++ operators

Some C++ operators are supported, they are converted to the corresponding functions on Rust side. Here is the list with the corresponding function name: * []get() or get_mut() * +, -add(), sub() * *, /mul(), div() * () (function call) → apply() * * (deref) → try_deref() or try_deref_mut() * ==, !=equals(), not_equals() * >, >=greater_than(), greater_than_or_equal() * <, <=less_than(), less_than_or_equal() * ++, --incr(), decr() * &, |, ^and(), or(), xor() * !negate()

Infallible functions

For infallible functions (like setters) that accept &str values the following logic applies: if a Rust string passed as argument contains null byte then this string will be truncated up to that null byte. So if for example you pass "123\0456" to the setter, the property will be set to "123".

Callbacks

Some API functions accept callbacks, e.g. set_mouse_callback. While currently it's possible to successfully use those functions there are some limitations to keep in mind. Current implementation of callback handling leaks the passed callback argument. That means that the closure used as a callback will never be freed during the lifetime of a program and moreover Drop will not be called for it. There is a plan to implement possibility to be able to free at least some of the closures.

Unsafety

Although the crate tries to provide an ergonomic Rust interface for OpenCV, don't expect Rust safety guarantees at this stage. It's especially true for the borrow-checking and the shared mutable ownership. Notable example would be Mat which is a reference counted object in its essence. You can own a seemingly separate Mat in Rust terms, but it's going to be a mutable reference to the other Mat under the hood. Treat safety of the crate's API as you would treat one of C++, use clone() when needed.

Contrib modules

To be able to use some modules you need to have opencv_contrib installed. You can find the full list of contrib modules here.

Missing modules and functions

While most of the API is covered, for various reasons (that might no longer hold) there are modules and functions that are not yet implemented. If a missing module/function is near and dear to you, please file an issue (or better, open a pull request!).

The binding strategy

This crate works similar to the model of python and java's OpenCV wrappers - it uses libclang to parse the OpenCV C++ headers, generates a C interface to the C++ API, and wraps the C interface in Rust.

All the major modules in the C++ API are merged together in a huge cv:: namespace. We instead made one rust module for each major OpenCV module. So, for example, C++ cv::Mat is opencv::core::Mat in this crate.

The methods and field names have been snake_cased. Methods arguments with default value lose these default values, but they are reported in the API documentation.

Overloaded methods have been mostly manually given different names or automatically renamed to *1, *2, etc.

Older OpenCV branches support

OpenCV 2

If you can't use OpenCV 3.x or higher, the (no longer maintained) 0.2.4 version of this crate is known to work with OpenCV 2.4.7.13 (and probably other 2.4 versions). Please refer to the README.md file for that version because the crate has gone through the considerable rewrite since.

OpenCV 3.2

The last version with confirmed OpenCV 3.2 support is 0.75.0, after that this branch of OpenCV is no longer tested and supported. It may still work though.

Contributor's Guide

The binding generator code lives in a separate crate under binding-generator. During the build phase it creates bindings from the header files and puts them into bindings directory. Those are then transferred to src for the consumption by the crate users.

The crate itself, as imported by users, consists of generated rust code in src committed to the repo. This way, users don't have to handle the code generation overhead in their builds. When developing this crate, you can test changes to the binding generation using cargo build -vv. When changing the binding-generator, be sure to push changes to the generated code!

If you're looking for things to improve be sure to search for todo and fixme labels in the project source, those usually carry the comment of what exactly needs to be fixed.

The license for the original work is MIT.

Special thanks to ttacon for yielding the crate name.