Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run OpenCv in jupyter with Docker

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
like image 993
TheMeaningfulEngineer Avatar asked Mar 13 '23 12:03

TheMeaningfulEngineer


1 Answers

There are two possible solutions:

  1. 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 system
  2. If 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.

like image 104
morxa Avatar answered Mar 16 '23 03:03

morxa