OpenCV a la RPi

De Wikijoan
Dreceres ràpides: navegació, cerca

Contingut

Introducció

La idea és utilitzar OpenCV per al reconeixement d'imatges en una recreativa de dards. L'objectiu es detectar amb dues webcams la posició exacta on s'ha tirat el dard. S'ha descartat la possibilitat de fer-ho amb alguna xarxa resistiva. Sembla ser que el mètode més net (i que ja ha fet algú altra) és utilitzar visió artificial.

L'objectiu és instal.lar OpenCV a la RPi 3, i fer totes les proves que em condueixin a detectar la posició dels dards. Primer es discuteix la instal.lació, i després les primeres proves de programació amb l'API de C++.

Instal.lació OpenCV 3 a la RPi 3 (Raspbian Jessie) (desembre 2016)

En una RPi B+ tenia instal.lat OpenCV:

sudo apt-get install libopencv-dev python-opencv

Quedava instal.lat el OpenCV 2.4.1. La funció findNonZero() no està implementada en aquesta versió. Decideixo migrar a la RPi 3, i instal.lar OpenCV des de les fonts.

Primer vull instal.lar OpenCV 3 a la RPi B+ seguint el següent tutorial: Installing OpenCV 3 on Raspbian Jessie (ell ho ha fet amb la Rpi2)

i m'ha donat problemes quan faig el sudo apt-get upgrade.

Instal.lo OpenCV3 a la RPi 3 seguin la següent versió del tutorial:

Aquest tutorial està orientat a utilitzar Python com a entorn de programació. I jo el que vull és utilitzar C++, que de fet és l'entorn nadiu. Per tant, el que he de fer és deixar de fer bastantes coses que es comenta en el tutorial.

Pas a pas, la manera de procedir que a mi m'ha funcionat, seguint el tutorial, és:

$ sudo raspi-config
$ sudo reboot
$ sudo apt-get purge wolfram-engine
$ sudo apt-get update

Em sembla que no he fet el upgrade

Coses meves:

$ sudo apt-get install joe
$ sudo apt-get install build-essential git cmake pkg-config

$ sudo apt-get install libjpeg-dev libtiff5-dev libjasper-dev libpng12-dev
$ sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
$ sudo apt-get install libxvidcore-dev libx264-dev
$ sudo apt-get install libgtk2.0-dev
$ sudo apt-get install libatlas-base-dev gfortran

Jo no instal.lo python2.7-dev ni python3-dev. Tampoc no instal.lo el pip (python package manager), ni tampoc instal.lo virtualenv ni virtualenvwrapper, perquè a mi no em caldrà cap Python virtual environment (jo programaré directament amb C++).

Descarrego el codi font de OpenCV:

$ cd ~
$ wget -O opencv.zip https://github.com/Itseez/opencv/archive/3.1.0.zip
$ unzip opencv.zip

$ wget -O opencv_contrib.zip https://github.com/Itseez/opencv_contrib/archive/3.1.0.zip
$ unzip opencv_contrib.zip

Ja podem compilar des de les fonts:

$ cd ~/opencv-3.1.0/
$ mkdir build
$ cd build
$ cmake -D CMAKE_BUILD_TYPE=RELEASE \
    -D CMAKE_INSTALL_PREFIX=/usr/local \
    -D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib-3.1.0/modules \
    -D BUILD_EXAMPLES=ON ..

(em carrego la línia -D INSTALL_PYTHON_EXAMPLES=ON \ que posa en el tutorial).

Quan acaba de fer el build, fixem-nos el resultat que tenim en pantalla, per saber quins seran els directoris importants i què estem a punt de compilar/instal.lar. Compilació:

$ make

Faig un make normal perquè el que proposa el tutorial és fer

$ make -j4

per tal d'aprofitar els 4 cores de la RPi3. Però a mi se'm penja (com es comenta que pot passar...). Per tant, faig la compilació normal, encara que triga molt més.

Instal.lació:

$ sudo make install
$ sudo ldconfig

I per comprovar que tot funciona correctament, el millor és provar els exemples que es fan en el següent punt.

Primeres proves a la RPi. Historial de proves

Els exemples que estic provant estan a /home/joan/recreativa_dards/proves_opencv.

Algunes proves utilitzen la webcam. De moment estic utilitzant una Logitech QuickCam Express. S'haurà de veure si aquesta webcam tindrà prou resolució, i també si en puc connectar dues alhora de forma viable. També tinc una RaspiCAM IR que es pot fer servir, però de moment no doncs sembre serà més barato utilitzar una d'aquestes webcams que es poden trobar barates.

1. color2grey.cpp: primera prova. Converteixo una imatge a escala de gris.

2. camera_capture1.cpp. Tinc la webcam (Logitche QuickCam Express) connectada, i ja puc llegir frames de la càmera

3. Simplegrab.cpp. Una altra manera de fer-ho. Obrim un dispositiu de video captura. He afegit les línies 24 i 25 per definir la resolució de la captura.

3b. SimplegrabPNG.cpp. Obrim un dispositiu de video captura. Gravem a png, i podem controlar els paràmetres de compressió, tot i que no es veu especialment diferència (però sí que afecta al tamany del fitxer png).

Amb les primeres proves que vaig fer amb la Rpi B+ i OpenCV 2.4.1, la resolució del frame és 176x144 (fa servir SBRG8 perquè S561 no funciona)

Amb les proves que faig amb la Rpi3 i OpenCV 3.0.1, la resolució del frame és 352x288 (fa servir S561, que ara funciona correctament)

Ara que ja sé generar imatges a partir de la càmera, començo a fer proves per detectar formes i colors.

4. detectar_vermell.cpp. Només em quedo amb el quadrat vermell

5. detectar_vermell2.cpp

6. detectar_vermell3.cpp -> no funciona. He d'instal.lar OpenCV 2.4.4 mínim -> he instal.lat OpenCV 3.0.1 i ja funciona

dpkg -l | grep libopencv
ii  libopencv-calib3d-dev                 2.4.1+dfsg-0exp2rpi2
...

Tinc instal.lada la versió 2.4.1, i per utilitzar findNonZero necessito com a mínim la versió OpenCV 2.4.4 (http://stackoverflow.com/questions/19242662/opencv-find-all-non-zero-coordinates-of-a-binary-mat-image)

7. findnonzero.cpp -> no funciona. He d'instal.lar OpenCV 2.4.4 mínim -> ja funciona amb OpenCV 3.0.1

8. contour.cpp -> detecta el contorn. Funciona molt bé.

9. diferencia1.cpp -> detecto correctament la diferència entre dues imatges.

$ pkg-config opencv --cflags --libs
-I/usr/include/opencv  -lopencv_calib3d -lopencv_contrib -lopencv_core -lopencv_features2d -lopencv_flann -lopencv_highgui -lopencv_imgproc -lopencv_legacy -lopencv_ml -lopencv_objdetect -lopencv_photo -lopencv_stitching -lopencv_ts -lopencv_video -lopencv_videostab

he instal.lat OpenCV 3.0.1 a partir de

$ pkg-config --libs --cflags opencv
-I/usr/local/include/opencv -I/usr/local/include -L/usr/local/lib -lopencv_stitching -lopencv_superres -lopencv_videostab -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_dnn -lopencv_dpm -lopencv_fuzzy -lopencv_line_descriptor -lopencv_optflow -lopencv_plot -lopencv_reg -lopencv_saliency -lopencv_stereo -lopencv_structured_light -lopencv_rgbd -lopencv_surface_matching -lopencv_tracking -lopencv_da
tasets -lopencv_text -lopencv_face -lopencv_xfeatures2d -lopencv_shape -lopencv_video -lopencv_ximgproc -lopencv_calib3d -lopencv_features2d -lopencv_flann -lopencv_xobjdetect -lopencv_objdetect -lopencv_ml -lopencv_xphoto -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs -lopencv_photo -lopencv_imgproc -lopencv_core

10. SimpleGrab_detectarvermell.cpp -> capturo una imatge i detecto el vermell. També puc detectar el verd i el blau. En canvi, no em detecta el groc.

11. tracking:

Buscant la manera de detectar el groc, trobo aquest tutorial, que està molt bé, i que mostra el moment d'un objecte, és a dir, el centre de gravetat:

12. SimpleGrab_detectargroc1.cpp -> detecto el groc. Genero la imatge amb punts blancs de les posicions del groc, i mostro els punts per pantalla.

13. SimpleGrab_detectargroc2.cpp -> detecto el groc. Calculo la posició (moment) de l'objecte groc.

14. hough-transformation (main.cpp) (carpeta hough-master). Serveix per detectar rectes.

14b. Adapatació hough-transformation (main2.cpp): he modificat el codi per tal de què no hi hagi part gràfica. Mostra totes les línies per pantalla (coordenades dels punts inicial i final).

15. image_to_binary.cpp. Capturem una imatge de la càmera, la convertim a grayscale, i fem un threshold amb el valor desitjat per tal de convertir-la a binari (blanc i negre).

16. generalContours.cpp. Serveix per detectar objectes i ficar contorns (rectangles o cercles) que s'ajustin de forma mínima a aquest objectes.

C++ i Rasberry Pi Camera Module (RaspiCam). Exemple 1

Disposo de la càmera NoIR (infrarrojos). La manera com accedim a la càmera RaspiCam és diferent de les webcams USB. D'entrada, el dispositiu no apareix a /dev/video0, el dispositiu funciona de forma diferent.

I el codi que tinc fins ara de OpenCV que funciona amb webcams USB ara no funciona. El que volem fer ara és un exemple C++ per capturar una imatge. Però de fet, aquest exemple no entraria dins de OpenCV.

Segueixo l'article.

$ raspivid -t 10000

és una aplicació de consola que serveix per enviar el streaming de video. Efectivament, a la tele puc veure el video a temps real, encara que llenci l'aplicatiu des del portàtil via SSH.

$ wget https://github.com/raspberrypi/userland/archive/master.zip
$ sudo mv master.zip /opt/vc
$ sudo unzip master.zip

i tot el contingut del zip va a parar a la carpeta userland-master

Change to the /opt/vc/userland-master folder, then build it with the following commands:

$ cd /opt/vc/userland-master
$ sudo mkdir build
$ cd build
$ sudo cmake -DCMAKE_BUILD_TYPE=Release ..
$ sudo make
$ sudo make install

Test everything worked by running raspivid again. You may see some different messages pop up (I got some harmless errors probably due to the build being so recent), but the crucial thing is that you still get the video feed on screen.


The api and samples can all be downloaded here:

Extract them into a folder in your home directory called 'picamdemo' (ho fico a /home/pi/recreativa_dards/proves_opencv_cpp). You should have a few cpp files in there, plus a make file and some shaders.

$ cd /home/pi/recreativa_dards/proves_opencv_cpp
$ mkdir picamdemo
$ cd picamdemo
$ wget http://www.cheerfulprogrammer.com/downloads/picamtutorial/picamdemo.zip
$ unzip picamdemo.zip

Change to the folder and build the application with:

$ cmake .

Es creen els fitxers Makefile, CMakeCache.txt, cmake_install.cmake i la carpeta carpeta CMakeFiles/.

Ara ja podem compilar i es crea el binari picamdemo.

$ make

C++ i Rasberry Pi Camera Module (RaspiCam). Exemple 2, millor

És la manera més senzilla que he trobat per integrar la raspicam amb C++:

RaspiCam: C++ API for using Raspberry camera with/without OpenCv

carpetes:

unzip raspicam-0.1.6.zip
cd raspicamxx
mkdir build
cd build
cmake ..
 make
sudo make install
sudo ldconfig

I els exemples més senzills, com està explicat a l'article,, són simpletest_raspicam.cpp i simpletest_raspicam_cv.cpp. El primer captura una imatge en format bitmap (.ppm, que suposo que és equivalent al bmp), i l'altra fa servir OpenCV i obtinc la imatge en format JPG. La resolució es molt bona.

g++ simpletest_raspicam.cpp -o simpletest_raspicam -I/usr/local/include -L/opt/vc/lib -lraspicam -lmmal -lmmal_core -lmmal_util
g++ simpletest_raspicam_cv.cpp -o  simpletest_raspicam_cv -I/usr/local/include/ -L/opt/vc/lib -lraspicam -lraspicam_cv -lmmal -lmmal_core -lmmal_util $(pkg-config --libs --cflags opencv)

D'altra banda, recpordar que des de C++ sempre puc capturar una imatge utilitzant la utilitat raspistill, similar a:

system(raspistill -o image.png)

NOTA. Totes aquestes proves les estic fent perquè necessito OpenCV per la recreativa de dards.

Aplicatiu cercle perfecte, recta perfecta (todo)

La idea ve de lluny, s'ha de fer un petit aplicatiu que analitzi un cercle/recta, o conjunt de cercles/rectes, i que et doni una puntuació.

Del segon link obtenim el contours_poly[i], que és el polígon del contorn de cada cercle. El polígon és un vector de punts. Aleshores podem fer una fórmula en què comparem cada punt del vector amb el centre del cercle que hem obtingut. Ho fem per tots els valors del poligon, promitgem, i aleshores obtenim un valor que ens diu quant de cercle és el nostre dibuix d'un cercle.

En definitiva és trobar la desviació estàndar

En la regressió linial, tenim el coeficient de correlació r. r=1 vol dir molt bona correlació. r=0 vol dir molt dolenta.

Recta perfecte

Donada una sèrie de línies, determinem els contorns d'aquestes línies. Els contours_poly[i] és un vector dels punts. Donats una sèrie de punts (x,y), puc calcular la mitjana de les x i y, la desviació típica (o estàndar), i la covariança.

La correlació és r=covariancia/(desv_tip_x*desv_tip_y)

Si r=1, vol dir que és una recta perfecte.

desv_tip_x = sqrt(1/N * sumatori((xi - xm)^2) ), on xm és la mitjana
desv_tip_y = sqrt(1/N * sumatori((yi - ym)^2) ), on ym és la mitjana
covariancia = 1/N * sumatori ((xi-xm)*(yi-ym))

r = covariancia / (desv_tip_x*desv_tip_y)

Cercle perfecte

A partir del segon link obtinc el cercle que s'ajusta al meu cercle dibuixat. El meu cercle dibuixat és un contours_poly[i] (vector de punts). N'hi ha prou en calcular la distància d'aquests punts al centre, fer un sumatori i la mitjana, és a dir, una desviació típica.

S'ha de dividir per R per normalitzar, doncs poden haver-hi cercles més grans i d'altres més petits.

sqrt(1/N * (sumatori(di^2))) té dimensions de distància
ho hem de normalitzar dividint per R per tal de què no tingui dimensions.

di = (xi-x0)^2 + (yi-y0)^2

r = 1/R0 * sqrt(1/N * (sumatori(di^2)))

En aquest cas, per al cercle perfecte r=0.


creat per Joan Quintana Compte, desembre 2016

Eines de l'usuari
Espais de noms
Variants
Accions
Navegació
IES Jaume Balmes
Màquines recreatives
CNC
Informàtica musical
joanillo.org Planet
Eines