fbpixel
Etiquetas: ,

Uma aplicação interessante na robótica é o reconhecimento de formas. Neste tutorial vamos utilizar a biblioteca OpenCV num código Python, que nos permitirá detectar o meio de uma linha. Para podermos acompanhar a linha, vamos realizar um tratamento de imagem com o OpenCV.

Isso permitirá, na sequência, regular de modo a manter o meio da linha sempre no centro da câmera, e assim seguir a sua trajetória! Decidimos fazer este tutorial no Raspberry Pi, pois o nosso propósito é realizar processamento de imagens por um robô utilizando a câmera Pi.

Material

Implementação

  • Instalação da OpenCV no Raspberry Pi
  • Uma fotografia de um cabo ou linha preta (como padrão, faça o download da fotografia abaixo – tirada com a câmera Pi – para trabalhar com o mesmo exemplo.)
photo-tuto-cable-2-3 Detectar uma linha com Python e a OpenCV

Código

Antes de tudo, para podermos reutilizar a detecção da linha ou cabo num vídeo (sucessão de imagens), vamos implementar uma classe. O parâmetro dessa classe será o caminho da imagem. Como padrão, se a imagem estiver na mesma pasta que o código, será suficiente colocar o nome da imagem, por exemplo: “cam.jpg”).

Depois, é preciso salvar o código python abaixo num arquivo com o nome 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]

E finalmente, criar um novo script python, por exemplo: 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()

Temos agora todos os códigos para testar o processamento da imagem. Vamos lançar no terminal o comando:

python3 test_tracking.py

Resultado

Duas janelas se abrem, com a imagem original e a imagem processada. Vemos que um quadrado verde marca a posição do cabo. Este ponto pode ser usado para conduzir um robô ou uma câmara móvel.

raspi-opencv-linetrack-result Detectar uma linha com Python e a OpenCV

Para parar a exibição, basta pressionar a barra de espaço.

Acabamos de concluir o processamento de uma imagem. Podemos agora implementá-lo num loop de processamento para um vídeo.

Aplicação

Agora pode utilizar a classe LineTracking no seu arquivo principal, que abre a câmara Raspberry. Para mais informações sobre como instalar uma PiCam no Raspberry Pi, veja o nosso tutorial: Gerir uma PiCam com o Raspberry Pi.

Fontes