Maman dort tranquillement la nuit - nous collectons OpenCV pour Raspbian'a

Les deux dernières semaines ont été difficiles pour notre équipe. OpenCV 4 est sorti , et avec lui, ils se sont préparés pour la boîte à outils Intel OpenVINO R4, qui comprend OpenCV. Vous pensez, je suis distrait pendant un certain temps, je vais regarder, comme d'habitude, sur les forums OpenCV et les commentaires des utilisateurs, et ici, il est devenu à la mode pour vous de dire que OpenCV n'est pas l'IoT, que sous Raspberry Pi, il suffit d'assembler - il n'y a pas assez de soudure pour mettre make -j2 - le matin, il sera prêt si vous avez de la chance.


Par conséquent, je propose de travailler ensemble et de voir comment assembler la bibliothèque OpenCV pour un système d'exploitation 32 bits fonctionnant sur un processeur ARM en utilisant les ressources d'une machine avec un système d'exploitation 64 bits, piloté par une excellente architecture CPU. Sorcellerie Compilation croisée, pas autrement!


Énoncé du problème


Compiler directement sur la carte, communément appelée native, est vraiment laborieux, nous allons donc ici envisager un moyen de construire un projet qui permet à des appareils informatiques plus puissants (appelons-les hôtes) de préparer des binaires pour leurs petits parents. De plus, les deux machines peuvent avoir des architectures CPU différentes. Il s'agit d'une compilation croisée.


Donc, pour préparer une tarte aux framboises farcie avec OpenCV, nous avons besoin de:


  • Ubuntu 16.04 carcasse image docker
  • La machine hôte est plus puissante que le Raspberry Pi (sinon, à quoi ça sert, non?)
  • Cross-compilateur pour ARMhf, ainsi que des bibliothèques de l'architecture correspondante

L'ensemble du processus de création d'OpenCV se déroulera sur la machine hôte. J'utilise Ubuntu à la maison. Avec une autre version de Linux, aucun problème de lecture ne devrait se produire. Pour les utilisateurs de Windows - je souhaite sincèrement ne pas abandonner et essayer de le découvrir par nous-mêmes.


Installer Docker


J'ai commencé ma connaissance de Docker il y a environ une semaine, alors ajoutez du sel gourmet et du sucre syntaxique au goût. Trois ingrédients suffisent pour vous et moi - Dockerfile, le concept d'image et de conteneur.


Docker lui-même est un outil pour créer et reproduire la configuration de n'importe quel système d'exploitation avec l'ensemble de composants nécessaire. Dockerfile est un ensemble de commandes shell que vous utilisez généralement sur la machine hôte, mais dans ce cas, elles s'appliquent toutes à la soi-disant image docker .


Pour installer docker, considérez la manière la plus simple: commandez un paquet via le service de livraison apt-get :


 sudo apt-get install -y docker.io 

Nous donnerons au démon docker tout ce qu'il demandera et nous ferons la déconnexion du système (notez la connexion en conséquence).


 sudo usermod -a -G docker $USER 

Préparation de l'espace de travail


Raspberry Pi (dans mon cas RPI 2 Model B) dans la préparation la plus courante est un processeur ARMv7 avec le système d'exploitation Raspbian (basé sur Debian). Nous allons créer une image docker basée sur Ubuntu 16.04, dans laquelle nous signalerons le compilateur croisé, les bibliothèques de l'armée et collecterons OpenCV au même endroit.


Créez un papa où Dockerfile notre Dockerfile :


 mkdir ubuntu16_armhf_opencv && cd ubuntu16_armhf_opencv touch Dockerfile 

Ajoutez des informations sur le système d'exploitation de base et l'architecture armhf pour le programme d'installation du package apt-get :


 FROM ubuntu:16.04 USER root RUN dpkg --add-architecture armhf RUN apt-get update 

Veuillez noter que les commandes comme FROM ... , RUN ... sont la syntaxe du docker et sont écrites dans le fichier de test Dockerfile créé.


Revenons au répertoire parent ubuntu16_armhf_opencv et essayons de créer notre image docker:


 docker image build ubuntu16_armhf_opencv 

Pendant l'exécution de la commande apt-get update , vous devriez être amené à voir des erreurs du type suivant: Err:[] [url] xenial[-] armhf Packages


 Ign:30 http://archive.ubuntu.com/ubuntu xenial-backports/main armhf Packages Ign:32 http://archive.ubuntu.com/ubuntu xenial-backports/universe armhf Packages Err:7 http://archive.ubuntu.com/ubuntu xenial/main armhf Packages 404 Not Found Ign:9 http://archive.ubuntu.com/ubuntu xenial/restricted armhf Packages Ign:18 http://archive.ubuntu.com/ubuntu xenial/universe armhf Packages Ign:20 http://archive.ubuntu.com/ubuntu xenial/multiverse armhf Packages Err:22 http://archive.ubuntu.com/ubuntu xenial-updates/main armhf Packages 404 Not Found Ign:24 http://archive.ubuntu.com/ubuntu xenial-updates/restricted armhf Packages Ign:26 http://archive.ubuntu.com/ubuntu xenial-updates/universe armhf Packages Ign:28 http://archive.ubuntu.com/ubuntu xenial-updates/multiverse armhf Packages Err:30 http://archive.ubuntu.com/ubuntu xenial-backports/main armhf Packages 404 Not Found Ign:32 http://archive.ubuntu.com/ubuntu xenial-backports/universe armhf Packages 

Si vous regardez le fichier /etc/apt/sources.list chacune de ces erreurs correspond à une ligne, par exemple:


Erreur


 Err:22 http://archive.ubuntu.com/ubuntu xenial-updates/main armhf Packages 404 Not Found 

Ligne dans /etc/apt/sources.list :


 deb http://archive.ubuntu.com/ubuntu/ xenial-updates main restricted 

Solution :
Divisez en deux:


 deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ xenial-updates main restricted deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted 

Ainsi, vous devez remplacer plusieurs sources de package. Dans notre docker, nous les remplacerons tous par une seule commande:


 RUN sed -i -E 's|^deb ([^ ]+) (.*)$|deb [arch=amd64] \1 \2\ndeb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ \2|' /etc/apt/sources.list 

La apt-get update devrait maintenant fonctionner sans erreur.


Nous mettons les packages nécessaires


Nous devons fournir des packages hôtes tels que git , python-pip , cmake et pkg-config , ainsi que crossbuild-essential-armhf , qui est un ensemble de compilateurs croisés gcc / g ++ ( arm-linux-gnueabihf-gcc et arm-linux-gnueabihf-g++ ) et les bibliothèques système de l'architecture correspondante:


 RUN apt-get install -y git python-pip cmake pkg-config crossbuild-essential-armhf 

De l'inhabituel - nous téléchargeons également GTK (utilisé pour dessiner des fenêtres dans le module highgui), GStreamer et Python, mais avec une indication explicite d'une architecture étrangère:


 RUN apt-get install -y --no-install-recommends \ libgtk2.0-dev:armhf \ libpython-dev:armhf \ libgstreamer1.0-dev:armhf \ libgstreamer-plugins-base1.0-dev:armhf \ libgstreamer-plugins-good1.0-dev:armhf \ libgstreamer-plugins-bad1.0-dev:armhf 

Et puis nous clonons et collectons, indiquant les drapeaux nécessaires:


 RUN git clone https://github.com/opencv/opencv --depth 1 RUN mkdir opencv/build && cd opencv/build && \ export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig && \ cmake -DCMAKE_BUILD_TYPE=Release \ -DOPENCV_CONFIG_INSTALL_PATH="cmake" \ -DCMAKE_TOOLCHAIN_FILE="../opencv/platforms/linux/arm-gnueabi.toolchain.cmake" \ -DWITH_IPP=OFF \ -DBUILD_TESTS=OFF \ -DBUILD_PERF_TESTS=OFF \ -DOPENCV_ENABLE_PKG_CONFIG=ON \ -DPYTHON2_INCLUDE_PATH="/usr/include/python2.7" \ -DPYTHON2_NUMPY_INCLUDE_DIRS="/usr/local/lib/python2.7/dist-packages/numpy/core/include" \ -DENABLE_NEON=ON \ -DCPU_BASELINE="NEON" .. 


  • CMAKE_TOOLCHAIN_FILE - le chemin d'accès au fichier cmake qui définit le processus de compilation croisée (définit le compilateur souhaité, restreint l'utilisation des bibliothèques hôtes.


  • WITH_IPP=OFF , - désactive les fortes dépendances.


  • BUILD_TESTS=OFF , BUILD_PERF_TESTS=OFF , désactivez la version de test.


  • OPENCV_ENABLE_PKG_CONFIG=ON - pour que pkg-config puisse trouver des dépendances comme GTK. PKG_CONFIG_PATH est le chemin correct où pkg-config recherchera les bibliothèques.


  • PYTHON2_INCLUDE_PATH , PYTHON2_NUMPY_INCLUDE_DIRS - chemins requis pour les wrappers de compilation croisée pour python2.


  • ENABLE_NEON=ON , CPU_BASELINE="NEON" - active l'optimisation NEON.


  • OPENCV_CONFIG_INSTALL_PATH - ajuste l'emplacement des fichiers dans le répertoire d' install .



La principale chose à laquelle vous devez faire attention après l'exécution de cmake est que tous les modules nécessaires sont assemblés (python2, par exemple):


 -- OpenCV modules: -- To be built: calib3d core dnn features2d flann gapi highgui imgcodecs imgproc java_bindings_generator ml objdetect photo python2 python_bindings_generator stitching ts video videoio -- Disabled: world -- Disabled by dependency: - -- Unavailable: java js python3 -- Applications: tests perf_tests apps -- Documentation: NO -- Non-free algorithms: NO 

et les dépendances nécessaires, telles que GTK, ont été trouvées:


 -- GUI: -- GTK+: YES (ver 2.24.30) -- GThread : YES (ver 2.48.2) -- GtkGlExt: NO -- -- Video I/O: -- GStreamer: -- base: YES (ver 1.8.3) -- video: YES (ver 1.8.3) -- app: YES (ver 1.8.3) -- riff: YES (ver 1.8.3) -- pbutils: YES (ver 1.8.3) -- v4l/v4l2: linux/videodev2.h 

Il ne reste plus qu'à appeler make , make install et attendre la fin de la build:


 Successfully built 4dae6b1a7d32 

Utilisez cet id image pour baliser et créer un conteneur:


 docker tag 4dae6b1a7d32 ubuntu16_armhf_opencv:latest docker run ubuntu16_armhf_opencv 

Et il suffit de pomper l'OpenCV assemblé hors du conteneur. Tout d'abord, regardons l'identifiant du conteneur créé:


 $ docker container ls --all CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e94667fe60d2 ubuntu16_armhf_opencv "/bin/bash" 6 seconds ago Exited (0) 5 seconds ago clever_yalow 

Et copiez le répertoire d'installation avec OpenCV installé:


 docker cp e94667fe60d2:/opencv/build/install/ ./ mv install ocv_install 

Mettre la table


Copiez ocv_install sur le Raspberry Pi, définissez les chemins et essayez d'exécuter OpenCV à partir de python.


 export LD_LIBRARY_PATH=/path/to/ocv_install/lib/:$LD_LIBRARY_PATH export PYTHONPATH=/path/to/ocv_install/python/:$PYTHONPATH 

Exécutez l'exemple de détection à l'aide du réseau neuronal MobileNet-SSD à partir de https://github.com/chuanqi305/MobileNet-SSD :


 import cv2 as cv print cv.__file__ classes = ['backgroud', 'aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor'] cap = cv.VideoCapture(0) net = cv.dnn.readNet('MobileNetSSD_deploy.caffemodel', 'MobileNetSSD_deploy.prototxt') cv.namedWindow('Object detection', cv.WINDOW_NORMAL) while cv.waitKey(1) != 27: hasFrame, frame = cap.read() if not hasFrame: break frame_height, frame_width = frame.shape[0], frame.shape[1] blob = cv.dnn.blobFromImage(frame, scalefactor=0.007843, size=(300, 300), mean=(127.5, 127.5, 127.5)) net.setInput(blob) out = net.forward() for detection in out.reshape(-1, 7): classId = int(detection[1]) confidence = float(detection[2]) xmin = int(detection[3] * frame_width) ymin = int(detection[4] * frame_height) xmax = int(detection[5] * frame_width) ymax = int(detection[6] * frame_height) if confidence > 0.5: cv.rectangle(frame, (xmin, ymin), (xmax, ymax), color=(255, 0, 255), thickness=3) label = '%s: %.2f' % (classes[classId], confidence) labelSize, baseLine = cv.getTextSize(label, cv.FONT_HERSHEY_SIMPLEX, 0.5, 1) ymin = max(ymin, labelSize[1]) cv.rectangle(frame, (xmin, ymin - labelSize[1]), (xmin + labelSize[0], ymin + baseLine), (255, 0, 255), cv.FILLED) cv.putText(frame, label, (xmin, ymin), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0)) cv.imshow('Object detection', frame) 


C'est tout, un assemblage complet ne prend pas plus de 20 minutes. Je joins la version finale du Dockerfile ci-dessous et en saisissant cette opportunité, je propose de répondre à une courte enquête de l'équipe OpenCV pour ceux qui ont déjà eu de l'expérience avec la bibliothèque: https://opencv.org/survey-2018.html .


Et oui, félicitations pour OpenCV 4! Ce n'est pas seulement le travail d'une équipe distincte, c'est le travail de toute la communauté - OpenCV 4 vous.


 FROM ubuntu:16.04 USER root RUN dpkg --add-architecture armhf RUN sed -i -E 's|^deb ([^ ]+) (.*)$|deb [arch=amd64] \1 \2\ndeb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ \2|' /etc/apt/sources.list RUN apt-get update && \ apt-get install -y --no-install-recommends \ cmake \ pkg-config \ crossbuild-essential-armhf \ git \ python-pip \ libgtk2.0-dev:armhf \ libpython-dev:armhf \ libgstreamer1.0-dev:armhf \ libgstreamer-plugins-base1.0-dev:armhf \ libgstreamer-plugins-good1.0-dev:armhf \ libgstreamer-plugins-bad1.0-dev:armhf RUN pip install numpy==1.12.1 RUN git clone https://github.com/opencv/opencv --depth 1 RUN mkdir opencv/build && cd opencv/build && \ export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig && \ cmake -DCMAKE_BUILD_TYPE=Release \ -DOPENCV_CONFIG_INSTALL_PATH="cmake" \ -DCMAKE_TOOLCHAIN_FILE="../opencv/platforms/linux/arm-gnueabi.toolchain.cmake" \ -DWITH_IPP=OFF \ -DBUILD_TESTS=OFF \ -DBUILD_PERF_TESTS=OFF \ -DOPENCV_ENABLE_PKG_CONFIG=ON \ -DPYTHON2_INCLUDE_PATH="/usr/include/python2.7" \ -DPYTHON2_NUMPY_INCLUDE_DIRS="/usr/local/lib/python2.7/dist-packages/numpy/core/include" \ -DENABLE_NEON=ON \ -DCPU_BASELINE="NEON" .. && make -j4 && make install 

Source: https://habr.com/ru/post/fr430906/


All Articles