Neste tutorial, veremos como realizar o reconhecimento de objetos com o TensorFlow e o OpenCV usando uma rede neural pré-treinada usando o aprendizado profundo.
Vimos num tutorial anterior como reconhecer formas simples utilizando a visão por computador. Este método só funciona para certas formas simples predefinidas. Se quiser reconhecer uma maior variedade de objectos, a forma mais fácil é utilizar a inteligência artificial.
Hardware
- Um computador com uma instalação Python3
- Uma câmara
Princípio
A inteligência artificial é um domínio da informática em que o próprio programa aprende a realizar determinadas tarefas. O reconhecimento visual, em particular. Neste tutorial, vamos utilizar uma rede neural treinada para reconhecer formas específicas.
São necessários muitos dados para poder treinar corretamente uma rede neural. Foi demonstrado que a aprendizagem é mais rápida numa rede neuronal treinada para outra coisa. Por exemplo, uma rede neuronal treinada para reconhecer cães será treinada mais facilmente para reconhecer gatos.
Configurar o Python
Caso contrário, pode descarregar e instalar o Python 3
Pode então instalar as bibliotecas OpenCV, numpy e imutils necessárias.
python3 -m pip install opencv-python numpy imutils
Eis as versões que estou a utilizar neste tutorial
numpy== 1.22.0 tensorflow== 2.13.0 opencv== 4.6.0
Nota: Ao utilizar certos pacotes python, como o TensorFlow, podem ocorrer frequentemente problemas de compatibilidade. Se tiver dificuldades, não hesite em instalar versões específicas dos pacotes. Se tiver vários projectos em curso, recomendo vivamente que crie ambientes virtuais (venv).
Recuperar um modelo pré-treinado
Descarregar o modelo ModelNet-SSD do Model Zoo (por exemplo, MobileNet SSD v2 320×320)
descarregar o ficheiro mscoco_label_map.pbtxt, que contém os identificadores dos objectos reconhecidos pelo modelo.
N.B.: num tutorial anterior, utilizámos os resultados da estrutura Caffe para o modelo (ficheiros prototxt e caffemodel). Neste artigo, usamos o SavedModel do TensorFlow.
Crie uma pasta TensorFlowCV, que será seu espaço de trabalho. Nesta pasta, crie uma pasta pretrained_models na qual pode descompactar o modelo descarregado.
Também pode criar uma pasta de dados para colocar as suas imagens ou vídeos.
Coloque os ficheiros do modelo numa pasta e crie o ficheiro ObjectRecognition.py
Script Python para reconhecimento de objectos
Em primeiro lugar, criamos um fluxo de vídeo (vs) utilizando a biblioteca imutils, que irá obter as imagens da câmara.
vs = VideoStream(src=0, resolution=(1600, 1200)).start()
Inicializamos uma rede neural com os parâmetros de SSD-ModelNetV2 (net) utilizando a biblioteca TensorFlow.
model= tf.saved_model.load("./pretrained_models/ssd_mobilenet_v2_320x320_coco17_tpu-8/saved_model")
Uma função obtém os nomes das classes reconhecidas pelo modelo a partir do ficheiro 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))
Em seguida, criaremos um ciclo que, em cada iteração, lerá a imagem da câmara e passá-la-á para a entrada da rede neural para deteção e reconhecimento de objectos.
#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)
Por fim, o código apresenta a caixa de deteção na imagem, a probabilidade de reconhecimento e a posição.
# 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)
Código completo de reconhecimento de objectos com OpenCV e 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()
Fontes de imagem para deteção de objectos
Pode utilizar este script com diferentes fontes de imagem. Para tal, é necessário adaptar ligeiramente o código anterior para modificar a variável “img” que contém a imagem a analisar.
- A câmara Web do seu computador
vs = VideoStream(src=0, resolution=(1600, 1200)).start() while True: frame = vs.read()
O fluxo de vídeo deve ser interrompido no final do guião com vs.stop()
- Uma câmara IP
vc = cv2.VideoCapture('rtsp://user:password@ipaddress:rtspPort') while True: ret, frame=vc.read() #from ip cam
Certifique-se de que pára a captura de vídeo no final do guião com vc.release()
- O Raspberry Pi Picam
vs = VideoStream(usePiCamera=True, resolution=(1600, 1200)).start() while True: frame = vs.read()
Lembre-se de parar o fluxo no final do script com vs.stop()
- Um ficheiro de vídeo
vc = cv2.VideoCapture('./img/Splash - 23011.mp4') #from video while True: ret, frame=vc.read() #from video
- Um ficheiro de imagem
frame= cv2.imread('./img/two-boats.jpg')
Resultados
Para este exemplo, enviamos uma imagem de dois barcos como entrada para a rede neural, que são corretamente reconhecidos. Para obter resultados ligeiramente diferentes, pode modificar o parâmetro de confiança para evitar falsos positivos.
Pode testar este código com a sua webcam ou com fotografias, por exemplo, para ver o desempenho do modelo e do reconhecimento de objectos.
Quando o script estiver a funcionar, pode treinar o modelo para detetar outros objectos.
Pacotes e modelos
Neste tutorial, usamos o modelo pré-treinado SSD ModelNetV2. Vale a pena notar que existem outros modelos de classificação com desempenho e características diferentes.
- vgg16
- vgg19
- resnet50
- resnet101
- resnet152
- densenet121
- densenet169
- densenet201
- inceptionresnetv2
- inceptionv3
- mobilenet
- mobilenetv2
- nasnetlarge
- nasnetmobile
- exceção
Não hesite em deixar-nos um comentário para partilhar os modelos que utiliza ou conhece e a sua opinião.