Overview

If you’re here, you’ve probably discovered that the versions of opencv available on the Anaconda cloud (via the conda package manager) don’t have ffmpeg codecs compiled within them. This means that you can’t read or write videos using these versions of opencv. There is no easy way around this as far as I know, so here I’m going to cover how to go about building opencv from source. We’ll set up our build config to that opencv links with our version of python bundled within anaconda in addition to enabling ffmpeg integration so we can read/write videos.

I’ve tried to generalize my code as much as possible so that you can use this with any version of opencv and anaconda, so watch out for steps where I’m explicitly asking you to type in your opencv and python versions.

The following represents a streamlined version of this guide.

Dependancies

As always, when building on linux I take a shotgun approach to dependancies. I’m just running a single call to apt covering all dependancies I’ve seen mentioned on other guides, or have figured out myself from build errors.

  1. First, lets cover our build tools.

     sudo apt update
     sudo apt upgrade
    
     sudo apt install build-essential cmake pkg-config git
    
  2. Now lets cover any libraries we might need.

     sudo apt install libjpeg8-dev libtiff5-dev libjasper-dev libpng12-dev \
         libavcodec-dev libavformat-dev libswscale-dev libv4l-dev \
         libxvidcore-dev libx264-dev libgtk-3-dev libatlas-base-dev gfortran
    

    Some of these libraries may be specific to ubuntu 16.04, so dont worry if your using a different linux distro and some packages are missing. If you run into dependancy issues later on, you can use the error logs to figure out which packages you need. Now lets grab the relevant source code!

Get the source code

Here, I’m going to be building from the latest stable release, which is 3.4.3 in my case. We’ll use git to grab the code and checkout version we need.

  1. Clone the opencv git repository and checkout the version 3.4.3

     git clone https://github.com/opencv/opencv.git
     cd opencv 
     git checkout 3.4.3 
     cd .. 
    
  2. Now that we have the opencv source, we’ll also need to clone another repo which covers installing the extra features we need, like ffmpeg integration of video codecs. Here, its important that we select the same version of both opencv and opencv_contrib.

     git clone https://github.com/opencv/opencv_contrib.git
     cd opencv_contrib
     git checkout 3.4.3
     cd ..
    

If you build it… they will come

After, you should have two folders in your current directory: opencv and opencv_contrib. Its important that you use the same version for both repos as they will depend on eachother for the build later.

  1. Now lets set up a build directory. Its always a good idea to keep your builds seperate from your source files.

     cd opencv
     mkdir build 
     cd build 
    
  2. Now we’ll setup our build configuration. First, we’ll have to manually specify the location of the anaconda install and the python version bundled with it. The following code should work if you copy and paste it as a single block into your terminal.

    Using the values you provide at the top of the code block, the script will generate paths where it expects to find libraries relevant to the build. The latter part of the code block just checks that these generated paths do in fact exist. If the paths you provide are incorrect, it’ll throw some warning messages.

     ##########################################################
     ## Specify directories of anaconda and python libraries ##
     ##########################################################
    
     anaconda="/home/james/anaconda3"
     pythonVersion="3.7"
    
     #################################################
     ## Check that user specified directories exist ##
     #################################################
     pass=true
     ############# Check Exec
     pyExec="${anaconda}/bin/python"
     if [ ! -e "${pyExec}" ]; then
          echo "${pyExec}/bin/python does not exist"
          pass=false
     fi
     ############# Check Lib
     pyLib="${anaconda}/lib/libpython${pythonVersion}m.so"
     if [ ! -e "${pyLib}" ]; then
         echo "${pyLib} does not exist"
         pass=false
      fi
     ############# Check Dir
     pyDir="${anaconda}/include/python${pythonVersion}m"
     if [ ! -d "${pyDir}" ]; then
         echo "${pyDir} does not exist"
         pass=false
     fi
     ############# Check Path
     pyPath="${anaconda}/lib/python${pythonVersion}"
     if [ ! -d "${pyPath}" ]; then
         echo "${pyPath} does not exist"
         pass=false
     fi
     ############# Check Path
     pyNumpy=${anaconda}/lib/python${pythonVersion}/site-packages/numpy/core/include
     if [ ! -d "${pyNumpy}" ]; then
         echo "${pyNumpy} does not exist"
         pass=false
     fi
    
     if [ "$pass" = true ]; then
         echo "Paths verified, you can go ahead and configure the build"
     fi
    

    If you recieved the message Paths verified, you can go ahead and configure the build!, continue to the next step. Otherwise, double check that the anaconda path and python version you supplied in lines 2-3 are correct.

    The path variables saved in this code block will be used in the next block, thus it’s important that you are using a single terminal session for all these steps (i.e. Do not close and reopen the terminal executing these code blocks).

    Before proceeding, double check that you are in the build directory we made, and that your directory structure looks like this.

     ├── opencv
     │   └── build
     └── opencv_contrib
    

    This is important, as I’ve coded in relative paths in the next code block which assume this structure.

    Now lets run the build configuration. It’ll only run if the values you gave earlier were correct.

     #### Run configuration if direcotries exist
     if [ "$pass" = true ]; then
     echo "Running configuration..."
     cmake -D CMAKE_BUILD_TYPE=RELEASE \
          -D CMAKE_INSTALL_PREFIX=/usr/local \
          -D INSTALL_C_EXAMPLES=OFF \
          -D INSTALL_PYTHON_EXAMPLES=OFF \
          -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \
          -D BUILD_EXAMPLES=OFF \
          -D BUILD_opencv_python2=OFF \
          -D BUILD_opencv_python3=ON \
          -D BUILD_TIFF=ON \
          -D WITH_FFMPEG=1 \
          -D WITH_CUDA=OFF \
          -D ENABLE_FAST_MATH=1 \
          -D PYTHON3_EXECUTABLE="${pyExec}" \
          -D PYTHON3_INCLUDE_DIR="${pyDir}" \
          -D PYTHON3_LIBRARY="${pyLib}" \
          -D PYTHON3_PACKAGES_PATH="${pyPath}" \
          -D WITH_LAPACK=OFF \
          -D PYTHON3_NUMPY_INCLUDE_DIRS="${pyNumpy}" \
           ..
     fi
    

    When finished, you should see some output like below. Do a quick check to verify that FFMPEG is set to yes and that the Python 3 section points to the correct libraries within anaconda (as opposed to your systems default bin directory).

     --   GUI: 
     --     GTK+:                        YES (ver 3.18.9)
     --       GThread :                  YES (ver 2.48.2)
     --       GtkGlExt:                  NO
     --     VTK support:                 NO
     -- 
     --   Media I/O: 
     --     ZLib:                        /home/james/anaconda3/lib/libz.so (ver 1.2.11)
     --     JPEG:                        /home/james/anaconda3/lib/libjpeg.so (ver 90)
     --     WEBP:                        /usr/lib/x86_64-linux-gnu/libwebp.so (ver encoder: 0x0202)
     --     PNG:                         /home/james/anaconda3/lib/libpng.so (ver 1.6.34)
     --     TIFF:                        build (ver 42 - 4.0.9)
     --     JPEG 2000:                   /usr/lib/x86_64-linux-gnu/libjasper.so (ver 1.900.1)
     --     OpenEXR:                     build (ver 1.7.1)
     --     HDR:                         YES
     --     SUNRASTER:                   YES
     --     PXM:                         YES
     -- 
     --   Video I/O:
     --     DC1394:                      NO
     --     FFMPEG:                      YES
     --       avcodec:                   YES (ver 57.107.100)
     --       avformat:                  YES (ver 57.83.100)
     --       avutil:                    YES (ver 55.78.100)
     --       swscale:                   YES (ver 4.8.100)
     --       avresample:                NO
     --     GStreamer:                   
     --       base:                      YES (ver 1.8.3)
     --       video:                     YES (ver 1.8.3)
     --       app:                       YES (ver 1.8.3)
     --       riff:                      YES (ver 1.8.3)
     --       pbutils:                   YES (ver 1.8.3)
     --     libv4l/libv4l2:              NO
     --     v4l/v4l2:                    linux/videodev2.h
     -- 
     --   Parallel framework:            pthreads
     -- 
     --   Trace:                         YES (with Intel ITT)
     -- 
     --   Other third-party libraries:
     --     Intel IPP:                   2017.0.3 [2017.0.3]
     --            at:                   /home/james/opencv/build/3rdparty/ippicv/ippicv_lnx
     --     Intel IPP IW:                sources (2017.0.3)
     --               at:                /home/james/opencv/build/3rdparty/ippicv/ippiw_lnx
     --     Eigen:                       NO
     --     Custom HAL:                  NO
     --     Protobuf:                    build (3.5.1)
     -- 
     --   NVIDIA CUDA:                   NO
     -- 
     --   OpenCL:                        YES (no extra features)
     --     Include path:                /home/james/opencv/3rdparty/include/opencl/1.2
     --     Link libraries:              Dynamic load
     -- 
     --   Python 3:
     --     Interpreter:                 /home/james/anaconda3/bin/python3 (ver 3.7)
     --     Libraries:                   /home/james/anaconda3/lib/lib3.7m.so (ver 3.7.0)
     --     numpy:                       /home/james/anaconda3/lib/python3.7/site-packages/numpy/core/include (ver 1.15.1)
     --     packages path:               /home/james/anaconda3/lib/python3.7
     -- 
     --   Python (for build):            /home/james/anaconda3/bin/python
     -- 
     --   Java:                          
     --     ant:                         NO
     --     JNI:                         NO
     --     Java wrappers:               NO
     --     Java tests:                  NO
     -- 
     --   Matlab:                        NO
     -- 
     --   Install to:                    /usr/local
     -- -----------------------------------------------------------------
     -- 
     -- Configuring done
     -- Generating done
     -- Build files have been written to: /home/james/opencv/build
     -- Configuring done
     -- Generating done
     -- Build files have been written to: /home/username/Downloads/opencv/build
    

    If you find you accidentally set a wrong path during the configuration, I strongly suggest deleting the contents of the build directory before rerunning the configuration again with new parameters. It’s a known issue that cached values in the configuration step can linger and cause problem even when you rerun the configuration with new values.

  3. Now we’ll build the library. We should still be in the build folder at this point, and you can use the option -j<n-cores> to specity how many cores you want to give opencv access to. Note that this build can take quite some time, so expect to wait over 20 minutes for this to complete.

    If you run into any errors at this step, you’ll have to look through the error messages and see if you can pinpoint a specific library thats causing problems. Once you found it, you can typically resolve the issue by either installing the missing library with apt or changing your build configuration. In my case, I kept on getting errors when building the examples. The simple solution to this was just to add -D BUILD_EXAMPLES=OFF as a build option. Whatever the problem is, make sure to nuke your build direcory and rerun the build configuration before trying to compile again.

     make -j4
    

    Finally, copy the compiled libraries the the correct destinations by calling the install recepie.

     sudo make install
     sudo ldconfig 
    
  4. Finally, lets validate that opencv is linked to anaconda. Open spyder (or any python console in anaconda), and enter:

     import cv2
     cv2.__version__
    

    Your output should be 3.4.3, which matches the version we just installed.

Final Thoughts

Font library errors when importing opencv library

I first ran this install script on Elementary os (based on Ubuntu 16.04) and it worked like a charm! The second time I ran this I was using Ubuntu 18.04 and after a sucessfull build I ran into the error: libfontconfig.so.1: undefined symbol: FT_Done_MM_Var when trying to import cv2. The strange thing is that this error did not appear when I was using ipython in spyder, but did appear in all other python IDEs I tried running (like VS Code), even though they were all running the same python binary file (in anaconda3/bin). As far as I can tell, this seems to be related to differently defined paths between the python IDEs I tried. The solution is simple and has been described here.

Delete the problematic libraries from anaconda3/lib which are mentioned in the error message. After you delete one, an error message for the next library should appear when you try to import opencv again.

  • <...>/anaconda3/lib/libfontconfig.so
  • <...>/anaconda3/lib/libfontconfig.so.1
  • <...>/anaconda3/lib/libfontconfig.so.1.11.1
  • <...>/anaconda3/lib/libpangoft2-1.0.so.0
  • <...>/anaconda3/lib/libpangoft2-1.0.so.0.4200.4

After deleting these libraries, I was able to import and run opencv apps without issue. My assumption is that some of these current anaconda3 libraries are incompatable with Ubuntu 18.04 and deleteing them causes Anaconda to revert to the system default libraries which work fine.

Updated on: 2018-11-06