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
- Raspberry Pi (ou o seu computador)
- Monitor, teclado e mouse, ou use a conexão remota via VNC
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.)
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.
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.