Create Docker images for ZED and OpenCV

Open in ClaudeOpen in ChatGPT

We have earlier seen how to create a docker image. In this section we follow the same recommended workflow for creating docker images with slight changes, therefore we highly recommend you go through that tutorial to refresh your memory before continuing here.

A generic Dockerfile skeleton is made available to assemble an image and a build script build-opencv-desktop-image.sh that specifies build arguments. build-opencv-desktop-image.sh lets you configure build arguments and then build the Docker image, thereby enabling the customization of your Docker container.

Dockerfile Overview

The full Dockerfile contains many instructions which are explained in detail later. This file can be altered based on your requirement.

1# Build arguments
2ARG UBUNTU_RELEASE_YEAR
3ARG ZED_SDK_MAJOR
4ARG ZED_SDK_MINOR
5ARG CUDA_MAJOR
6ARG CUDA_MINOR
7
8# Specify the parent image from which we build
9FROM stereolabs/zed:${ZED_SDK_MAJOR}.${ZED_SDK_MINOR}-gl-devel-cuda${CUDA_MAJOR}.${CUDA_MINOR}-ubuntu${UBUNTU_RELEASE_YEAR}.04
10
11# OpenCV Version
12ARG OPENCV_VERSION
13
14# Install dependencies
15RUN apt-get update || true && apt-get upgrade -y &&\
16 # Install build tools, build dependencies and python
17 apt-get install --no-install-recommends -y \
18 build-essential gcc g++ \
19 cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev \
20 libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev \
21 yasm libatlas-base-dev gfortran libpq-dev \
22 libxine2-dev libglew-dev libtiff5-dev zlib1g-dev libavutil-dev libpostproc-dev \
23 libeigen3-dev python3-dev python3-pip python3-numpy libx11-dev tzdata \
24&& rm -rf /var/lib/apt/lists/*
25
26# Set Working directory
27WORKDIR /opt
28
29
30# Install OpenCV from Source
31RUN git clone --depth 1 --branch ${OPENCV_VERSION} https://github.com/opencv/opencv.git && \
32 git clone --depth 1 --branch ${OPENCV_VERSION} https://github.com/opencv/opencv_contrib.git && \
33 cd opencv && \
34 mkdir build && \
35 cd build && \
36 cmake \
37 -D CMAKE_BUILD_TYPE=RELEASE \
38 -D CMAKE_INSTALL_PREFIX=/usr/ \
39 -D PYTHON3_PACKAGES_PATH=/usr/lib/python3/dist-packages \
40 -D WITH_V4L=ON \
41 -D WITH_QT=OFF \
42 -D WITH_OPENGL=ON \
43 -D WITH_GSTREAMER=ON \
44 -D OPENCV_GENERATE_PKGCONFIG=ON \
45 -D OPENCV_ENABLE_NONFREE=ON \
46 -D OPENCV_EXTRA_MODULES_PATH=/opt/opencv_contrib/modules \
47 -D INSTALL_PYTHON_EXAMPLES=OFF \
48 -D INSTALL_C_EXAMPLES=OFF \
49 -D BUILD_EXAMPLES=OFF .. && \
50 make -j"$(nproc)" && \
51 make install
52
53# ALternatively, Install from Ubuntu Repository
54###
55#RUN apt-get update -y || true && \
56# DEBIAN_FRONTEND=noninteractive apt-get install -y && \
57# apt-get install -y --no-install-recommends libopencv-dev && \
58# rm -rf /var/lib/apt/lists/* && apt autoremove && apt clean
59###
60
61WORKDIR /
62
63 CMD ["bash"]

Below is the analysis of the main parts that compose the Dockerfile.

Specify the parent image

First, specify a base ZED SDK docker image from which you want to build the new image. These images come with ZED SDK pre-installed and let you use the ZED camera with SDK applications.

There are multiple Docker images available with different Ubuntu release years, SDK and CUDA versions. Hence, we first choose a specific ZED SDK Docker image as a parent image by configuring the arguments.

The Ubuntu release year, SDK and CUDA versions are passed as arguments during the build stage making it modular. Assigning these arguments with the version of your choice will be discussed in a later section.

1# Build arguments
2ARG UBUNTU_RELEASE_YEAR
3ARG ZED_SDK_MAJOR
4ARG ZED_SDK_MINOR
5ARG CUDA_MAJOR
6ARG CUDA_MINOR
7
8# Specify the parent image from which we build
9FROM stereolabs/zed:${ZED_SDK_MAJOR}.${ZED_SDK_MINOR}-gl-devel-cuda${CUDA_MAJOR}.${CUDA_MINOR}-ubuntu${UBUNTU_RELEASE_YEAR}.04

Based on the arguments specified in the build script a specific base image will be imported, for example, if the build arguments in build-opencv-ubuntu-image.sh are set to values mentioned below:

1UBUNTU_RELEASE_YEAR=20
2ZED_SDK_MAJOR=3
3ZED_SDK_MINOR=7
4CUDA_MAJOR=11
5CUDA_MINOR=4

Then the base image will be stereolabs/zed:3.7-gl-devel-cuda11.4-ubuntu20.04

Note that the base image is chosen such that it already consists of OpenGL support for display, if you wish to not have it you can follow the section below to build image without display support.

Meanwhile, you can also explore the StereoLabs DockerHub repository that contains official ZED SDK Docker images.

Install dependencies

Once you have specified the parent image you can go ahead and decide which OpenCV version to be installed. Be careful to check the version availability and compatibility.

This part of the Dockerfile installs all the OpenCV dependencies.

1# OpenCV Version
2ARG OPENCV_VERSION
3
4# Install dependencies
5RUN apt-get update || true && apt-get upgrade -y &&\
6 # Install build tools, build dependencies and python
7 apt-get install --no-install-recommends -y \
8 build-essential gcc g++ \
9 cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev \
10 libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev \
11 yasm libatlas-base-dev gfortran libpq-dev \
12 libxine2-dev libglew-dev libtiff5-dev zlib1g-dev libavutil-dev libpostproc-dev \
13 libeigen3-dev python3-dev python3-pip python3-numpy libx11-dev tzdata \
14&& rm -rf /var/lib/apt/lists/*

In the next stage, you install OpenCV, this can be achieved in two methods and both of them are explained below.

Method 1: Install OpenCV from the source

This section downloads the OpenCV source files of the chosen version and builds it.

1# Install OpenCV from Source
2RUN git clone --depth 1 --branch ${OPENCV_VERSION} https://github.com/opencv/opencv.git && \
3 git clone --depth 1 --branch ${OPENCV_VERSION} https://github.com/opencv/opencv_contrib.git && \
4 cd opencv && \
5 mkdir build && \
6 cd build && \
7 cmake \
8 -D CMAKE_BUILD_TYPE=RELEASE \
9 -D CMAKE_INSTALL_PREFIX=/usr/ \
10 -D PYTHON3_PACKAGES_PATH=/usr/lib/python3/dist-packages \
11 -D WITH_V4L=ON \
12 -D WITH_QT=OFF \
13 -D WITH_OPENGL=ON \
14 -D WITH_GSTREAMER=ON \
15 -D OPENCV_GENERATE_PKGCONFIG=ON \
16 -D OPENCV_ENABLE_NONFREE=ON \
17 -D OPENCV_EXTRA_MODULES_PATH=/opt/opencv_contrib/modules \
18 -D INSTALL_PYTHON_EXAMPLES=OFF \
19 -D INSTALL_C_EXAMPLES=OFF \
20 -D BUILD_EXAMPLES=OFF .. && \
21 make -j"$(nproc)" && \
22 make install

Make sure you eliminate this section if you choose to use the 2nd method

Method 2: Install OpenCV using the Ubuntu repository

Alternatively, you can simply install OpenCV from the Ubuntu repository.

1RUN apt-get update -y || true && \
2DEBIAN_FRONTEND=noninteractive apt-get install -y tzdata libx11-dev && \
3apt-get install -y --no-install-recommends libopencv-dev && \
4 rm -rf /var/lib/apt/lists/* && apt autoremove && apt clean

Although this method is a much simpler and easier method to install OpenCV that makes your image lighter, building OpenCV from the source allows you to have the latest available version, flexibility and complete control over the build options.

Choose the method that is appropriate for you.

Build Script Overview

As mentioned above the Docker images can be customized to various available versions and the build-opencv-ubuntu-image.sh script lets you configure the versions which are passed during the build and also creates the Docker image using docker build command.

The script is detailed in this section below.

Configure the arguments

Specify the Ubuntu release year, ZED SDK CUDA and OpenCV versions. Here can see the default values set in the script, you should edit it to the version you want. These arguments are later passed as --build-arg during the build.

$UBUNTU_RELEASE_YEAR=20 #Specify the Ubuntu release year
$ZED_SDK_MAJOR=3 # ZED SDK major version
$ZED_SDK_MINOR=7 # ZED SDK minor version
$CUDA_MAJOR=11 # CUDA major version
$CUDA_MINOR=4 # CUDA minor version
$OPENCV_VERSION=4.5.3 # OpenCV version

Check for the version compatibility

This section of the script checks the arguments you have entered in the above section and examines compatibility between different versions. In case of invalid entry, it exits the build.

$#Check for the version compatibilities
$
$if [ ${UBUNTU_RELEASE_YEAR} == "18" ] ; then
$echo "Ubuntu 18.04"
$# Not compatible with CUDA <= 9
$if [ ${CUDA_MAJOR} -le "9" ] ; then
$ echo "Ubuntu 18.04 Not compatible with CUDA <= 9"
$ exit
$fi
$elif [ ${UBUNTU_RELEASE_YEAR} == "20" ] ; then
$# Not compatible with CUDA <= 10
$if [ ${CUDA_MAJOR} -le "10" ] ; then
$ echo "Ubuntu 20.04 is not compatible with CUDA <= 10 "
$ exit
$fi
$else
$ echo "UBUNTU_RELEASE_YEAR! Allowed values are 18 or 20 "
$ exit
$fi
$
$if [ ${CUDA_MAJOR} -ge "11" ] ; then
$if [ ${ZED_SDK_MINOR} -lt "2" ] ; then # CUDA 11.0 was introduced with 3.2
$ echo "CUDA 11.0 was introduced with 3.2"
$ exit
$fi
$if [ ${CUDA_MINOR} -ge "1" ] ; then
$ if [ ${ZED_SDK_MINOR} -lt "3" ] ; then # CUDA 11.1 was introduced with 3.3
$ echo "CUDA 11.1 was introduced with 3.3"
$ exit
$ fi
$fi
$if [ ${CUDA_MINOR} == "2" ] || [ ${CUDA_MINOR} == "3" ] || [ ${CUDA_MINOR} -ge "6" ] ; then
$ #invalid CUDA versions
$ echo "Invalid CUDA_MINOR! Allowed values : 0,1,4,5"
$ exit
$fi
$
$elif [ ${CUDA_MAJOR} == "10" ] ; then
$ if [ ${CUDA_MINOR} != "0" ] || [ ${CUDA_MINOR} != "2" ] ; then
$ echo "Invalid CUDA_MINOR! Allowed values are 0 or 2"
$ exit
$ fi
$else
$ echo "Invalid CUDA_MAJOR! Allowed values are 10 or 11"
$fi

Docker build

The below part of the script assigns a default tag to the docker image that is to be created based on the chosen arguments and builds the Docker container.

$# Default Tag based on the selected versions
$TAG="${ZED_SDK_MAJOR}.${ZED_SDK_MINOR}-opencv-gl-devel-cuda${CUDA_MAJOR}.${CUDA_MINOR}-ubuntu${UBUNTU_RELEASE_YEAR}.04"
$ echo "Building '${TAG}'"
$
$docker build --build-arg UBUNTU_RELEASE_YEAR=${UBUNTU_RELEASE_YEAR} \
>--build-arg ZED_SDK_MAJOR=${ZED_SDK_MAJOR} \
>--build-arg ZED_SDK_MINOR=${ZED_SDK_MINOR} \
>--build-arg OPENCV_VERSION=${OPENCV_VERSION} \
>--build-arg CUDA_MAJOR=${CUDA_MAJOR} \
>--build-arg CUDA_MINOR=${CUDA_MINOR} \
>-t "${TAG}" -f Dockerilfe.opencv .
$

Create your Docker Image with OpenCV

Now that you are familiar with the Dockerfile and the build-opencv-desktop-image.sh it’s time to create your image. Download the files from this link, edit the arguments to your desired version and simply run the script to create the Docker image

$./build-opencv-ubuntu-image.sh

That’s it! You can now change versions and create your own docker containers by just manipulating the arguments. Go ahead and test your images and host them as mentioned in this tutorial.

Docker Image without display support

Display window is an integral part of most OpenCV applications. However, Docker is mainly intended to run command-line applications and the addition of a display window is possible only in containers with OpenGL support.

By eliminating the inclusion of OpenGL we can make the docker images much lighter and besides it eliminates the need for all the dependencies required to include display support. Below are a few ways how it can be achieved.

Choose a parent docker image without OpenGL support which can be simply made by changing the Parent image tag as follows

1FROM stereolabs/zed:${ZED_SDK_MAJOR}.${ZED_SDK_MINOR}-devel-cuda${CUDA_MAJOR}.${CUDA_MINOR}-ubuntu${UBUNTU_RELEASE_YEAR}.04

You can read more about image-specific tags on Stereolab’s DockerHub page.

  • In the applications, the output image window can be saved instead of displayed. Below is the code snippet from zed-opencv sample that uses the ENABLE_DISPLAY flag to either display the image or save it as a video.
C++
1#define ENABLE_DISPLAY 1
2#if ENABLE_DISPLAY
3 cv::imshow("Image", image_ocv);
4 #ifdef HAVE_CUDA
5 // download the Ocv GPU data from Device to Host to be displayed
6 depth_image_ocv_gpu.download(depth_image_ocv);
7 #endif
8 cv::imshow("Depth", depth_image_ocv);
9#else
10 //Save Image and Depth video if the Display is disabled
11 cv::VideoWriter video_image("../Image.avi", cv::VideoWriter::fourcc('M','J','P','G'), 10, cv::Size(new_width,new_height));
12 video_image.write(image_ocv);
13 #ifdef HAVE_CUDA
14 // download the Ocv GPU data from Device to Host to be displayed
15 depth_image_ocv_gpu.download(depth_image_ocv);
16 #endif
17 cv::VideoWriter video_depth("../Depth.avi", cv::VideoWriter::fourcc('M','J','P','G'), 10, cv::Size(new_width,new_height));
18 video_depth.write(depth_image_ocv); // Display image and depth using cv:Mat which share sl:Mat data
19 //std::cout<<"The key: "<<key<<std::endl;
20#endif

Please refer to zed-opencv GitHub repository for the complete code.