Standalone C++ Build — TF + OpenCV

This tutorial is about setting up your local Tensorflow and OpenCV standalone build for C++ implementation. This tutorial is tested with following versions, but should work for all version, except there are some drastic changes in the libraries. Please let me know your findings, if so happens.

  1. Ubuntu 16.4 LTS
  2. Tensorflow : v1.8.0
  3. OpenCV : 3.4.1
  4. Bazel : 0.10.0

Github Repo for, Tensorflow Lite Standalone C++ build for Linux and MacOS here.

1. Install Dependencies

sudo apt-get -y update && apt-get -y upgrade

Next, install some base dependencies and tools we’ll need.

For Bazel:

There are few options given on the bazel build page but, i prefer from the binary. Make sure you install the tensorflow compatible version, else it won’t build.

For Building tools:

sudo apt-get -y install pkg-config zlib1g-dev default-jdk autoconf automake libtool wget unzip build-essential checkinstall yasm gfortran cmake git libjpeg8-dev

For CentOS (ONLY):

yum install -y patch make cmake 

For OpenCV:

sudo apt-get -y install libavcodec-dev libavformat-dev libswscale-dev libdc1394-22-dev libxine2-dev libv4l-dev libatlas-base-dev                 libfaac-dev libmp3lame-dev libtheora-dev libvorbis-dev libxvidcore-dev libopencore-amrnb-dev libopencore-amrwb-dev x264 v4l-utils libsm6 libxext6

We will build OpenCV from source and hence the following step:

git clone https://github.com/opencv/opencv.gitcd opencvgit checkout 3.4.1cd ..mkdir buildcd buildcmake -D CMAKE_BUILD_TYPE=RELEASE -DBUILD_SHARED_LIBS=OFF -D BUILD_opencv_objdetect=OFF -D BUILD_opencv_video=OFF -D BUILD_opencv_videoio=OFF -D BUILD_opencv_features2d=OFF -D BUILD_opencv_flann=OFF -D BUILD_opencv_highgui=OFF -D BUILD_opencv_ml=OFF -D BUILD_opencv_photo=OFF -D BUILD_opencv_python=OFF -D BUILD_opencv_shape=OFF -D BUILD_opencv_stitching=OFF -D BUILD_opencv_superres=OFF -D BUILD_opencv_ts=OFF -D BUILD_opencv_videostab=OFF ..

As you saw, my cmake is building one a specific modules of OpenCV and not the complete build, feel free to change them as per your requirements.

Feel free to change the cmake options as per your requirements.

make -j $nproc
make install

For TensorFlow:

# For Python 2.7
sudo apt-get install python-pip python-numpy swig python-dev
sudo pip install wheel
# For Python 3.3+
sudo apt-get install python3-pip python3-numpy swig python3-dev
sudo pip3 install wheel

2. TensorFlow

We will build tensorflow from source and its dependencies like protobuf and eigen libraries. So let clone tensorflow:

First let’s configure the build:

git clone https://github.com/tensorflow/tensorflow.git cd tensorflowgit checkout v1.8.0./configureYou have bazel 0.5.1- installed.
Please specify the location of python. [Default is /usr/bin/python]: /usr/bin/python
Do you wish to build TensorFlow with MKL support? [y/N] N
No MKL support will be enabled for TensorFlow
Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -march=native]:
Do you wish to use jemalloc as the malloc implementation? [Y/n] Y
jemalloc enabled
Do you wish to build TensorFlow with Google Cloud Platform support? [y/N] N
No Google Cloud Platform support will be enabled for TensorFlow
Do you wish to build TensorFlow with Hadoop File System support? [y/N] N
No Hadoop File System support will be enabled for TensorFlow
Do you wish to build TensorFlow with the XLA just-in-time compiler (experimental)? [y/N] N
No XLA support will be enabled for TensorFlow
Do you wish to build TensorFlow with VERBS support? [y/N] N
No VERBS support will be enabled for TensorFlow
Do you wish to build TensorFlow with OpenCL support? [y/N] N
No OpenCL support will be enabled for TensorFlow
Do you wish to build TensorFlow with CUDA support? [y/N] N
No CUDA support will be enabled for TensorFlow
Do you wish to build TensorFlow with MPI support? [y/N] N
MPI support will not be enabled for TensorFlow
Configuration finished

Note: make sure you specify correct python path on your system.

For ProtoBuf:

mkdir /tmp/protobuf
tensorflow/contrib/makefile/download_dependencies.sh
cd tensorflow/contrib/makefile/downloads/protobuf/
./autogen.sh
./configure --prefix=/tmp/protobuf/
make
make install

For Eigen:

mkdir /tmp/eigen
cd ../eigen
mkdir build_dir
cd build_dir
cmake -DCMAKE_INSTALL_PREFIX=/tmp/eigen/ ../
make install
cd ../../../../../..

TensorFlow has different shared object for C and C++ and following are the commands for each of them respectively:

For C++:

bazel build -c opt --config=monolithic //tensorflow:libtensorflow_cc.so

Bazel, can start multiple threads and can consume lot of memory, if you are on constrained system use following command to control the resources, with a disclaimer that it can take long time to get compiled:

bazel build -c opt --config=monolithic --jobs 1 --local_resources 2048,0.5,1.0 --verbose_failures //tensorflow:libtensorflow_cc.so

For C:

bazel build -c opt //tensorflow:libtensorflow.so

3. Create Project

Create the demo project where we will link these generated libraries:

mkdir my_proj
cd my_proj
vim my_test.cpp // Chose editor of your choice

and copy this code to my_test.cpp, i have made some edits in this code.

#include "tensorflow/cc/client/client_session.h"
#include "tensorflow/cc/ops/standard_ops.h"
#include "tensorflow/core/framework/tensor.h"
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main() {

cout << "OpenCV version : " << CV_VERSION << endl;

using namespace tensorflow;
using namespace tensorflow::ops;
Scope root = Scope::NewRootScope();
// Matrix A = [3 2; -1 0]
auto A = Const(root, { {3.f, 2.f}, {-1.f, 0.f}});
// Vector b = [3 5]
auto b = Const(root, { {3.f, 5.f}});
// v = Ab^T
auto v = MatMul(root.WithOpName("v"), A, b, MatMul::TransposeB(true));
std::vector<Tensor> outputs;
ClientSession session(root);
// Run and fetch v
TF_CHECK_OK(session.Run({v}, &outputs));
// Expect outputs[0] == [19; -3]
LOG(INFO) << outputs[0].matrix<float>();
return 0;
}

Now copy the generated libraries to the my_projproject directory:

mkdir ../my_proj/lib
cp bazel-bin/tensorflow/libtensorflow_cc.so ../my_proj/lib/
cp bazel-bin/tensorflow/libtensorflow_framework.so ../my_proj/lib/
cp /tmp/protobuf/lib/libprotobuf.a ../my_proj/lib/

Then the includes files:

mkdir -p ../my_proj/include/tensorflow
cp -r bazel-genfiles/* ../my_proj/include/
cp -r tensorflow/cc ../my_proj/include/tensorflow
cp -r tensorflow/core ../my_proj/include/tensorflow
cp -r third_party ../my_proj/include
cp -r /tmp/protobuf/include/* ../my_proj/include
cp -r /tmp/eigen/include/eigen3/* ../my_proj/include

Finally, we need to compile my_test.cpp

4. Compile the test project

Create a Makefile:

vim Makefile

copy the following text to Makefile:

CC = g++
CPPFLAGS = -c -g
SOURCES = my_test.cpp
CPPFLAGS += -fPIC -Iinclude -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux/ -I/usr/lib/jvm/java-8-openjdk-amd64/include/ `pkg-config --cflags opencv`
LDFLAGS += '-Wl,-rpath,$$ORIGIN/lib' -Llib -ltensorflow_cc -ltensorflow_framework -lopencv_core -lopencv_imgproc -lopencv_ml -lopencv_highgui -lopencv_imgcodecs `pkg-config --libs opencv`
OBJ = $(SOURCES:.cpp=.o)%.o : %.cpp
$(CC) -std=gnu++11 -c -o $@ $< $(CPPFLAGS)
my_test: $(OBJ)
$(CC) -std=gnu++11 -o $@ $^ $(LDFLAGS)
clean:
rm -rf *.o my_test

Or run following command from CLI:

g++ -std=gnu++11 -Wl,-rpath='$ORIGIN/lib' -Iinclude -Llib my_test.cpp -ltensorflow_cc -ltensorflow_framework -lopencv_core -lopencv_imgproc -lopencv_highgui -o my_test

You can now execute your program with:

./my_test

Github Repo for, Tensorflow Lite Standalone C++ build for Linux and MacOS here.

Co-founder Logits Systems https://logits.systems. Biometric on the edge. https://tomdeore.wixsite.com/epoch