Create Docker images for ZED and OpenCV

Open in ClaudeOpen in ChatGPT

We have already seen how to create a Docker image. In this section, we follow the same recommended workflow with a few changes, so we strongly recommend going through that tutorial first to refresh your memory before continuing here.

The Dockerfile and build script below come from a community example and were written for older ZED SDK, Ubuntu, and CUDA versions (the compatibility check only allows Ubuntu 18.04 / 20.04 and CUDA 10 / 11). Use them to understand the workflow, then adapt the versions to your needs. The latest ZED SDK is v5.4.0, which uses CUDA 12.8 / 13.0 on Ubuntu 22.04 / 24.04. For officially maintained Dockerfiles and ready-to-use images, see the zed-docker GitHub repository and the StereoLabs DockerHub repository.

A generic Dockerfile skeleton is provided to assemble an image, along with a build script, build-opencv-desktop-image.sh, that specifies the build arguments. build-opencv-desktop-image.sh lets you configure the build arguments and then build the Docker image, allowing you to customize your container.

Dockerfile Overview

The full Dockerfile contains many instructions, explained in detail below. You can adapt this file to your requirements.

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 the 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 the 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
63CMD ["bash"]

Below is an analysis of the main parts that make up the Dockerfile.

Specify the parent image

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

There are many Docker images available with different Ubuntu release years and SDK and CUDA versions. We therefore choose a specific ZED SDK Docker image as the parent image by configuring the build arguments.

The Ubuntu release year and the SDK and CUDA versions are passed as arguments during the build stage, which keeps the Dockerfile modular. Setting these arguments to the version of your choice is covered 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 set in the build script, a specific base image is imported. For example, if the build arguments in build-opencv-desktop-image.sh are set to the values 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 this base image already includes OpenGL support for display. If you do not need it, follow the section below to build an image without display support.

You can also browse the StereoLabs DockerHub repository, which lists all the official ZED SDK Docker images.

Install dependencies

Once you have specified the parent image, you can choose which OpenCV version to install. Be sure to check 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 done in two ways, both explained below.

Method 1: Install OpenCV from source

This step downloads the OpenCV source files for the chosen version and builds them.

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 remove this section if you choose the second method.

Method 2: Install OpenCV from 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

This is a much simpler way to install OpenCV and produces a lighter image, but building OpenCV from source gives you the latest available version, more flexibility, and complete control over the build options.

Choose the method that best fits your needs.

Build Script Overview

As mentioned above, the Docker image can be built for various versions. The build-opencv-desktop-image.sh script lets you configure the versions passed during the build and then creates the image with the docker build command.

The script is detailed below.

Configure the arguments

Specify the Ubuntu release year and the ZED SDK, CUDA, and OpenCV versions. The default values set in the script are shown below; edit them to the versions you want. These arguments are later passed as --build-arg during the build.

$UBUNTU_RELEASE_YEAR=20 # 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 version compatibility

This part of the script validates the arguments you entered above and checks compatibility between the different versions. If an entry is invalid, the build is aborted.

$# Check for version compatibility
$
$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 part of the script below assigns a default tag to the image based on the chosen arguments and runs the build.

$# 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 Dockerfile.opencv .

Create your Docker Image with OpenCV

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

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

That’s it! You can now change versions and create your own Docker containers just by editing the arguments. Go ahead and test your images, then host them as described in this tutorial.

Docker Image without display support

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

By leaving out OpenGL, you can make the Docker images much lighter and remove the need for all the dependencies required for display support. There are a few ways to achieve this.

Choose a parent Docker image without OpenGL support by changing the parent image tag (drop the gl- prefix), 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 the image-specific tags on the StereoLabs DockerHub page.

  • In your application, the output image window can be saved instead of displayed. Below is a snippet from the 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 OpenCV 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 OpenCV 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 shares sl::Mat data
19 //std::cout<<"The key: "<<key<<std::endl;
20#endif

Refer to the zed-opencv GitHub repository for the complete code.