This tutorial help people who are strugling with building Tensorflow C++ library for Windows and use it with OpenCV. I will show you how to build Tensorflow C++ library for Windows from source using bazel and Visual Studio 2019.
- Tut install
- Tut build
- Tut run example with tensorflow
- Tut run example with tensorflow + opencv
- Windows 10
- Visual Studio 2019 and Build Tools
- Python 3.8
- bazel 3.1.0
- MSYS2
- Tensorflow 2.4.4 (CPU only)
***Note***: You can change the version of Tensorflow and bazel, due to the compatibility of Tensorflow and bazel, you can check the compatibility [here](https://www.tensorflow.org/install/source_windows#tested_build_configurations).
- Download Python 3.8 from here.
- Install Python 3.8.
- Remember to check the box "Add Python 3.8 to PATH" when installing Python 3.8.
- Test Python 3.8 by openning CMD and type command:
python --version
- Download bazel 3.1.0 from here
- Change the file name to
bazel.exe
- Copy the file to
C:\bazel
- Add
C:\bazel
to PATH environment variable. - Test bazel by openning CMD and type command:
bazel --version
- Download MSYS2 from here.
- Install MSYS2.
- Add
C:\msys64\usr\bin
to PATH environment variable. - Test MSYS2 by openning CMD and type command:
mintty --version
- Download Visual Studio 2019 from here.
- Download Build Tools from here.
- Install Visual Studio 2019 and Build Tools.
- Remember to check the box
Desktop development with C++
,MSVC v142-VS2019 C++ build tools
andWindows 10 SDK
when installing Visual Studio 2019.
-
Open CMD and type command:
git clone https://github.com/tensorflow/tensorflow -b v2.4.4 --depth 1
-
Open the project and install requirements listed under
REQUIRED_PACKAGES
intensorflow\tools\pip_package\setup.py
-
Some Bug Fixing Before Compiling:
Before we start, we should edit the TensorFlow source code, because you will end up with linking errors (unresolved external symbols LK2019) as shown below if you follow the typical framework building steps.
Session and SessionOptions symbols are not exported So what are these errors?
Dynamic-link library(DLL) can only expose a maximum of 60,000 symbols which is one of DLL limitation. As TensorFlow has more than 60,000 symbols, so we have to manually choose which symbols to be exposed if they are not exposed from TensorFlow by default.
According to the experience, in order to deploy a TensorFlow model, the TensorFlow Session and SessionOptions Classes are required to be exported. The steps include:
Edit tensorflow\core\public\session.h Firstly, include TensorFlow macro header.
-
Build Tensorflow 2.4.4 by openning CMD and type command:
bazel build --config=opt //tensorflow:tensorflow.dll bazel build --config=opt //tensorflow:tensorflow.lib bazel build --config=opt //tensorflow:install_headers
-
Note: If you got stuck while building tensorflow.dll (the terminal hang at compiling... but the timming still running), you can try to restart the computer and build again (without running
bazel clean
). -
After building, you will get
tensorflow.dll
andtensorflow.lib
attensorflow\bazel-bin\tensorflow
andheaders
attensorflow\bazel-bin\tensorflow\include
.
-
Create a new project in Visual Studio 2019.
-
Choose
Console App
andC++
as the project type. -
Go to
Project Properties
->C/C++
->General
->Additional Include Directories
and add relative path totensorflow\bazel-bin\tensorflow\include
folder andtensorflow\bazel-bin\tensorflow\include\src
folder in Tensorflow build output to the list. -
Go to
Project Properties
->Linker
->General
->Additional Library Directories
and addtensorflow\bazel-bin\tensorflow
to the list. -
Go to
Project Properties
->Linker
->Input
->Additional Dependencies
and addtensorflow.lib
to the list. -
Go to
Build Events
->Post-Build Event
->Command Line
and addxcopy /y /d "<tensorflow.dll relative path>" "$(OutDir)"
-
Note: Remember to change Configuration to All Configuration and Platform to All Platforms
-
Create a new file
main.cpp
and copy the code below:#define NOMINMAX #include <iostream> #include "tensorflow/core/framework/graph.pb.h" #include "tensorflow/core/public/session.h" #include "tensorflow/core/public/version.h" int main() { std::cout << tf_git_version() << std::endl; std::unique_ptr<tensorflow::Session> session(tensorflow::NewSession({})); return 0; }
-
The
#define NOMINMAX
to avoid the errormin
andmax
are defined inwindef.h
andwinnt.h
in Windows SDK. -
Build the project and you will get the Console execution at
$(OutDir)
.
-
Download Opencv from here.
-
Extract by running the .exe file and copy the folder
opencv\build\include
totensorflow\bazel-bin\tensorflow\include
. -
Go to
Project Properties
->C/C++
->General
->Additional Include Directories
and add relative path totensorflow\bazel-bin\tensorflow\include\opencv2
folder in Tensorflow build output to the list. -
Go to
Project Properties
->Linker
->General
->Additional Library Directories
and addopencv\build\x64\vc16\lib
to the list. -
Change Configuration to Debug and Platform to x64.
- Go to
Project Properties
->Linker
->Input
->Additional Dependencies
and addopencv_world480d.lib
to the list. - Go to
Build Events
->Post-Build Event
->Command Line
and addxcopy /y /d "<opencv_world480d.dll relative path>" "$(OutDir)"
- Go to
-
Change Configuration to Release and Platform to x64.
- Go to
Project Properties
->Linker
->Input
->Additional Dependencies
and addopencv_world480.lib
to the list. - Go to
Build Events
->Post-Build Event
->Command Line
and addxcopy /y /d "<opencv_world480.dll relative path>" "$(OutDir)"
- Go to
-
Edit file
main.cpp
and copy the code below:#define NOMINMAX #include <iostream> #include "tensorflow/core/framework/graph.pb.h" #include "tensorflow/core/public/session.h" #include "tensorflow/core/public/version.h" /* int main() { return 0; } */ #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main(int argc, char** argv) { std::cout << tf_git_version() << std::endl; std::unique_ptr<tensorflow::Session> session(tensorflow::NewSession({})); // Read the image file Mat image = imread("<Your Test Image Path>"); // Check for failure if (image.empty()) { cout << "Image Not Found!!!" << endl; cin.get(); //wait for any key press return -1; } // Show our image inside a window. imshow("Image Window Name here", image); //// Wait for any keystroke in the window waitKey(0); return 0; }
-
Build the project and you will get the Console execution at
$(OutDir)
.