Building OpenCV with CUDA support is a task and a half. Many folks get a surprise when the try to run the result in Python. Fortunately, there’s a solution. Looky here:
Python is a general purpose programming language which runs on many different machines, architectures and operating systems. As such, there are always quirks and niggles to get things to work correctly. Running Python on Ubuntu is no exception.
The Linux for Jetson operating system is based on Ubuntu. Ubuntu is built on a Debian base. Debian is a Linux operating system. The file layout for Debian based systems is slightly different than other Linux distributions.
The file layout is important because it determines where programs and their libraries are stored. It is the library locations that cause the major headaches in developing programs. If you’ve ever attempted programming on a computer, you’re likely aware that identifying which support software (libraries) are installed, locating their installation directories, and ensuring they are the appropriate versions can be quite challenging. Truthfully, almost impossible at times. You may even notice this when simply installing software.
My suspicion is that this is the reason you have to pay programmers. No one is going to wade into that swamp without being paid.
Linux File System
Here’s a great 100 second explanation of the Linux file system layout:
Let’s expand on what that means to us as far as storing programs and libraries. The terms binaries, programs, executable files, applications and commands tend to be interchangeable, depending on use. The term bin is short for binaries. Space for characters were at a premium at the dawn of Linux, so terms like bin replace the more formal binaries or programs.
In the root directory, denoted by a the / character, there are three directories of interest. The root directory holds the essential system programs that are required to run a Linux system. Files in the /bin directory hold programs which we call commands. These are familiar commands we use on the Terminal such as ls, cp, cat and mv. Files in the /sbin directory are for system administration. These are also commands, one example of which is mount. The third directory is /lib which contains system libraries used by the commands and other parts of the system.
One directory in the root folder is the /usr directory. Like the root directory, /usr contains bin, sbin and lib directories as well as other directories. Debian based systems use Advanced Packaging Tool (apt) to manage packages in these directories. /usr/bin contains user commands which are not essential to the system. This is where the bulk of user-installed and distributable software go. Applications like web browsers, word processors and other tools.
/usr/sbin is another system administrator area, where non-essential system commands are kept. /usr/lib is where libraries are stored, usually related to the programs in /usr/bin and /usr/sbin. This includes shared libraries, static libraries, modules, plugins, package data, development files and so on.
The take away here is that this is a managed area, the apt program should do the housekeeping.
In the /usr directory, there is a directory named local. We refer to this as /usr/local Like /usr, /usr/local contains several directories including bin, sbin and lib. As you can guess, /usr/local/bin contains executable files installed by a system administrator (typically from source), or by using a package manager that is separate from the system’s default package manager. In Python, this might be pip installing a package. /usr/local is the place for ‘locally installed software’. Because /usr/local is not managed by the primary package manager, the software installed there will not be overwritten or removed during system updates or upgrades.
/usr/local/sbin serves the similar purpose for system binaries for use by system admins. /usr/local/lib stores library files that are installed locally on the system. These are usually in support for the programs in /usr/local/bin and /usr/local/sbin.
The environment variable PATH is a list of directories that the Linux shell searches through when you enter a command. When a command is issued in the Terminal, the system uses the PATH environment variable to locate the executable file for the command. It usually searches from local to system, searching in order /usr/local/sbin, /usr/local/bin, /usr/sbin, /usr/bin, /sbin, /bin. You can change the PATH variable to support whatever search pattern you need, so there’s no hard and fast rule for the ordering.
Because Debian is a little different than other Unixes, there are some issues. Here’s a good rant/article about install locations if you want to know the issues in depth. Here’s how it works, as far as I can figure.
When a Python module/package is installed, it goes into one of two folders. dist-packages are modules that are installed as a super user, i.e. installed with sudo. site-packages hold modules/packages that are installed as a regular user.
If apt installs the module/package, then it goes into the appropriate directory in the /usr directory. For example if we sudo apt install python3-numpy , it would be in /usr/lib/python3/dist-packages/numpy . Because apt installs use sudo, there usually isn’t a site-packages directory in /usr/lib/python3. Also note that there are more explicit paths based on the version of Python, for example /usr/lib/python3.6 which may contain modules/packages which override others.
If you compile your own Python packages, or use a Python package manager like pip to do it, then it will be installed in /usr/local/lib/dist-package if it was a sudo install, or /usr/local/lib/site-packages if it was a regular user install.
With all that said (and now you know why you have to pay programmers), you have to make sure that Python understands where libraries are installed. On the Jetson, Python does not appear to know about the site-packages directory. There are several ways to tell Python about it. One of the side effects of programmers being exposed to directory paths like this is that they eventually go insane. Therefore anyway that you decide to resolve the conflict will be met with forceful derision, because there’s always “a better or correct way”. Just remember, they cra cra.
One way to tell Python where to look is to use the PYTHONPATH environment variable. Python uses the PYTHONPATH to determine the search order to look for modules. Here’s an example. Let’s say that we’re using Python 3.6 on a Jetson Nano as shown in the video. The cv2 module has been built and installs into /usr/local/lib/python3.6/site-packages We export the PYTHONPATH to the shell:
You will want to place this in ~/.bashrc so that it will be remembered every time you open a new shell. Remember the ~ represents your home user directory. The period in front of bashrc indicates the file is hidden. There are a couple of ways to make this persist, this is the one shown in the video. Also, the python3.6 in the above path should be whichever Python you built against. We used Python 3.6.
You should be able to run:
$ opencv_version -v
to print out the build information and get the location of the library install. This is the same as the cv2.getBuildInformation() command in Python.
That’s a long post to say “add this one line to your .bashrc file”. However, if you are a developer this is a fight you will always be in. In this case it was in Python, but it holds true for all the programming languages. You need to know where the libraries are, and set the paths to them correctly to build and link against them. I am hoping that this gives you some insight as to how it all fits together.