fbpixel
Étiquettes : ,

Une application intéressante en robotique est la reconnaissance de forme. Dans ce tutoriel nous allons utiliser la librairie OpenCV dans un code en Python qui permettra de détecter le centre d’une ligne. Afin de réaliser ce suivi de ligne nous allons effectuer du traitement d’image avec OpenCV.

Cela vous permettra ensuite de pouvoir réaliser votre régulation pour toujours garder le centre de la ligne au milieu de la caméra et donc suivre la trajectoire ! Nous avons donc décidé de réaliser ce tutoriel sur Raspberry Pi puisque ce tutoriel a pour vocation d’effectuer du traitement d’image pour un robot en utilisant la Pi Caméra.

Matériel

Mise en place

  • L’installation d’OpenCV sur Raspberry Pi
  • Une photo d’un câble ou ligne noire (par défaut télécharger la photo ci-dessous pour travailler sur le même exemple, elle a été prise avec la Pi Caméra)
photo-tuto-cable-2-3 Détection d'une ligne avec Python et OpenCV

Code

Pour commencer, afin que vous puissiez réutiliser la détection d’une ligne ou d’un câble sur une vidéo (succession d’images), nous allons implémenter une Classe. Cette classe prendra en paramètre le chemin de l’image. Par défaut si l’image se trouve dans le même dossier que le code il suffira de mettre le nom de l’image, par exemple : « cam.jpg »).

Ensuite, enregistrer le code python ci-dessous dans un fichier nommé : suivi_ligne.py

# -*- coding: utf-8 -*-
"""
@author: AranaCorp
"""
import cv2
import time
import numpy as np
import matplotlib.pyplot as plt


class LineTracking():
	"""
	Classe permettant le traitement d'image, la délimitation d'un contour et permet de trouver le centre de la
	forme detectée
	"""
	def __init__(self,img_file):
		"""The constructor."""
		self.img = cv2.imread(img_file)
		self.img_inter = self.img
		self.img_final = self.img
		self.cendroids = []
		self.mean_centroids = [0,0]

	def processing(self):
		"""Méthode permettant le traitement d'image"""
		#self.img=cv2.resize(self.img,(int(self.img.shape[1]*0.2),int(self.img.shape[0]*0.2))) #redimensionner l'image d'origine
		print(self.img.shape)
		#self.img = self.img[199:391, 149:505] #on recentre l'image en excluant les zones extérieures afin d'avoir une plus grande précision pour la suite
		gray = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY) #on passe l'image en nuances de gris
		blur = cv2.GaussianBlur(gray,(5,5),0) #on floute l'image
		ret,thresh = cv2.threshold(blur,60,255,cv2.THRESH_BINARY_INV) #on binarise l'image

		self.img_inter=thresh
		"""Une ouverture permet d'enlever tous les élements qui sont plus petits que l'élement structurant (ou motif)
		Une fermeture permet de "combler" les trous qui ont une taille inférieur à l'élement structurant """
		kernel_open = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5)) #on créé l'élement structurant de l'ouverture
		kernel_close = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(10,10)) #on créé l'élement structurant de la fermeture

		thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel_open) #on fait une ouverture suivant un motif
		thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel_close) #on fait une fermeturesuivant un motif

		connectivity = 8

		output = cv2.connectedComponentsWithStats(thresh, connectivity, cv2.CV_32S) #permet de délimiter une forme
		num_labels = output[0]
		labels = output[1]
		stats = output[2]
		self.centroids = output[3] #donne les centres de la ou des formes de l'image

		for c in self.centroids :
			"""Permet de faire la moyenne des centres de la forme, en effet sur l'image test,
			   il y a deux centres qui sont très proches et la moyenne de deux convient.
			   On pourra imaginer que dans un cas général on modifie cela
			"""
			self.mean_centroids[0] += c[0]/len(self.centroids)
			self.mean_centroids[1] += c[1]/len(self.centroids)

		self.img_final = cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR)

		#permet de rajouter un carré rouge à l'endroit du centre de la forme
		#self.img_final[int(self.mean_centroids[1])-10 : int(self.mean_centroids[1])+20, int(self.mean_centroids[0])-10 : int(self.mean_centroids[0])+20] = [0,0,255]
		for c in self.centroids :
			self.img_final[int(c[1])-5 : int(c[1])+10, int(c[0])-5 : int(c[0])+10] = [0,255,0]

Enfin, créez un nouveau script python, par exemple : test_tracking.py

if __name__ == '__main__' :
	test = LineTracking('cam.png') #créer un objet LineTracking qui est la Classe créée au dessus .png ou .jpg
	test.processing() #lance le traitement d'image
	while True :
		cv2.imshow('image',test.img) #affiche l'image original après redimensionnement
		#cv2.imshow('process',test.img_inter ) #affiche l'image après traitement
		cv2.imshow('cable',test.img_final) #affiche l'image après traitement
		key= cv2.waitKey(1);
		if  key == ord(' '): #pour fermer les fenêtres appuyer sur la barre 'espace'
			break
	cv2.destroyAllWindows()

Vous avez maintenant tous les codes pour tester votre traitement d’image. Lancez dans un terminal la commande :

python3 test_tracking.py

Résultat

Deux fenêtres s’ouvre avec l’image originale et l’image traitée. On peut observer qu’un carré vert repère la position du câble. Ce point pourra être utilisé pour diriger un robot ou une caméra mobile.

raspi-opencv-linetrack-result Détection d'une ligne avec Python et OpenCV

Pour stopper l’affichage appuyer sur la barre « espace ».

Pour conclure, le traitement vient d’être effectué sur une image. Vous pouvez maintenant l’implémenter dans une boucle de traitement pour une vidéo.

Application

Vous pouvez maintenant utilisez la classe LineTracking dans votre fichier principal qui ouvre la caméra de la Raspberry. Pour plus d’informations sur l’installation d’une PiCam sur Raspberry Pi vous pouvez suivre notre tutoriel : gestion d’une PiCam avec Raspberry Pi

Source