The newest members in my toy collection are a Raspberry Pi Zero W (paid link) and a NoIR Camera Module (paid link), purchased in Dec 2017.
Recently, I witnessed an impressive Contour Detection demo at MoCoMakers meetup.
I read their source code, and it has a dependency on cv2
Python package.
Therefore, the first step to get it working on my RPi Zero would be installing OpenCV that provides cv2
package.
While Raspbian Stretch offers a python-opencv package, it is version 2.4.9 released in 2014, and it only works with Python 2 but not Python 3. Since I'm starting from scratch, I wanted to develop on newer platforms: OpenCV 3.x and Python 3.
Many online tutorials suggest compiling OpenCV from source code. There are also a few sites offering pre-compiled tarballs, but these are either compiled for the Raspberry Pi 3, or built for Raspbian Jessie; neither would be compatible with my Raspberry Pi Zero W running Raspbian Stretch. Therefore, I started my quest to build OpenCV 3 for Pi Zero.
Debian Package > Source Code
When I first learned Linux, the standard process of installing software is wget
, tar xzvf
, ./configure
, make
, make install
.
Today, this is no longer recommended because software installed this way is difficult to remove and could cause conflicts.
Instead, it is recommended to install everything from Debian packages.
OpenCV 3 does have Debian packages, but they are intended for Debian Buster. There isn't a Raspbian Buster yet.
It is, however, possible to build a package intended for a newer Debian version onto an older Debian release. This process is known as building a backport. I decided to do things in the proper way, and build backport packages instead of installing from OpenCV 3 source code.
ARM64 is not "armhf"
Pi Zero has one CPU core and 512MB of memory. It would take a long time to build OpenCV 3, a large and complex software package. I decided to build it in the cloud, and let a Scaleway instance do the heavy work.
I created a virtual machine with 4 dedicated ARM64 CPU cores and 2GB memory, at the cost of €0.04 per hour with IPv6-only connectivity.
Following the official guide for building a private backport, it took about 20 hours to produce 66 .deb package files.
I noticed something wrong as I was downloading them to the local storage: they are suffixed with _arm64.deb
rather than the familiar _armhf.deb
.
ARM64 is a different CPU architecture from 32-bit "armhf" CPU, and the packages would not be compatible.
"armhf" CPUs are Not Created Equal
Realizing my ARM64 mistake, I provisioned a "bare metal" C1 instance on Scaleway. They have 32-bit "armhf" CPU cores, and I previously built software for my Raspberry Pi 3 on these instances. It costs slightly more at €0.06 per hour, because an IPv4 address is required to access it.
As I noticed during the previous attempt, the fakeroot debian/rules binary
step was not strictly necessary, so I skipped it this time.
It still required an overnight job (15 hours) to finish the build.
I joyfully downloaded 66 _armhf.deb
package files, and installed them into my Pi Zero.
I eagerly typed import cv2
into the Python 3 console, but received an error message:
Illegal instruction.
After some GDB and searching, I learned that, the Raspberry Pi Zero has an ARMv6 CPU, while Scaleway's C1 and the Pi 3 have ARMv7 CPUs. Although they are both labeled "armhf", ARMv7 architecture supports more CPU instructions than ARMv6. As a result, software compiled for ARMv7 would contain instructions unavailable on ARMv6 and therefore cause "Illegal instruction" error.
Building on the Pi Zero in 3 Days
Unfortunately there isn't a cloud provider offering ARMv6 instances, and I am not well-versed on the art of cross-compiling.
I was left with no choice but to build OpenCV 3 on the Pi Zero itself.
To reduce wear-and-tear on the microSD card, I plugged in a 16GB USB flash drive via a USB OTG cable (paid link), to store the source code, build files, and a 1GB swapfile
.
The build progressed to 12% overnight, and then I kicked loose the power cord.
After restarting the build from the beginning, I left the Pi Zero alone and avoided coming too close to it.
It took 56 hours for dpkg-buildpackage -us -uc
to terminate, with a bloody error:
dh_installman
stdin not open for reading!
stdin not open for reading!
stdin not open for reading!
dh_installman: man --recode UTF-8 ./opencv_createsamples\.1 > opencv_createsampl
es\.1\.new returned exit code 2
debian/rules:71: recipe for target 'binary' failed
make: *** [binary] Error 2
dpkg-buildpackage: error: fakeroot debian/rules binary gave error exit status 2
Although it is obvious where this error message comes from, and I have seen it several times building other packages, I do not know how to fix it. Therefore, I used a quick and dirty workaround:
if ! [[ -f /usr/bin/dh_installman.real ]]; then
mv /usr/bin/dh_installman /usr/bin/dh_installman.real
(echo '#!/bin/bash'; echo '/usr/bin/dh_installman.real "$@" || true') > /usr/bin/dh_installman
chmod +x /usr/bin/dh_installman
fi
This replaces dh_installman
with a bash script that returns "true" even if the actual program has failed.
With this workaround in place, I restarted the package building process.
56 hours of work did not go down the drain, however, because I added the --no-pre-clean
flag this time, which allows dpkg-buildpackage
to use the "dirty" source code directory and pick up from where it left off.
It took another 10 hours to finish the packaging process.
I installed the packages, and fidgetingly typed import cv2
into the Python 3 console.
It succeeded.
I made the contour detection algorithm working a few days later.
You can Install OpenCV 3 in 15 Minutes
After a happy dance, I uploaded my OpenCV 3 packages to a Bintray repository to share with everyone. Now you can follow my instructions and install OpenCV 3 on Raspberry Pi Zero W in 15 minutes.