Cours:Classif
Révision datée du 2 février 2026 à 15:16 par Fredmn (discussion | contributions) (→Bouts de code Python)
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
- 1 Technos matérielles et logicielles
- 2 Connexion à la Rpi et test d'acquisition en ligne de commande
- 3 Capture d'image et affichage en temps réel
- 4 Prétraitement
- 5 Reconnaissance simple d'un seul objet, avec descripteurs géométriques élémentaires
- 6 Descripteur et Classifieur plus évolué
- 7 Plusieurs objets
- 8 Bouts de code Python
- 9 Références
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)
- Le langage Python accompagné de
- la librairie libcamera pour les acquisitions :
- PIL et numpy pour les traitements bas niveaux
- les librairies opencv et dlib pour la classification et la reconnaissance :
Étapes :
- Connexion à la Rpi et test d'acquisition en ligne de commande
- Capture d'image et affichage en temps réel, avec Python
- Prétraitement
- Reconnaissance simple d'un seul objet, avec descripteurs géométriques
- Classifieur plus évolué (knn, svm)
- Plusieurs objets
Connexion à la Rpi et test d'acquisition en ligne de commande
- Connecter (si cela n'est pas fait) la PiCam à la Rpi4
- Dans un terminal, se connecter à la Rpi en ssh :
ssh -X root@10.98.33.XX - Tester la PiCam avec
libcamera-hello(la capture en video doit s'afficher sur l'écran de la Rpi). Avec les informations affichées, identifier :- le modèle du capteur,
- ses caractéristiques (résolution, format, cadence, etc ...).
- Tester l'acquisition d'image avec l'éxecutable
libcamera-still- Explorer les options de cette application (
libcamera-still -h), en particulier-n,--immediate,--width,--heightet-o - Voir la page suivante pour le détails des options possibles : https://www.raspberrypi.com/documentation/computers/camera_software.html
- Explorer les options de cette application (
Capture d'image et affichage en temps réel
En exploitant la documentation Picamera2 (principalement section 6 - Capturing images and requests)
- Tester les deux exemples Capturing arrays et Capturing PIL images
- PIL fait référence à Python Imaging Library : une bibliothèque Python de traitement d'images.
- Écrire un script Python qui :
- initialise la camera
- affiche en continu son image
- sur l'appui d'une touche, réalise une capture (dans un objet
arrayouPIL) et sauvegarde l'image dans un fichier
En pratique :
- Vous pouvez lancer un interpréteur Python dans le terminal pour tester des choses
- Vous pouvez accéder aux dossiers de la Rpi depuis votre PC fixe, depuis le navigateur Dolphin avec comme url
sftp://root@10.98.33.83:22/. Ce qui vous permettra par exemple d'éditer le fichier script depuis votre PC fixe. - Dans le terminal,
python monscript.pypour executer votre script - On peut facilement attendre l'appui d'une touche avec
cv2.waitkey() - Référence Python :
Prétraitement
- Modification éventuelle de la zone de capture de la camera (crop).
- Conversion en image niveaux de gris, sur 8 bits.
- Binarisation (en mettant l'objet à 255, le fond à 0).
Reconnaissance simple d'un seul objet, avec descripteurs géométriques élémentaires
- En ne plaçant qu'un seul objet dans le champ de la camera, calculer et afficher ses descripteurs de forme : longueur et largeur de l'objet, cf https://raphael.candelier.fr/?blog=Image%20Moments (calcul de l et w)
- Construire une décision idoine à l'aide de la largeur et de la longueur de l'ellipse englobante, afin de discrimer trois classes d'objets (par exemple : jeton court, jeton long, jeton rond)
Exemple de calcul de l et w à partir d'une image binaire représentée dans un tableau numpy (arr de type ndarray) :
img = arr.astype(np.float64, copy=False)
H, W = img.shape
yy, xx = np.indices((H, W))
M00 = float(np.sum(img))
M10 = float(np.sum(xx * img))
M01 = float(np.sum(yy * img))
M11 = float(np.sum(xx * yy * img))
M20 = float(np.sum((xx * xx) * img))
M02 = float(np.sum((yy * yy) * img))
xm = int(M10 / M00)
ym = int(M01 / M00)
mu20 = M20 / M00 - xm * xm
mu02 = M02 / M00 - ym * ym
mu11 = M11 / M00 - xm * ym
t = math.sqrt(4.0 * mu11 * mu11 + (mu20 - mu02) * (mu20 - mu02))
l = int(math.sqrt(8.0 * (mu20 + mu02 + t)))
w = int(math.sqrt(8.0 * (mu20 + mu02 - t)))
Descripteur et Classifieur plus évolué
- Descripteurs de Fourier
- On transforme le contour d’un objet (suite de points) en un signal périodique, puis on le décompose en harmoniques avec la transformée de Fourier. Les premiers coefficients décrivent la forme globale et, une fois normalisés, ils permettent de comparer/reconnaître des formes indépendamment de la position, de la taille et de la rotation.
- Méthodologie :
- image en niveau de gris (éventuellement binarisation) :
cv2.cvtColor() - détection des contours :
cv2.Canny()etv2.findContours() - description des contours :
cv2.ximgproc.fourierDescriptor()
- image en niveau de gris (éventuellement binarisation) :
- Références :
- Il sera nécessaire de normaliser ces descripteurs : https://dsp.stackexchange.com/questions/19982/fourier-descriptors-trying-to-classify-objects
- Exemple :
# Descripteurs de Fourier
from picamera2 import Picamera2
import numpy as np
import cv2
picam = Picamera2()
picam.start()
a = picam.capture_array("main")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 100, 200)
contours, hierarchy = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnt = max(contours, key=cv2.contourArea)
cnt = cnt.astype(np.float32)
# Paramètres utiles :
# nbElt = nombre de points ré-échantillonnés sur le contour
# nbFD = nombre de descripteurs gardés
fd = cv2.ximgproc.fourierDescriptor(cnt, nbElt=128, nbFD=16)
print(fd.shape, fd.dtype)
# Normalisation
fd = np.squeeze(fd)
# Assure forme (nbFD, 2)
if fd.ndim == 1 and fd.shape[0] == 2*nbFD:
fd = fd.reshape(nbFD, 2)
re = fd[:, 0].astype(np.float32)
im = fd[:, 1].astype(np.float32)
mag = np.sqrt(re*re + im*im) # rotation-invariant
mag[0] = 0.0 # enlève la composante continue (liée à la translation)
# normalisation d'échelle (et normalisation globale)
norm = np.linalg.norm(mag) + 1e-12
feat = mag / norm- KNN
- Redressement de la perspective
- Détecteur de coin de Harris : https://docs.opencv.org/4.5.1/dc/d0d/tutorial_py_features_harris.html
-
cv2.findHomography()etc2.warpPerspective() - ou https://docs.opencv.org/4.5.1/da/d6e/tutorial_py_geometric_transformations.html
- SVM
Plusieurs objets
- Segmentation nécessaire pour séparer les objets.
- Puis une labellisation pour les numéroter.
Bouts de code Python
- Convertir une image couleur img (4 canaux) en image OpenCV :
import cv2
im_cv = cv2.cvtColor(img, cv2.COLOR_RGBA2BGR)
- Acquisition d'image en recommançant en cas d'échec :
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.
Archives de cette page :