Étiquettes : , ,

Nous allons voir dans ce tutoriel comment faire de la reconnaissance d’objet avec TensorFlow et OpenCV en utilisant un réseau de neurones pré-entrainé grâce au deep learning.

Nous avons vu dans un précédent tutoriel comment reconnaitre des formes simples avec la vision par ordinateur. Cette méthode ne fonctionne que pour certaines formes simples prédéfinies. Si vous souhaitez reconnaitre une plus grande variété d’objets, le plus simple est d’utiliser l’intelligence artificielle.

Matériel

  • Un ordinateur avec une installation de Python3
  • Une caméra

Principe

L’intelligence artificielle est un domaine de l’informatique dans lequel le programme apprend par lui-même à effectuer certaines tâches. Notamment de la reconnaissance visuelle. Dans ce tutoriel, nous allons utiliser un réseau de neurones entrainé pour reconnaitre des formes particulières.

Il faut de nombreuse données pour pouvoir entrainer correctement un réseau de neurone. Il a été démontré que l’apprentissage était plus rapide sur un réseau de neurones entrainé pour autre chose. Par exemple, un réseau de neurones entrainé pour reconnaitre les chiens s’entrainera plus facilement à reconnaitre les chats.

Configuration de Python

Si ce n’est pas le cas, vous pouvez télécharger et installer Python 3

Vous pouvez ensuite installer les librairies nécessaires OpenCV, numpy et imutils

python3 -m pip install opencv-python numpy imutils

Voici les versions que j’utilise dans ce tutoriel

numpy== 1.22.0
tensorflow== 2.13.0
opencv== 4.6.0

N.B.: Lorsqu’on utilise certains paquets python comme TensorFlow, il peut y avoir très fréquemment des problèmes de compatibilité. Si vous avez des difficultés n’hésitez pas à installer des versions spécifiques des paquets. Si vous avez plusieurs projets en cours, je vous invite fortement à créer des environnements virtuels (venv).

Récupérer un modèle pré-entrainé

Téléchargement du modèle ModelNet-SSD à partir du Model Zoo (ex: SSD MobileNet v2 320×320)

Téléchargez le fichier mscoco_label_map.pbtxt qui contient les identifiants des objets reconnus par le modèle.

N.B.: dans un précédent tutoriel, nous avions utilisez le résultat du framework Caffe pour le modèle (fichiers prototxt et caffemodel). Dans cet article, nous utilisons le SavedModel de TensorFlow.

Créer un dossier TensorFlowCV, qui sera votre espace de travail. Dans ce dossier créer un dossier pretrained_models dans lequel vous pouvez décompresser le modèle téléchargé.

Vous pouvez également créer un dossier data, dans lequel vous placerez vos images ou vidéo.

Placer les fichiers du modèle dans un dossier et créer le fichier ObjectRecognition.py

Script Python pour la reconnaissance d’Objet

Tout d’abord, nous créons un flux vidéo (vs) à l’aide de la librairie imutils qui va récupérer les images de la caméra.

vs = VideoStream(src=0, resolution=(1600, 1200)).start()

Nous initialisons un réseau de neurones avec les paramètres du SSD-ModelNetV2 (net) à l’aide de la librairie TensorFlow.

model= tf.saved_model.load("./pretrained_models/ssd_mobilenet_v2_320x320_coco17_tpu-8/saved_model")

Une fonction se charge de récupérer les noms des classes reconnues par le modèle à partir du fichier pbtxt

#load class names
def read_label_map(label_map_path):

    item_id = None
    item_name = None
    items = {}
    
    with open(label_map_path, "r") as file:
        for line in file:
            line.replace(" ", "")
            if line == "item{":
                pass
            elif line == "}":
                pass
            elif "id" in line:
                item_id = int(line.split(":", 1)[1].strip())
            elif "display_name" in line: #elif "name" in line:
                item_name = line.split(":", 1)[1].replace("'", "").strip()

            if item_id is not None and item_name is not None:
                #items[item_name] = item_id
                items[item_id] = item_name
                item_id = None
                item_name = None

    return items

class_names=read_label_map("./pretrained_models/ssd_mobilenet_v2_320x320_coco17_tpu-8/mscoco_label_map.pbtxt")
class_colors = np.random.uniform(0, 255, size=(len(class_names), 3))

Nous allons, ensuite, créer une boucle qui à chaque itération va lire l’image de la caméra et la passer en entrée du réseau de neurone pour faire la détection et reconnaissance d’objet.

	#Main loop
	while True:
		# Get video sttream. max width 800 pixels 
		#img = vs.read()
		img= cv2.imread('./data/two-boats.jpg') #from image file
		#ret, img=vc.read() #from video or ip cam
		img = imutils.resize(img, width=800)

		img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
		# get height and width of image
		h, w, _ = img.shape

		input_tensor = np.expand_dims(img, 0)

		# predict from model
		resp = model(input_tensor)

Enfin, le code affiche sur l’image la boite de détection, la probabilité de reconnaissance ainsi que la position

					# write classname for bounding box
					cls=int(cls) #convert tensor to index
					label = "{}: {:.2f}%".format(class_names[cls],score * 100)
					cv2.putText(img, label, (xmin, ymin-10), cv2.FONT_HERSHEY_SIMPLEX, 1, class_colors[cls], 1)
					
					#display position
					X= (xmax+xmin)/2
					Y= (ymax+ymin)/2
					poslbl= "X: ({},{})".format(X,Y)
					cv2.circle(img, (int(X)-15, int(Y)), 1, class_colors[cls], 2)	
					cv2.putText(img, poslbl, (int(X), int(Y)),
						cv2.FONT_HERSHEY_SIMPLEX, 0.5, class_colors[cls], 2)
					
					# draw on image
					cv2.rectangle(img, (xmin, ymin), (xmax, ymax), class_colors[cls], 4)

Code complet de reconnaissance d’objet avec OpenCV et TensorFlow

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  ObjectRecognitionTFVideo.py
#  Description:
#		Use ModelNetV2-SSD model to detect objects on image or video
#
#  www.aranacorp.com

# import packages
import sys
from imutils.video import VideoStream
from imutils.video import FPS
import numpy as np
import argparse
import imutils
import time
import cv2
import tensorflow as tf


# load model from path
model= tf.saved_model.load("./pretrained_models/ssd_mobilenet_v2_320x320_coco17_tpu-8/saved_model")
print("model loaded")

#load class names
def read_label_map(label_map_path):

    item_id = None
    item_name = None
    items = {}
    
    with open(label_map_path, "r") as file:
        for line in file:
            line.replace(" ", "")
            if line == "item{":
                pass
            elif line == "}":
                pass
            elif "id" in line:
                item_id = int(line.split(":", 1)[1].strip())
            elif "display_name" in line: #elif "name" in line:
                item_name = line.split(":", 1)[1].replace("'", "").strip()

            if item_id is not None and item_name is not None:
                #items[item_name] = item_id
                items[item_id] = item_name
                item_id = None
                item_name = None

    return items

class_names=read_label_map("./pretrained_models/ssd_mobilenet_v2_320x320_coco17_tpu-8/mscoco_label_map.pbtxt")
class_colors = np.random.uniform(0, 255, size=(len(class_names), 3))


if __name__ == '__main__':

	# Camera initialisation
	print("Start Camera...")
	vs = VideoStream(src=0, resolution=(1600, 1200)).start() #from usb cam
	#vs = VideoStream(usePiCamera=True, resolution=(1600, 1200)).start() #from RPi cam
	#vc = cv2.VideoCapture('./data/Splash - 23011.mp4') #from video file

	time.sleep(2.0)
	fps = FPS().start()
	
	#Main loop
	while True:
		#get image
		img = vs.read() # Get video stream
		#img= cv2.imread('./data/two-boats.jpg') #from image file
		#ret, img=vc.read() #from video or ip cam

                #process image
		img = imutils.resize(img, width=800) #max width 800 pixels 
		img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
		# get height and width of image
		h, w, _ = img.shape

		input_tensor = np.expand_dims(img, 0)

		# predict from model
		resp = model(input_tensor)

		# iterate over boxes, class_index and score list
		for boxes, classes, scores in zip(resp['detection_boxes'].numpy(), resp['detection_classes'], resp['detection_scores'].numpy()):
			for box, cls, score in zip(boxes, classes, scores): # iterate over sub values in list
				if score > 0.61: # we are using only detection with confidence of over 0.6
					ymin = int(box[0] * h)
					xmin = int(box[1] * w)
					ymax = int(box[2] * h)
					xmax = int(box[3] * w)
									
					# write classname for bounding box
					cls=int(cls) #convert tensor to index
					label = "{}: {:.2f}%".format(class_names[cls],score * 100)
					cv2.putText(img, label, (xmin, ymin-10), cv2.FONT_HERSHEY_SIMPLEX, 1, class_colors[cls], 1)
					
					#display position
					X= (xmax+xmin)/2
					Y= (ymax+ymin)/2
					poslbl= "X: ({},{})".format(X,Y)
					cv2.circle(img, (int(X)-15, int(Y)), 1, class_colors[cls], 2)	
					cv2.putText(img, poslbl, (int(X), int(Y)),
						cv2.FONT_HERSHEY_SIMPLEX, 0.5, class_colors[cls], 2)
					
					# draw on image
					cv2.rectangle(img, (xmin, ymin), (xmax, ymax), class_colors[cls], 4)
				
				
		# Show video frame
		cv2.imshow("Frame", img)
		key = cv2.waitKey(1) & 0xFF

		# Exit script with letter q
		if key == ord("q"):
			break

		# FPS update 
		fps.update()

	# Stops fps and display info
	fps.stop()
	print("[INFO] elapsed time: {:.2f}".format(fps.elapsed()))
	print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))

	cv2.destroyAllWindows()
	vs.stop()
	#vc.release()

Sources d’image pour la détection d’objet

Vous pouvez utiliser ce script avec différentes sources d’image. Pour cela, il faut légèrement adapter le code précédent afin de modifier la variable « img » contenant l’image à analyser.

  • La webcam de votre ordinateur
vs = VideoStream(src=0, resolution=(1600, 1200)).start()
while True:
	frame = vs.read()

Le stream vidéo doit être arrêté à la fin du script avec vs.stop()

vc = cv2.VideoCapture('rtsp://user:password@ipaddress:rtspPort')
while True:
	ret, frame=vc.read() #from ip cam

Veillez à arrêter la capture vidéo à la fin du script avec vc.release()

  • La Picam du Raspberry Pi
vs = VideoStream(usePiCamera=True, resolution=(1600, 1200)).start()
while True:
	frame = vs.read()

Pensez à arrêter le stream à la fin du script avec vs.stop()

  • Un fichier vidéo
vc = cv2.VideoCapture('./img/Splash - 23011.mp4') #from video
while True:
	ret, frame=vc.read() #from video
  • Un fichier image
frame= cv2.imread('./img/two-boats.jpg') 

Résultats

Pour cet exemple nous envoyons en entrée du réseau de neurones une image de deux bateaux qui sont reconnus correctement. Pour obtenir des résultats légèrement différents, vous pouvez modifier le paramètre confidence pour éviter les faux positifs.

tf-ssd-mobilenetv2-result-boats Reconnaissance d'Objet avec TensorFlow et OpenCV

Vous pouvez tester ce code avec votre webcam ou avec des photos, par exemple, pour voir les performances du modèle et de la reconnaissance d’objet

Une fois que votre script fonctionne, vous pouvez entrainer votre modèle pour qu’il puisse détecter d’autres objets.

Paquets et Modèles

Dans ce tutoriel, nous avons utiliser le modèle pré-entrainé SSD ModelNetV2. Il est bon de noter qu’ils existent d’autres modèles de classification avec des performances et caractéristiques différentes.

  • vgg16
  • vgg19
  • resnet50
  • resnet101
  • resnet152
  • densenet121
  • densenet169
  • densenet201
  • inceptionresnetv2
  • inceptionv3
  • mobilenet
  • mobilenetv2
  • nasnetlarge
  • nasnetmobile
  • xception

N’hésitez pas à nous laisser un commentaire pour partager les modèles que vous utilisez ou connaissez et votre retour d’expérience.

Sources