I would like to make an easily runnable jupyter notebook that supports OpenCV and is delivered as a Docker image.
The concept is to have a docker container running the jupyter kernel and accessing the notebook through the browser in the host. Something similar to this.
However, the issue is that OpenCV seems to be dependent on a running Gtk environment.So trying to run the following code:
import numpy as np
import cv2
img = cv2.imread('pendulum.png',0)
cv2.imshow('image',img)
Results in jupyter kernel crashing with:
(image:603): Gtk-WARNING **: cannot open display:
[I 15:23:49.808 NotebookApp] KernelRestarter: restarting kernel (1/5)
Is there a way to bypass this dependency and have OpenCV running in a docker container show images in the browser of the host system ?
Steps to reproduce the issue:
Dockerfile:
FROM ubuntu:16.04
RUN apt-get update
RUN apt-get update --fix-missing && apt-get install -y wget bzip2 ca-certificates \
libglib2.0-0 libxext6 libsm6 libxrender1 \
git mercurial subversion
RUN echo 'export PATH=/opt/conda/bin:$PATH' > /etc/profile.d/conda.sh && \
wget --quiet https://repo.continuum.io/archive/Anaconda3-4.0.0-Linux-x86_64.sh && \
/bin/bash /Anaconda3-4.0.0-Linux-x86_64.sh -b -p /opt/conda && \
rm /Anaconda3-4.0.0-Linux-x86_64.sh
ENV PATH /opt/conda/bin:$PATH
RUN conda install -y -c https://conda.binstar.org/menpo opencv3
RUN apt-get install -y libgomp1
RUN apt-get install -y libgtk2.0-0 x11-xserver-utils libcanberra-gtk3-module
RUN mkdir /home/user
RUN groupadd -r user -g 777 && \
useradd -u 431 -r -g user -d /home/user -s /sbin/nologin -c "Docker image user" user
RUN apt-get install -y libcanberra-gtk*
RUN chown -R user:user /home/user
USER user
WORKDIR /home/user
Commands to execute:
docker build -t opencv-play .
docker run -v /home/user/.Xauthority:/home/user/.Xauthority -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=unix$DISPLAY -u user -v `pwd`:/home/user -p 8008:8008 -t -i opencv-play
jupyter notebook --ip='*' --no-browser --port=8008 #Inside the container
#Open the browser, URL-> http://localhost:8008
#Run the above code in jupyter
There are two possible solutions:
Allow your container to access your local XServer. This will show all graphical output as if you ran the software directly on the host instead of in a Docker container. In order to do this, you need to set the DISPLAY
environment variable and you need to pass the X11 socket to the container. In your example, you would:
$ docker run -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY -v `pwd`:/home/workspace -p 8008:8008 -t -i opencv-play
-v /tmp/.X11-unix:/tmp/.X11-unix
passes the X11 socket to the container-e DISPLAY=$DISPLAY
sets the display environment variable to the one on your host systemIf you don't need the graphical output, you can run a 'fake' X server that doesn't show any output. Xvfb
is such a display server that doesn't need any access to a monitor. In order to use it, you would need to install Xvfb
in your image, i.e. add apt-get install xvfb
to your Dockerfile. Then, when you run the container, you first need to start xvfb and set DISPLAY
accordingly. I usually do this with a small script that then starts your command, e.g.
#!/bin/bash
export DISPLAY=0:0
Xvfb $DISPLAY &
jupyter notebook --ip='*' --no-browser --port=8008
This starts Xvfb in the background and then starts jupyter, which passes all graphical output to the Xvfb display server on 0:0
. Add this script to the image and then run it in the following way:
docker run -v `pwd`:/home/workspace -p 8008:8008 -t -i opencv-play /path/to/the/script
Note that you do not need to pass DISPLAY
to the container.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With