Skip to content

Header-only library to make available to Python those functions and methods written in C++ whose input/output is an OpenCv matrix.

License

Notifications You must be signed in to change notification settings

luiscarlosgph/ndarray-opencv-converter

Repository files navigation

Build Status

ndarray-opencv-converter

If you have a C++ computer vision pipeline that uses OpenCV and you want to expose it to Python, this header-only library will make your code work seamlessly in C++ and Python.

Dependencies

  • Python >= 3.8.2

  • OpenCV >= 4.0 (last tested to be working 4.5.1). Skip this step if you have OpenCV already installed in your system. Otherwise, you can install it running:

    # Ubuntu/Debian
    $ sudo apt update
    $ sudo apt install libopencv-dev python3-opencv
    
  • Numpy >= 1.20.0. Skip this step if you have Numpy already installed in your system. Otherwise, you can install it running:

    # Ubuntu/Debian
    $ sudo apt update
    $ sudo apt install python3-pip
    $ python3 -m pip install numpy --user
    
  • libboost_python >= 1.70.0 (last tested to be working 1.75.0)

    $ wget https://dl.bintray.com/boostorg/release/1.75.0/source/boost_1_75_0.tar.gz
    $ tar xf boost_1_75_0.tar.gz
    $ cd boost_1_75_0/
    $ ./bootstrap.sh --with-python=/usr/bin/python3
    $ ./b2 --with-python link=static cxxflags="-std=c++11 -fPIC" variant=release stage
    $ sudo ./b2 --with-python link=static cxxflags="-std=c++11 -fPIC" variant=release install
    

Usage

Let's assume you have a library called superlibrary, with header superlibrary.h and implementation superlibrary.cpp (which should contain your Python wrapper). For example:

superlibrary.h

#ifndef SUPERLIBRARY_H
#define SUPERLIBRARY_H

#include <opencv2/imgproc/imgproc.hpp>

// TODO: Define your classes/functions here

// Exemplary function that we want to use from C++ but also expose to Python
cv::Mat coolFunction(const cv::Mat &im);

// Exemplary class that we want to use in C++ but also expose to Python
class CoolClass {
  public:
    cv::Mat toGray(const cv::Mat &im);
};

#endif

superlibrary.cpp

#include <boost/python.hpp>
#include "superlibrary.h"
#include "ndcv.h" // NOTE: Header-only library that does the conversion magic, you need to keep it!

// TODO: Implement your library here

// Exemplary function that we want to use from C++ but also expose to Python
cv::Mat coolFunction(const cv::Mat &im) {
  cv::Mat smoothIm;
  cv::GaussianBlur(im, smoothIm, cv::Size(15, 15), 0, 0);
  return smoothIm;
}

// Exemplary class that we want to use in C++ but also expose to Python
cv::Mat CoolClass::toGray(const cv::Mat &im) {
  cv::Mat greyIm;
  cv::cvtColor(im, greyIm, cv::COLOR_BGR2GRAY);
 return greyIm;
}

// NOTE: conversion magic, you need to keep it!
static void *init_ar() {
  Py_Initialize();
  import_array();
  return NULL;
}

// NOTE: you should change the name of the library from 'superlibrary' to something more
//       appropriate, but, you must call the output library file with the same name.
//       That is, in your CMakeLists.txt:
//
//       add_library(superlibrary SHARED superlibrary.cpp)
//                        /\
//                        || These two must be equal!
//                        \/
BOOST_PYTHON_MODULE(superlibrary) {
  // NOTE: conversion magic, you need to keep it!
  init_ar();
  boost::python::to_python_converter<cv::Mat, matToNDArrayBoostConverter>();
  matFromNDArrayBoostConverter();

  // TODO: Expose your functions and classes to Python here
  
  // Example 1: this is how you expose a function
  boost::python::def("cool_function", coolFunction);
  
  // Example 2: this is how you expose a class and its methods
  boost::python::class_<CoolClass>("CoolClass", boost::python::init<>())
    .def("to_gray", &CoolClass::toGray);
}

In the example above, the conversion between an ndarray (what Python passes) and cv::Mat (what your library expects) is performed transparently, and the code just works.

Exemplary programs in C++ and Python that use the same .so library (superlibrary.so, whose code is shown above) here:

#include <opencv2/imgcodecs.hpp>
#include "superlibrary.h"

int main(int argc, char **argv) {
  // Read demo image
  cv::Mat im = cv::imread("demo_image.png"); 
  
  // Use C++ coolFunction()
  cv::Mat blur = coolFunction(im);
  
  // Use C++ CoolClass::toGray()
  CoolClass cc;
  cv::Mat gray = cc.toGray(im);
  
  // Write output images
  cv::imwrite("blur.png", blur);
  cv::imwrite("gray.png", gray);
}
import cv2
import superlibrary

# Read demo image
im = cv2.imread('demo_image.png')

# Use C++ coolFunction()
blur = superlibrary.cool_function(im)

# Use C++ CoolClass::toGray()
cc = superlibrary.CoolClass()
gray = cc.to_gray(im)

# Write output images
cv2.imwrite('blur.png', blur)
cv2.imwrite('gray.png', gray)

How to test this repo

$ git clone https://github.com/luiscarlosgph/ndarray-opencv-converter.git
$ cd ndarray-opencv-converter
$ mkdir build
$ cd build
$ cmake ..
$ make
$ sudo make install
$ cd ..

# To test the C++ program that uses the library (exemplary_program.cpp)
$ build/exemplary_program

# To test the Python script that uses the library (exemplary_program.py)
$ python3 exemplary_program.py

Credits

The code in this repo is based on numpy-boost-python-opencv and pyboostcvconverter.

License

This project is distributed under an MIT license.

About

Header-only library to make available to Python those functions and methods written in C++ whose input/output is an OpenCv matrix.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published