Raspberry Pi is a small ARM computer with a camera, a network controller, and Linux on board. That makes it a good choice for DIY computer vision projects.
In this post, we will learn how to build the OpenCV library for Raspbian with native compiler on board and cross-compiler.
Supported Raspberry Pi Versions
We have tested the solution for Raspberry versions from 1 to 4. In addition, we provide some tips and tricks to optimize the library performance, dependencies, and build time.
Target hardware
OpenCV is a highly optimized library. Most of its functions have different implementations for different processors: this way, the code can be specifically tuned to use the capabilities of the chips. The optimized code often uses some specific hardware-related functions, or instructions sets: for example, Intel CPUs support SSE, AVX and other instruction sets, and ARM chips support VFP and NEON instructions.
Different versions of Raspberry board are built with different generations of ARM chips. Each of them has different vectorization and optimization capabilities, and thus supports different instruction subsets.
By default, OpenCV uses ARMv7 instruction set as a minimal baseline — it is a modern architecture and enables the execution on a wide spectrum of hardware.
Old Raspberry Pi 1 and Raspberry Pi Zero use older ARMv6 architecture and do not have much scope for acceleration. Your Raspberry may well support more than ARMv7 baseline.
You can significantly optimize OpenCV by letting it know more details of your hardware during the compilation.
Here is the full list of ARM CPU features, and the corresponding CMake options for OpenCV configuration:
CPU Feature | CMake Key | Comment |
---|---|---|
thumb | N/A | ARM Thumb instruction set is enabled by default |
VFPv3 | -DENABLE_VFPV3=ON | ARM VFPv3 floating point instructions extension |
NEON | -DENABLE_NEON=ON | ARM NEON vector instruction set |
/proc/cpuinfo
file contains all the CPU options and capabilities of your board. Let’s run it on two Raspberries: v1 and v3 – and compare the outputs.
The file content on Raspberry Pi 1 model B is the following:
pi@raspberrypi:~ $ cat /proc/cpuinfo
processor : 0
model name : ARMv6-compatible processor rev 7 (v6l)
BogoMIPS : 697.95
Features : half thumb fastmult vfp edsp java tls
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part : 0xb76
CPU revision : 7
...
For OpenCV compilation, we need the model name
and features
. Model name means that the CPU is built using the ARMv6 architecture, and the feature list doesn’t contain any useful optimization options.
The same file on Raspberry Pi 3 is the following:
pi@raspberrypi:~ $ cat /proc/cpuinfo
processor : 0
model name : ARMv7 Processor rev 4 (v7l)
BogoMIPS : 38.40
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part : 0xd03
CPU revision : 4
...
The model name means that the CPU is built using the ARMv7 architecture. As we see, the features contain VFPV3
and NEON
that can be used for optimization.
Check CMake status output to ensure that all the relevant hardware options are applied. For example, here is what you should see for ARMv6:
-- CPU/HW features:
-- Baseline:
-- requested: DETECT
-- disabled: VFPV3 NEON
Example for ARMv7 with NEON support:
-- CPU/HW features:
-- Baseline: VFPV3 NEON
-- requested: DETECT
-- required: VFPV3 NEON
ARM-specific libraries for performance
The OpenCV library provides an integration with several ARM-specific acceleration libraries.
- OpenCV HAL (Hardware Abstraction Layer) is an interface for platform-specific and low-level architecture-specific implementations. OpenCV contains NVIDIA Carotene — it implements HAL for ARMv7 and ARMv8 architectures and uses NEON instructions. OpenCV enables Carotene HAL if
-DENABLE_NEON=ON
is specified:
-- Other third-party libraries:
-- Lapack: NO
-- Eigen: YES (ver 3.3.7)
-- Custom HAL: YES (carotene (ver 0.0.1))
-- Protobuf: build (3.5.1)
- OpenCV now supports Tengine – a powerful inference engine for deep learning on ARM. In fact, it is a very recent addition to OpenCV – the code to support Tengine was committed this March. It is experimental for now and is disabled by default. Add
-DWITH_TENGINE=ON
to CMake command line to enable it. Look at CMake output to check that the library is there:
-- Other third-party libraries:\n"
-- Tengine: YES (tengine)
-- Lapack: NO
Native build on Pi
The simplest, but not so efficient, way to build OpenCV for Pi is to do it natively on board. The build procedure takes hours depending on Pi version and SD-card speed.
- Install all the required packages on Pi.
Mandatory part:
sudo apt-get -y update
# compiler and build tools
sudo apt-get -y install git build-essential cmake pkg-config checkinstall
# development files for system wide image codecs
sudo apt-get -y install libjpeg-dev libpng-dev libtiff-dev
# Protobuf library and tools for dnn module
sudo apt-get -y install libprotobuf-dev protobuf-compiler
# development files for V4L2 to enable web cameras support in videoio module
sudo apt-get -y install libv4l-dev
Optional part:
# FFmpeg development files to enable video decoding and encoding in videoio module
sudo apt-get -y install libavcodec-dev libavformat-dev libswscale-dev
# development files for GTK 2.0 UI library for highgui module
sudo apt-get -y install libgtk2.0-dev
# Eigen library needed for some modules in contrib repository
sudo apt-get -y install libeigen3-dev
# Numpy and Python3 development files for Python bindings
sudo apt-get -y install python3-dev python3-pip
sudo -H pip3 install numpy
OpenCV contains its own implementation of MJPEG video codec and can use it even if FFmpeg isn’t available.
- All Raspberry Pi boards, besides the top configuration of the 4th generation, have a small RAM that’s not enough for OpenCV library build. That said, the build process requires a swap file to be at least 1Gb in size. Run the following command to enable the swap on your Pi:
sudo sed -i 's/CONF_SWAPSIZE=100/CONF_SWAPSIZE=1024/g' /etc/dphys-swapfile
sudo /etc/init.d/dphys-swapfile stop
sudo /etc/init.d/dphys-swapfile start
- Clone OpenCV and OpenCV Contrib repositories:
git clone https://github.com/opencv/opencv.git
git clone https://github.com/opencv/opencv_contrib.git
4a. In case if you do not need features from Contrib repository you can build only core part of the library. Please don’t forget to add the platform-specific options to CMake command line to get the best performance:
mkdir build
cd build
cmake ../opencv
An example of CMake output for Raspberry Pi 3 with VFPv3 and NEON enabled:
-- General configuration for OpenCV 4.3.0-dev =====================================
-- Version control: 4.3.0-87-g8ff0399432
--
-- Platform:
-- Timestamp: 2020-04-15T09:02:57Z
-- Host: Linux 4.19.97-v7+ armv7l
-- CMake: 3.13.4
-- CMake generator: Unix Makefiles
-- CMake build tool: /usr/bin/make
-- Configuration: Release
--
-- CPU/HW features:
-- Baseline: VFPV3 NEON
-- requested: DETECT
-- required: VFPV3 NEON
--
-- C/C++:
-- Built as dynamic libs?: YES
-- C++ standard: 11
-- C++ Compiler: /usr/bin/c++ (ver 8.3.0)
-- C++ flags (Release): -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wsuggest-override -Wno-delete-non-virtual-dtor -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG -DNDEBUG
-- C++ flags (Debug): -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wsuggest-override -Wno-delete-non-virtual-dtor -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections -fvisibility=hidden -fvisibility-inlines-hidden -g -O0 -DDEBUG -D_DEBUG
-- C Compiler: /usr/bin/cc
-- C flags (Release): -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wuninitialized -Winit-self -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections -fvisibility=hidden -O3 -DNDEBUG -DNDEBUG
-- C flags (Debug): -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wuninitialized -Winit-self -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections -fvisibility=hidden -g -O0 -DDEBUG -D_DEBUG
-- Linker flags (Release): -Wl,--gc-sections -Wl,--as-needed
-- Linker flags (Debug): -Wl,--gc-sections -Wl,--as-needed
-- ccache: NO
-- Precompiled headers: NO
-- Extra dependencies: dl m pthread rt
-- 3rdparty dependencies:
--
-- OpenCV modules:
-- To be built: calib3d core dnn features2d flann gapi highgui imgcodecs imgproc ml objdetect photo python2 python3 stitching ts video videoio
-- Disabled: world
-- Disabled by dependency: -
-- Unavailable: java js
-- Applications: tests perf_tests apps
-- Documentation: NO
-- Non-free algorithms: NO
--
-- GUI:
-- GTK+: NO
-- VTK support: NO
--
-- Media I/O:
-- ZLib: /usr/lib/arm-linux-gnueabihf/libz.so (ver 1.2.11)
-- JPEG: /usr/lib/arm-linux-gnueabihf/libjpeg.so (ver 62)
-- WEBP: build (ver encoder: 0x020f)
-- PNG: /usr/lib/arm-linux-gnueabihf/libpng.so (ver 1.6.36)
-- TIFF: /usr/lib/arm-linux-gnueabihf/libtiff.so (ver 42 / 4.1.0)
-- JPEG 2000: build Jasper (ver 1.900.1)
-- OpenEXR: build (ver 2.3.0)
-- HDR: YES
-- SUNRASTER: YES
-- PXM: YES
-- PFM: YES
--
-- Video I/O:
-- DC1394: NO
-- FFMPEG: YES
-- avcodec: YES (58.35.100)
-- avformat: YES (58.20.100)
-- avutil: YES (56.22.100)
-- swscale: YES (5.3.100)
-- avresample: NO
-- GStreamer: NO
-- v4l/v4l2: YES (linux/videodev2.h)
--
-- Parallel framework: pthreads
--
-- Trace: YES (with Intel ITT)
--
-- Other third-party libraries:
-- Lapack: NO
-- Eigen: YES (ver 3.3.7)
-- Custom HAL: YES (carotene (ver 0.0.1))
-- Protobuf: build (3.5.1)
--
-- OpenCL: YES (no extra features)
-- Include path: /home/pi/Projects/opencv/3rdparty/include/opencl/1.2
-- Link libraries: Dynamic load
--
-- Python 2:
-- Interpreter: /usr/bin/python2.7 (ver 2.7.16)
-- Libraries: /usr/lib/arm-linux-gnueabihf/libpython2.7.so (ver 2.7.16)
-- numpy: /usr/lib/python2.7/dist-packages/numpy/core/include (ver 1.16.2)
-- install path: lib/python2.7/dist-packages/cv2/python-2.7
--
-- Python 3:
-- Interpreter: /usr/bin/python3 (ver 3.7.3)
-- Libraries: /usr/lib/arm-linux-gnueabihf/libpython3.7m.so (ver 3.7.3)
-- numpy: /usr/lib/python3/dist-packages/numpy/core/include (ver 1.16.2)
-- install path: lib/python3.7/dist-packages/cv2/python-3.7
--
-- Python (for build): /usr/bin/python2.7
--
-- Java:
-- ant: /usr/bin/ant (ver 1.10.5)
-- JNI: NO
-- Java wrappers: NO
-- Java tests: NO
--
-- Install to: /usr/local
-- -----------------------------------------------------------------
--
-- Configuring done
-- Generating done
-- Build files have been written to: /home/pi/Projects/opencv-build
4b. In case if you want to use some features from Contrib, you need to add it to build. Again, don’t forget to add the platform-specific options:
mkdir build
cd build
cmake -DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib/modules ../opencv
- Now we’ll build the library itself. Be ready that the process takes several hours depending on your board performance and selected features:
make
- Build a simple Debian package:
$ checkinstall make install
checkinstall 1.6.2, Copyright 2009 Felipe Eduardo Sanchez Diaz Duran
This software is released under the GNU GPL.
The package documentation directory ./doc-pak does not exist.
Should I create a default set of package docs? [y]: y
Preparing package documentation...OK
Please write a description for the package.
End your description with an empty line or EOF.
>> Self build OpenCV for my Pi
>>
*****************************************
**** Debian package creation selected ***
*****************************************
This package will be built according to these values:
0 - Maintainer: [ pi@raspberrypi ]
1 - Summary: [ Self build OpenCV for my Pi ]
2 - Name: [ opencv ]
3 - Version: [ 1 ]
4 - Release: [ 1 ]
5 - License: [ GPL ]
6 - Group: [ checkinstall ]
7 - Architecture: [ armhf ]
8 - Source location: [ opencv-build ]
9 - Alternate source location: [ ]
10 - Requires: [ ]
11 - Provides: [ opencv ]
12 - Conflicts: [ ]
13 - Replaces: [ ]
Enter a number to change any of them or press ENTER to continue:
Installing with make install...
- Install the generated Debian package:
sudo dpkg -i ./opencv.deb
Congrats! We’ve installed OpenCV and it’s ready to use.
- Restore the original swap size if you don’t need it any more:
sudo sed -i 's/CONF_SWAPSIZE=1024/CONF_SWAPSIZE=100/g' /etc/dphys-swapfile
sudo /etc/init.d/dphys-swapfile stop
sudo /etc/init.d/dphys-swapfile start
Cross compilation with Ubuntu host
If you are not ready to spend several hours to build OpenCV library for your Pi, you can use cross-compiler on your Ubuntu host. This means that we’ll compile OpenCV for Raspberry right on the desktop computer. I used Ubuntu 18.04, but you can adapt the instruction to the other Ubuntu/Linux versions too. The solution is applicable if you don’t need UI, FFmpeg, and other advanced system dependencies as they’re not provided with the cross-compiler by default.
- Check the GCC version on your board. The major version of your cross-compiler needs to be the same as the GCC version on your board for compatibility reasons:
$ gcc --version
gcc (Raspbian 8.3.0-6+rpi1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- Install the cross-compiler and build tools on Ubuntu:
# Python 3 is used for scripting
sudo apt-get install git build-essential cmake pkg-config python3
sudo apt-get install gcc-8-arm-linux-gnueabi-base gcc-8-arm-linux-gnueabihf g++-8-arm-linux-gnueabihf
# Eigen is header only library and can be used during cross-compilation too
sudo apt-get install eigen
- Clone OpenCV and OpenCV Contrib repositories:
git clone https://github.com/opencv/opencv.git
git clone https://github.com/opencv/opencv_contrib.git
4a. Again, we’ll first configure and build just the core part of OpenCV. We’ll add the platform-specific options to cmake command line to get the best performance:
mkdir build
cd build
cmake -DCMAKE_TOOLCHAIN_FILE=../opencv/platforms/linux/arm-gnueabi.toolchain.cmake -DGCC_COMPILER_VERSION=8 ../opencv
# use more threads (8, 12, 16) for acceleration if you hardware is capable of doing it
make -j4
make install
An example of CMake output for Raspberry Pi 3 with VFPv3 and NEON enabled:
-- General configuration for OpenCV 4.3.0-dev =====================================
-- Version control: 4.3.0-113-g2cef100303
--
-- Platform:
-- Timestamp: 2020-04-23T10:06:08Z
-- Host: Linux 5.3.0-46-generic x86_64
-- Target: Linux 1 arm
-- CMake: 3.10.2
-- CMake generator: Unix Makefiles
-- CMake build tool: /usr/bin/make
-- Configuration: Release
--
-- CPU/HW features:
-- Baseline: VFPV3 NEON
-- requested: DETECT
-- required: VFPV3 NEON
--
-- C/C++:
-- Built as dynamic libs?: NO
-- C++ standard: 11
-- C++ Compiler: /usr/bin/arm-linux-gnueabihf-g++-8 (ver 8.4.0)
-- C++ flags (Release): -mthumb -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wsuggest-override -Wno-delete-non-virtual-dtor -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections -mfpu=neon -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG -DNDEBUG
-- C++ flags (Debug): -mthumb -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wsuggest-override -Wno-delete-non-virtual-dtor -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections -mfpu=neon -fvisibility=hidden -fvisibility-inlines-hidden -g -O0 -DDEBUG -D_DEBUG
-- C Compiler: /usr/bin/arm-linux-gnueabihf-gcc-8
-- C flags (Release): -mthumb -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi -fsigned-char -W -Wall -Werror=return-type -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wuninitialized -Winit-self -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections -mfpu=neon -fvisibility=hidden -O3 -DNDEBUG -DNDEBUG
-- C flags (Debug): -mthumb -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi -fsigned-char -W -Wall -Werror=return-type -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wuninitialized -Winit-self -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections -mfpu=neon -fvisibility=hidden -g -O0 -DDEBUG -D_DEBUG
-- Linker flags (Release): -Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--gc-sections -Wl,--as-needed
-- Linker flags (Debug): -Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--gc-sections -Wl,--as-needed
-- ccache: NO
-- Precompiled headers: NO
-- Extra dependencies: ade dl m pthread rt
-- 3rdparty dependencies: ittnotify libprotobuf zlib libjpeg-turbo libwebp libpng libtiff libjasper quirc tegra_hal
--
-- OpenCV modules:
-- To be built: calib3d core dnn features2d flann gapi highgui imgcodecs imgproc ml objdetect photo stitching ts video videoio
-- Disabled: world
-- Disabled by dependency: -
-- Unavailable: java js python2 python3
-- Applications: tests perf_tests apps
-- Documentation: NO
-- Non-free algorithms: NO
--
-- GUI:
-- GTK+: NO
--
-- Media I/O:
-- ZLib: build (ver 1.2.11)
-- JPEG: libjpeg-turbo (ver 2.0.4-62)
-- WEBP: build (ver encoder: 0x020f)
-- PNG: build (ver 1.6.37)
-- TIFF: build (ver 42 - 4.0.10)
-- JPEG 2000: build Jasper (ver 1.900.1)
-- HDR: YES
-- SUNRASTER: YES
-- PXM: YES
-- PFM: YES
--
-- Video I/O:
-- DC1394: NO
-- FFMPEG: NO
-- avcodec: NO
-- avformat: NO
-- avutil: NO
-- swscale: NO
-- avresample: NO
-- GStreamer: NO
-- v4l/v4l2: YES (linux/videodev2.h)
--
-- Parallel framework: pthreads
--
-- Trace: YES (with Intel ITT)
--
-- Other third-party libraries:
-- Lapack: NO
-- Custom HAL: YES (carotene (ver 0.0.1))
-- Protobuf: build (3.5.1)
--
-- OpenCL: YES (no extra features)
-- Include path: /home/alexander/Projects/OpenCV/opencv/3rdparty/include/opencl/1.2
-- Link libraries: Dynamic load
--
-- Python (for build): /usr/bin/python2.7
--
-- Install to: /home/alexander/Projects/OpenCV/opencv-4.0-rpi/install
-- -----------------------------------------------------------------
--
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alexander/Projects/OpenCV/opencv-4.0-rpi
4b. Now we’ll configure OpenCV with Contrib modules.
mkdir build
cd build
cmake -DCMAKE_TOOLCHAIN_FILE=../opencv/platforms/linux/arm-gnueabi.toolchain.cmake \
-DGCC_COMPILER_VERSION=8 \
-DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib/modules \
../opencv
# use more threads (8, 12, 16) for acceleration if you hardware is capable of doing it
make -j4
make install
- As the cross-compiler generates the binaries for another architecture, there is no sense in installing binaries to system directory to your host computer. In fact,
make install
installs everything to theinstall
sub-folder of the build folder. You just need to copy the contents of theinstall
folder to you board file system manually.
And we’re done with the cross-compilation!