├── .gitignore ├── Dockerfile ├── nvidia-docker ├── readme.md ├── runme.sh └── webcamfaces.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.*~ 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nvidia/cuda:7.5-cudnn3-devel 2 | 3 | MAINTAINER Chip Garner 4 | 5 | RUN mkdir OpenCV && cd OpenCV 6 | 7 | RUN apt-get update && apt-get install -y \ 8 | build-essential \ 9 | checkinstall \ 10 | cmake \ 11 | pkg-config \ 12 | yasm \ 13 | libtiff5-dev \ 14 | libjpeg-dev \ 15 | libjasper-dev \ 16 | libavcodec-dev \ 17 | libavformat-dev \ 18 | libswscale-dev \ 19 | libdc1394-22-dev \ 20 | libxine-dev \ 21 | libgstreamer0.10-dev \ 22 | libgstreamer-plugins-base0.10-dev \ 23 | libv4l-dev \ 24 | python-dev \ 25 | python-numpy \ 26 | python-pip \ 27 | libtbb-dev \ 28 | libeigen3-dev \ 29 | libqt4-dev \ 30 | libgtk2.0-dev \ 31 | # Doesn't work libfaac-dev \ 32 | libmp3lame-dev \ 33 | libopencore-amrnb-dev \ 34 | libopencore-amrwb-dev \ 35 | libtheora-dev \ 36 | libvorbis-dev \ 37 | libxvidcore-dev \ 38 | x264 \ 39 | v4l-utils \ 40 | # Doesn't work ffmpeg \ 41 | libgtk2.0-dev \ 42 | # zlib1g-dev \ 43 | # libavcodec-dev \ 44 | unzip \ 45 | wget 46 | 47 | RUN cd /opt && \ 48 | wget https://github.com/Itseez/opencv/archive/3.1.0.zip -O opencv-3.1.0.zip -nv && \ 49 | unzip opencv-3.1.0.zip && \ 50 | cd opencv-3.1.0 && \ 51 | rm -rf build && \ 52 | mkdir build && \ 53 | cd build && \ 54 | cmake -D CUDA_ARCH_BIN=3.2 \ 55 | -D CUDA_ARCH_PTX=3.2 \ 56 | -D CMAKE_BUILD_TYPE=RELEASE \ 57 | -D CMAKE_INSTALL_PREFIX=/usr/local \ 58 | -D WITH_TBB=ON \ 59 | -D BUILD_NEW_PYTHON_SUPPORT=ON \ 60 | -D WITH_V4L=ON \ 61 | -D BUILD_TIFF=ON \ 62 | -D WITH_QT=ON \ 63 | # -D USE_GStreamer=ON \ 64 | -D WITH_OPENGL=ON .. && \ 65 | make -j4 && \ 66 | make install && \ 67 | echo "/usr/local/lib" | sudo tee -a /etc/ld.so.conf.d/opencv.conf && \ 68 | ldconfig 69 | ln /dev/null /dev/raw1394 70 | RUN cp /opt/opencv-3.1.0/build/lib/cv2.so /usr/lib/python2.7/dist-packages/cv2.so 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /nvidia-docker: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. 3 | 4 | DOCKER=${DOCKER:-"docker"} 5 | 6 | NV_DEVICE="/dev/nvidia" 7 | UVM_DEVICE="${NV_DEVICE}-uvm" 8 | CTL_DEVICE="${NV_DEVICE}ctl" 9 | 10 | CUDA_VERSION_LABEL="com.nvidia.cuda.version" 11 | 12 | NV_BINS_VOLUME="/usr/local/bin" 13 | NV_BINS="nvidia-cuda-mps-control \ 14 | nvidia-cuda-mps-server \ 15 | nvidia-debugdump \ 16 | nvidia-persistenced \ 17 | nvidia-smi" 18 | 19 | NV_LIBS_VOLUME="/usr/local/nvidia" 20 | NV_LIBS_CUDA="cuda \ 21 | nvcuvid \ 22 | nvidia-compiler \ 23 | nvidia-encode \ 24 | nvidia-ml" 25 | 26 | NV_DOCKER_ARGS="" 27 | 28 | __log() 29 | { 30 | local level="$1" 31 | local msg="$2" 32 | 33 | printf "[ NVIDIA ] =$level= $msg\n" >&2 34 | } 35 | 36 | __image_label() 37 | { 38 | local image="$1" 39 | local label="$2" 40 | 41 | echo $( $DOCKER inspect --format="{{index .Config.Labels \"$label\"}}" $image ) 42 | } 43 | 44 | __nvsmi_query() 45 | { 46 | local section="$1" 47 | local gpu_id="$2" # optional 48 | local cmd="nvidia-smi -q" 49 | 50 | if [ $# -eq 2 ]; then 51 | cmd="$cmd -i $gpu_id" 52 | fi 53 | echo $( $cmd | grep "$section" | awk '{print $4}' ) 54 | } 55 | 56 | __library_paths() 57 | { 58 | local lib="$1" 59 | 60 | echo $( ldconfig -p | grep "lib${lib}.so" | awk '{print $4}' ) 61 | } 62 | 63 | __library_arch() 64 | { 65 | local lib="$1" 66 | 67 | echo $( file -L $lib | awk '{print $3}' | cut -d- -f1 ) 68 | } 69 | 70 | __filter_duplicate_paths() 71 | { 72 | local paths="$1" 73 | 74 | local sums="$( md5sum $paths | sed 's/[^/]*$/ &/' )" 75 | local uniq="$( echo "$sums" | uniq -u -f2 | awk '{print $2$3}')" 76 | local dupl="$( echo "$sums" | uniq --all-repeated=separate -f2 \ 77 | | uniq -w 32 | awk 'NF {print $2$3}')" 78 | echo $uniq $dupl 79 | } 80 | 81 | check_prerequisites() 82 | { 83 | local cmds="nvidia-smi nvidia-modprobe" 84 | 85 | for cmd in $cmds; do 86 | command -v $cmd >/dev/null && continue 87 | __log ERROR "Command not found: $cmd" 88 | exit 1 89 | done 90 | } 91 | 92 | parse_docker_args() 93 | { 94 | local args="$1" 95 | local help="$2" 96 | 97 | local shift=1 98 | local skip=0 99 | local non_bool_args="$( $DOCKER help $help | \ 100 | sed '/^\s*\(-[^=]\+\)=[^{true}{false}].*/!d;s//\1/;s/, /\n/' )" 101 | 102 | for arg in $args; do 103 | test $skip -eq 1 && skip=0 && continue 104 | case $arg in 105 | -*) 106 | for nb_arg in $non_bool_args; do 107 | test $arg = $nb_arg && skip=1 && break 108 | done 109 | shift=$((shift+$skip+1)) ;; 110 | *) 111 | return $shift ;; 112 | esac 113 | done 114 | return 0 115 | } 116 | 117 | check_image_version() 118 | { 119 | local image="$1" 120 | local driver_version="$( __nvsmi_query "Driver Version" )" 121 | local cuda_image_version="$( __image_label $image $CUDA_VERSION_LABEL )" 122 | 123 | if [ -z $cuda_image_version ]; then 124 | __log INFO "Not a CUDA image, nothing to be done" 125 | return 1 126 | fi 127 | __log INFO "Driver version: $driver_version" 128 | __log INFO "CUDA image version: $cuda_image_version" 129 | return 0 130 | } 131 | 132 | load_uvm() 133 | { 134 | if [ ! -e $UVM_DEVICE ]; then 135 | nvidia-modprobe -u -c=0 136 | fi 137 | } 138 | 139 | build_docker_args() 140 | { 141 | local args="--device=$CTL_DEVICE --device=$UVM_DEVICE" 142 | 143 | for gpu in $( echo $GPU | tr -s ", " " " ); do 144 | local minor="$( __nvsmi_query "Minor Number" $gpu )" 145 | if [ -z $minor ]; then 146 | __log WARN "Could not find GPU device: $gpu" 147 | continue 148 | fi 149 | args="$args --device=${NV_DEVICE}$minor" 150 | done 151 | 152 | for lib in $NV_LIBS_CUDA; do 153 | local paths="$( __library_paths $lib )" 154 | if [ -z "$paths" ]; then 155 | __log WARN "Could not find library: $lib" 156 | continue 157 | fi 158 | for path in $( __filter_duplicate_paths "$paths" ); do 159 | args="$args -v $path:$path" 160 | case $( __library_arch "$path" ) in 161 | 32) args="$args -v $path:$NV_LIBS_VOLUME/lib/$(basename $path)" ;; 162 | 64) args="$args -v $path:$NV_LIBS_VOLUME/lib64/$(basename $path)" ;; 163 | esac 164 | done 165 | done 166 | 167 | for bin in $NV_BINS; do 168 | local path="$( which $bin )" 169 | if [ -z $path ]; then 170 | __log WARN "Could not find binary: $bin" 171 | continue 172 | fi 173 | args="$args -v $path:$NV_BINS_VOLUME/$bin" 174 | done 175 | 176 | NV_DOCKER_ARGS=$args 177 | } 178 | 179 | print_debug() 180 | { 181 | if [ ! -z $NVDEBUG ]; then 182 | seq -s= 60 | tr -d '[:digit:]' 183 | echo $NV_DOCKER_ARGS | sed 's/-[-v][^/]*//g' | tr ' ' '\n' 184 | seq -s= 60 | tr -d '[:digit:]' 185 | fi 186 | } 187 | 188 | setup() 189 | { 190 | local image="$1" 191 | 192 | check_image_version $image 193 | if [ $? -eq 0 ]; then 194 | build_docker_args 195 | load_uvm 196 | print_debug >&2 197 | fi 198 | echo 199 | } 200 | 201 | check_prerequisites 202 | parse_docker_args "$*"; ret=$? 203 | 204 | DOCKER_ARGS="" 205 | CMD="$( eval echo \${$ret} )" 206 | 207 | i=0; while [ $i -lt $ret ]; do 208 | DOCKER_ARGS="$DOCKER_ARGS $1" 209 | i=$((i+1)) 210 | shift 211 | done 212 | 213 | case $CMD in 214 | run|create) 215 | parse_docker_args "$*" $CMD; ret=$? 216 | if [ $ret -gt 0 ]; then 217 | image="$( eval echo \${$ret} )" 218 | setup $image 219 | fi 220 | ;; 221 | esac 222 | 223 | $DOCKER $DOCKER_ARGS $NV_DOCKER_ARGS $@ 224 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | #Docker file for OpenCV with CUDA and a bash file example for using a webcam and display. 2 | 3 | ##Opencv 3.1.0 using nvidia-docker images for CUDA version 7.5 and cuDNN 3. Includes a Python 2.7 example using a webcam and face detection. Works with or without a GPU. 4 | 5 | The docker image is available on [Docker Hub](https://hub.docker.com/r/chipgarner/opencv3-webcam/). 6 | 7 | A sample run command is shown in [runme.sh](runme.sh) and listed below. This runs on Ubuntu 14.04, and probably on other linux flavors. 8 | 9 | xhost + 10 | 11 | GPU=0 ./nvidia-docker run --privileged --rm -it \ 12 | --env DISPLAY=$DISPLAY \ 13 | --env="QT_X11_NO_MITSHM=1" \ 14 | -v /dev/video0:/dev/video0 \ 15 | -v /tmp/.X11-unix:/tmp/.X11-unix:ro \ 16 | -v /home/jkg/PycharmProjects:/dev/projects \ 17 | chipgarner/opencv3-webcam:python2 bash 18 | 19 | xhost - 20 | 21 | These instructions require setting xhost + on the host machine. I could not get the camera to work without xhost +. It should be possible to enable access to only the docker container. If you are not using the camera you should be able to get the display working without xhost + using one of the methods explained [here](http://wiki.ros.org/docker/Tutorials/GUI). 22 | 23 | Additional GPU's can be listed e.g. GPU=0, GPU=1. The [nvidia-docker](nvidia-docker) script replaces the docker run command. If you do not have an Nvidia GPU leave off the GPU=0 and use the standard docker run statement instead of ./nvida-docker run. 24 | 25 | **--env DISPLAY=$DISPLAY** sends the display id from the host to the container. 26 | 27 | **--env="QT_X11_NO_MITSHM=1"** is required by OpenCV to show the display. 28 | 29 | **-v /dev/video0:/dev/video0** This lets the container find the camera. 30 | 31 | **-v /tmp/.X11-unix:/tmp/.X11-unix:ro** This lets the container find the display via X server. 32 | 33 | **-v /home/jkg/PycharmProjects:/dev/projects** I use this for development. This is a possibly useful example of using "volume" to make a directory on the host available in the container. Delete it or point it to your own directories. 34 | 35 | **chipgarner/opencv3-webcam:python2 bash** Part of the normal docker run command to start a container with a terminal running. Your image will have the same name if you pulled it from [Docker Hub](https://hub.docker.com/r/chipgarner/opencv3-webcam/). 36 | 37 | **webacmfaces.py** is a small script that might be useful for testing that everything is working. It should run as is in the container. It prints the OpenCV version, prints the frame rate, and outlines any faces in front of the camera. It uses the GPU and multiple CPUs. 38 | 39 | ##Buliding the image from the Dockerfile. 40 | 41 | ###Pick your GPU/CUDA configuration: 42 | 43 | If you have an Nvidia GPU and want to use CUDA, see [nvidia-docker on GitHub](https://github.com/NVIDIA/nvidia-docker) for instructions for creating the CUDA and cuDNN images. I am using this with Caffe for training and running neural networks and it is faster with [CUDA](https://developer.nvidia.com/cuda-zone) and [cuDNN](https://developer.nvidia.com/cudnn). OpenCV 3.1.0 is faster with CUDA enabled (if you have one or more CUDA enabled GPUs), but cuDNN is not useful unless you are working with neural networks. The resulting image is smaller without the Nvidia images but most of the 7.6 GB is from OpenCV, and the full image will run without a GPU. 44 | 45 | You can build the image using cuDNN and CUDA, using just CUDA or using neither if you do not have an NVIDIA GPU. As of early January 2016, the [Nvidia site](https://github.com/NVIDIA/nvidia-docker) says "Currently, only cuDNN v2 based on CUDA 7.0 is supported", however cuDNN v3 and CUDA 7.5 Dockerfiles are there and work well. cuDNN is built from CUDA, and you will need the development (devel) versions in both cases. 46 | 47 | ###Modify the Dockerfile: 48 | 49 | Modify the Dockerfile FROM to use the appropriate image: 50 | **FROM cuda:7.5-cudnn3-devel** (or whatever you called it) for cuDNN or, 51 | **FROM cudnn3:latest** (your name for just CUDA without cuDNN) for CUDA 0r, 52 | **FROM ubuntu:14.04** for no CUDA GPU support. 53 | 54 | Modify **make -j4** on line 65, the four should be the number of cores you have and wish to use for the make. 55 | 56 | ### Run the [docker build](https://docs.docker.com/engine/reference/commandline/build/) command: 57 | 58 | For example: 59 | sudo docker build -t image-name:image-tag . 60 | 61 | -------------------------------------------------------------------------------- /runme.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | xhost + 4 | 5 | GPU=0 ./nvidia-docker run --privileged --rm -it \ 6 | --env DISPLAY=$DISPLAY \ 7 | --env="QT_X11_NO_MITSHM=1" \ 8 | -v /dev/video0:/dev/video0 \ 9 | -v /tmp/.X11-unix:/tmp/.X11-unix:ro \ 10 | -v /home/jkg/PycharmProjects:/dev/projects \ 11 | chipgarner/opencv3-webcam:python2 bash 12 | 13 | xhost - 14 | -------------------------------------------------------------------------------- /webcamfaces.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | video_capture = cv2.VideoCapture(0) 4 | if not video_capture.isOpened(): 5 | print('No video camera found') 6 | exit() 7 | 8 | # Uncomment the "..FULLSCREEN" calls and comment out "..AUTOSIZE" to display full screen 9 | # Mouse click on the screen and hit q to exit 10 | # cv2.namedWindow("Video", cv2.WND_PROP_FULLSCREEN) 11 | # cv2.setWindowProperty("Video", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN) 12 | cv2.namedWindow("Video", cv2.WND_PROP_AUTOSIZE) 13 | cv2.setWindowProperty("Video", cv2.WND_PROP_AUTOSIZE, cv2.WINDOW_AUTOSIZE) 14 | 15 | print("OpenCV version : {0}".format(cv2.__version__)) 16 | 17 | t = cv2.getTickCount() 18 | t_count = 0.0 19 | t_sum = 0.0 20 | 21 | 22 | faceCascade = cv2.CascadeClassifier('/opt/opencv-3.1.0/data/haarcascades_cuda/haarcascade_frontalface_default.xml') 23 | 24 | 25 | def get_faces(frm): 26 | # Gray scale image for the face detector, shrink it to make it faster 27 | gray = cv2.cvtColor(frm, cv2.COLOR_BGR2GRAY) 28 | image_scale = 3 29 | scl = 1.0 / image_scale 30 | smallgray = cv2.resize(gray, (0, 0), fx=scl, fy=scl) 31 | faces = faceCascade.detectMultiScale( 32 | smallgray, 33 | scaleFactor=1.1, 34 | minNeighbors=3, 35 | minSize=(10, 10), 36 | flags=cv2.CASCADE_SCALE_IMAGE 37 | ) 38 | # Draw andy face rectangles on the full size image 39 | for (x, y, w, h) in faces: 40 | x1 = int(x * image_scale) 41 | x2 = int((x + w) * image_scale) 42 | y1 = int(y * image_scale) 43 | y2 = int((y + h) * image_scale) 44 | cv2.rectangle(frm, (x1, y1), (x2, y2), (0, 0, 255), 2) 45 | 46 | return frm 47 | 48 | while True: 49 | 50 | t = cv2.getTickCount() 51 | t_count += 1.0 52 | 53 | # Capture frame-by-frame 54 | ret, frame = video_capture.read() 55 | 56 | cv2.imshow('Video', get_faces(frame)) 57 | 58 | # Calculate and print the frame rate every 10 frames. 59 | t_sum += cv2.getTickFrequency() / (cv2.getTickCount() - t) 60 | if t_count > 9: 61 | print(t_sum / t_count) 62 | t_count = 0.0 63 | t_sum = 0.0 64 | 65 | # OpenCV won't display anything until it hits the waitkey() function. 66 | # Press q to exit the program 67 | if cv2.waitKey(1) & 0xFF == ord('q'): 68 | break 69 | 70 | # When finished release the capture and window 71 | video_capture.release() 72 | cv2.destroyAllWindows() 73 | --------------------------------------------------------------------------------