Cours:Classif
TP Classification : détection d'objet en temps réel par vision
Le travail de cette étape va consister à
- analyser des images acquises en "temps réel" afin de détecter et identifier des objets
- les objets seront
- dans un premier temps des jetons de nain jaune
- dans un second temps des briques lego.
Sommaire
Technos matérielles et logicielles
Vous utiliserez :
- Une Rpi 4 que vous programmerez depuis des postes utilisés en terminaux connectés par
ssh
, avec redirection graphique (option- X
). - Une camera PiCam Wide (grand angle)
- la librairie opencv pour la reconnaissance
- la librairie CImg pour des traitements bas niveaux et affichages : https://cimg.eu/
Prise d'images en terminal
- Connecter (si cela n'est pas fait) la PiCam à la Rpi4
- Tester la PiCam avec
libcamera-hello
(la capture doit s'afficher sur l'écran de la Rpi) - Tester l'acquisition d'image avec l'éxecutable
libcamera-still
- Explorer les options de cette application (
libcamera-still -h
), en particulier-n
,--immediate
,--width
,--height
et-o
Voir la page suivante pour le détails des options possibles : https://www.raspberrypi.com/documentation/computers/camera_software.html
Livrable 0 : acquisition d'image
La PiCam s'interface en exploitant la librairie LibCamera.
Démo
- Télécharger depuis GitHub (
git clone ...
), ce projet de démo : https://github.com/edward-ardu/libcamera-cpp-demo/tree/main - Le compiler et l'exécuter pour tester.
- Prendre le temps d'analyser le programme
main.cpp
pour comprendre :- comment il fonctionne ;
- comment l'image est acquise et utilisée dans openCV :
- quel est l'objet openCV qui contient l'image ?
- comment est affichée cette image ?
- comment l'acquisition d'une touche est-elle gérée ?
- ...
OneShot
- copier le dossier de ce programme exemple vers un nouveau dossier
OneShot
- modifier le
main.cpp
en l'alégeant, afin d'obtenir un programme qui
- dès son lancement, lance une acquisition d'image ;
- attend que cette acquisition soit terminée
- affiche l'image, et attend l'appui d'une touche
- se termine
Une solution possible : File:Main-oneshot.cpp
Avec CImg
- copier ce dossier
OneShot
vers un dossierOneshotCimg
- Télécharger la libraire CImg et placer
CImg.h
dans le dossier source - Modifier le
main.cpp
pour
- convertir l'image openCV couleur en niv. de gris
- convertir l'image niv. de gris openCV en image CImg
- avec CImg : afficher l'image et attendre la fermeture de la fenêtre.
- Il sera nécessaire d'ajouter :
- dans le
main.cpp
:
- dans le
#include "CImg.h"
#define cimg_plugin1 "cvMat.h"
using namespace cimg_library;
- dans le fichier
CMakeLists.txt
- dans le fichier
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
et de modifier
target_link_libraries(libcamera-demo "${LIBCAMERA_LIBRARIES}" ${OpenCV_LIBS})
en
target_link_libraries(libcamera-demo "${LIBCAMERA_LIBRARIES}" ${OpenCV_LIBS} X11)
Livrable 1 : prétraitements et mesure de descripteurs
Cette partie est moins guidée, elle devra être incluse dans votre compte-rendu.
- Modification éventuelle de la zone de capture de la camera.
- Conversion en image niv. de gris.
- Binarisation.
- (si plusieurs objets) Segmentation.
- En ne plaçant qu'un seul objet dans le champ de la camera, calculer et afficher ses descripteurs de forme : longueur/largeur de l'objet, cf https://raphael.candelier.fr/?blog=Image%20Moments
- Fonction de calcul des descripteurs géométriques (longueur l, largeur w) d'un objet dans une image :
void compute_desc(CImg<> image) {
long M00, M10, M01, M11, M20, M02;
M00 = 0; M10 = 0; M01 = 0; M11 = 0; M20 = 0; M02 = 0;
cimg_forXY(image,x,y) {
M00 += image(x,y);
M10 += x*image(x,y);
M01 += y*image(x,y);
M11 += x*y*image(x,y);
M20 += x*x*image(x,y);
M02 += y*y*image(x,y);
}
long xm = M10/M00;
long ym = M01/M00;
long mu20 = M20/M00 - xm*xm;
long mu02 = M02/M00 - ym*ym;
long mu11 = M11/M00 - xm*ym;
long l = sqrt(8 * (mu20 + mu02 + sqrt(4*mu11*mu11 + (mu20-mu02)*(mu20-mu02))));
long w = sqrt(8 * (mu20 + mu02 - sqrt(4*mu11*mu11 + (mu20-mu02)*(mu20-mu02))));
cout << "l = " << l << endl;
cout << "w = " << w << endl;
}
Livrable 2 : identification par KNN
Cette partie est moins guidée, elle devra être incluse dans votre compte-rendu.
a) Dans un premier temps
- un seul plus proche voisin
- un seul échantillon de référence par classe
- pour un objet à classer : en calculant la distance à chaque échantillon de référence
b) Puis progressivement
- viser une décision multiclasse (ex. "Quelle est la classe de l'objet ?").
- augmenter le nb d'échantillons de référence par classe (réfléchir à la façon dont vous souhaitez stocker et manipuler cette information). Si vous avez du temps, il serait intéressant de tracer graphiquement la position de vos échantillons de références dans l'espace des descripteurs, par exemple en exportant vos coordonnées (dans cet espace) vers matlab.
- passer à 3 plus proches voisins
c) Ensuite - et seulement, ou si vous n'arrivez pas à coder a) et b) - vous pourrez comparer avec l'implémentation de openCV
Livrable 3 : identification par SVM
Livrable final (noté) : Compte rendu
- Deadline : vendredi 28 février à 23h59.
- en m'envoyant un fichier PDF par mail
- par binôme
- en expliquant vos choix
- en donnant le code C++ dont vous pourrez extraire des morceaux pour expliquer ce que vous avez fait. (Inutile de m'expliquer des points de syntaxe du C++, je sais programmer).
Contenu (en quelques pages) :
- Introduction : contexte, objectif, briques matérielles et logicielles utilisés
- Pré-traitements : description des traitements appliqués avant la classification, description choisie, ...
- Classification/Décision : quelle méthode ? Quels paramètres ?
- Résultats/Validation : quels sont les résultats obtenus ? (une description quantitative si possible)
- Conclusion : objectif atteint ? Pistes d'améliorations ?
Références
OpenCV :
- OpenCV Tutorials
- Exemples OpenCV en c++
- K-Nearest Neighbour
- Image Segmentation with Watershed Algorithm
- connected Components et son exemple en cpp : https://docs.opencv.org/3.4/de/d01/samples_2cpp_2connected_components_8cpp-example.html#a3
- Introduction to Support Vector Machines
- Fourier Descriptors, voir également Contours example pour obtenir les contours d'un objet.
CImg :
- Tutorial : Getting Started
- Namespace List
- Documentation, en particulier Image Loops