"Lo siento, reconocí ..." o reconoce frambuesas y controladores utilizando la API de detección de objetos de Tensorflow

A fines del año pasado, escribí un artículo sobre cómo me intrigaba la capacidad de reconocer objetos en imágenes usando redes neuronales. En ese artículo, usando PyTorch, categorizamos las frambuesas o un controlador tipo arduino en video. Y a pesar del hecho de que me gustaba PyTorch, recurrí a él porque no podía tratar con TensorFlow de inmediato. Pero prometí que volveré al tema del reconocimiento de objetos en el video. Parece que ha llegado el momento de cumplir la promesa.

En este artículo, probaremos en nuestra máquina local para volver a entrenar el modelo terminado en Tensorflow 1.13 y la API de detección de objetos en nuestro propio conjunto de imágenes, y luego lo usaremos para reconocer bayas y controladores en la transmisión de video de una cámara web usando OpenCV.

¿Quieres mejorar tu habilidad de reconocimiento de bayas para el verano? Entonces eres bienvenido bajo cat.



Contenido:

Parte I: introducción
Parte II: entrenar el modelo en TenosrFlow
Parte III: aplicar el modelo en OpenCV
Parte IV: conclusión

Parte I: Introducción


Quienes han leído el artículo anterior sobre PyTorch ya saben que soy un aficionado en cuestiones de redes neuronales. Por lo tanto, no percibas este artículo como la verdad última. Pero de todos modos, espero poder ayudar a alguien a lidiar con los conceptos básicos del reconocimiento de video utilizando la API de detección de objetos de Tensorflow.

Esta vez no intenté hacer un tutorial, por lo que el artículo será más corto de lo habitual.
Para empezar, el tutorial oficial sobre el uso de la API de detección de objetos en una máquina local, por decirlo suavemente, no es exhaustivo. Como novato, era completamente inadecuado y tenía que centrarme en los artículos del blog.

Para ser sincero, me gustaría probar TensorFlow 2.0, pero en la mayoría de las publicaciones, en el momento de escribir este artículo, los problemas de migración no se resolvieron por completo. Por lo tanto, al final, me decidí por TF 1.13.2.

Parte II: enseñando un modelo en TensorFlow


Aprendí instrucciones para enseñar el modelo de este artículo , o más bien de su primera mitad, hasta que se aplicó JavaScript (si no habla inglés, puede ver un artículo sobre el mismo tema en Habré ) .

Es cierto que en mi caso hay varias diferencias:

  1. Usé Linux porque Anaconda para Linux ya ha construido protobuf y pycocoapi, así que no tuve que construirlos yo mismo.
  2. TensorFlow 1.13.2, Object Detection API 1.13 , TensorFlow 1.13.2. master TF 1.15, 1.13.
  3. numpy — 1.17.5, 1.18 .
  4. faster_rcnn_inception_v2_coco ssd_mobilenet_v2_coco, , .

Por las dudas, diré que no utilicé un acelerador de gráficos. La capacitación se llevó a cabo solo en las capacidades del procesador.

Se puede descargar un conjunto de imágenes, un archivo de configuración, un gráfico guardado, así como un script para reconocer imágenes usando OpenCV, como siempre, desde GitHub .

Han pasado 23 horas de entrenamiento modelo, todo el té en la casa ya se ha bebido, "¿Qué? ¿Dónde? ¿Cuando?" inspeccionado y ahora mi paciencia finalmente llegó a su fin.

Dejamos de entrenar y guardamos el modelo.

Instale OpenCV en el mismo entorno de "Anaconda" con el siguiente comando:

conda install -c conda-forge opencv

Finalmente instalé la versión 4.2

Además, las instrucciones de este artículo ya no las necesitaremos.

Después de guardar el modelo, cometí un error que no era obvio para mí, a saber, inmediatamente intenté sustituir el archivo graph.pbtxt utilizado anteriormente en la carpeta de entrenamiento / en la función:

cv2.dnn.readNetFromTensorflow()

Desafortunadamente, esto no funciona de esta manera y tendremos que hacer una manipulación más para obtener graph.pbtxt para OpenCV.

Lo más probable es que el hecho de que ahora aconseje no sea una buena manera, pero para mí funciona.

Descargue tf_text_graph_ssd.py , y también tf_text_graph_common.py póngalos en la carpeta donde está nuestro gráfico guardado (tengo esta carpeta inference_graph).
Luego vaya a la consola en esta carpeta y ejecute desde ella un comando de aproximadamente los siguientes contenidos:

python tf_text_graph_ssd.py --input frozen_inference_graph.pb --config pipeline.config --output graph.pbtxt

Y eso es todo lo que queda para subir nuestro modelo a OpenCV.


Parte III: aplique el modelo en OpenCV


Como en el artículo sobre PyTorch sobre el trabajo con OpenCV, tomé como base el código del programa de esta publicación .

Hice pequeños cambios para simplificarlo un poco más, pero como no entiendo completamente el código, no lo comentaré. Funciona y agradable. Está claro que el código podría haber sido mejor, pero todavía no tengo tiempo para sentarme para los tutoriales de OpenCV .

Código OpenCV

# USAGE
# based on this code https://proglib.io/p/real-time-object-detection/
# import the necessary packages
from imutils.video import VideoStream
from imutils.video import FPS
import numpy as np
import imutils
import time
import cv2

prototxt="graph.pbtxt"
model="frozen_inference_graph.pb"
min_confidence = 0.5

# initialize the list of class labels MobileNet SSD was trained to
# detect, then generate a set of bounding box colors for each class
CLASSES = ["background", "duino","raspb"]
COLORS = [(40,50,60),((140,55,130)),(240,150,25)]

# load our serialized model from disk
print("[INFO] loading model...")

net =cv2.dnn.readNetFromTensorflow(model,prototxt)

# initialize the video stream, allow the cammera sensor to warmup,
# and initialize the FPS counter
print("[INFO] starting video stream...")
vs = VideoStream(src=0).start()
time.sleep(0.5)
fps = FPS().start()

# loop over the frames from the video stream
while True:
	# grab the frame from the threaded video stream and resize it
	# to have a maximum width of 400 pixels
	frame = vs.read()
	frame = imutils.resize(frame, width=300)

	# grab the frame dimensions and convert it to a blob
	(h, w) = frame.shape[:2]
	blob = cv2.dnn.blobFromImage(frame, size=(300, 300), swapRB=True)

	# pass the blob through the network and obtain the detections and
	# predictions
	net.setInput(blob)
	detections = net.forward()

	# loop over the detections
	for i in np.arange(0, detections.shape[2]):
		# extract the confidence (i.e., probability) associated with
		# the prediction
		print (detections)
		confidence = detections[0, 0, i, 2]

		if confidence > min_confidence:
			# extract the index of the class label from the
			# `detections`, then compute the (x, y)-coordinates of
			# the bounding box for the object
			idx = int(detections[0, 0, i, 1])
			box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
			(startX, startY, endX, endY) = box.astype("int")

			# draw the prediction on the frame
			label = "{}: {:.2f}%".format(CLASSES[idx],
				confidence * 100)
			cv2.rectangle(frame, (startX, startY), (endX, endY),
				COLORS[idx], 2)
			y = startY - 15 if startY - 15 > 15 else startY + 15
			cv2.putText(frame, label, (startX, y+3),
				cv2.FONT_HERSHEY_SIMPLEX, 0.5, COLORS[idx], 1)

	# show the output frame
	cv2.imshow("Frame", frame)
	key = cv2.waitKey(1) & 0xFF

	# if the `q` key was pressed, break from the loop
	if key == ord("q"):
		break

	# update the FPS counter
	fps.update()

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

# do a bit of cleanup
cv2.destroyAllWindows()
vs.stop()


Entonces, todo está listo. Lanzamos el modelo, apuntamos la lente a mi viejo CraftDuino y disfrutamos del resultado:



a primera vista, no está nada mal, pero es solo a primera vista.
Parece que en 23 horas, el modelo fue reentrenado, por lo tanto, produce errores graves al definir objetos.

Aquí hay una demostración visual:



como puede ver, no solo un cuchillo, sino incluso un fondo negro, este modelo lo define como un controlador tipo arduino. Quizás esto se deba a que en los datos de entrenamiento había imágenes oscuras con el Arduino y sus análogos, en las que el modelo logró toparse en 23 horas.

Como resultado, tuve que cargar mi computadora durante otras 8 horas y entrenar un nuevo modelo.

Las cosas están mucho mejor con ella.

Aquí hay un ejemplo con CraftDuino:



Las frambuesas vivas no están a la mano. Tuve que imprimir fotos. Desde la pantalla del teléfono o monitor, también puede reconocer, pero desde el papel fue más conveniente.



Veamos cómo el modelo reconoce el Arduino nano, que a su debido tiempoDrzugrikpara mí, soldaré a mi mega dispositivo con sensores:



como puede ver, reconoce bastante bien, pero con un ángulo muy pobre y con una iluminación cálida, puede reconocer algunos fragmentos como las frambuesas. Pero, de hecho, un marco con un error fue difícil de atrapar en la lente.

Ahora veamos cómo clasifica esos objetos en los que no fue entrenada.

De nuevo, un ejemplo con un cuchillo y un fondo negro:



esta vez todo funciona como debería.

Ofreceremos nuestro modelo para reconocer el pequeño controlador Canny 3, sobre el que escribí en un artículo anterior .



Dado que nuestro modelo no conoce nada más que frambuesas y controladores similares a arduino, podemos decir que el modelo reconoció el controlador Canny con bastante éxito.

Es cierto que, como en el caso del Arduino nano, mucho depende del ángulo y la iluminación.

Con la luz cálida de una lámpara incandescente y con un ángulo fallido, el controlador puede no solo no ser reconocido, sino incluso definido como frambuesa. Es cierto que, como en el caso anterior, estos ángulos todavía tenían que intentar atrapar la lente.



Bueno, el último caso es una especie de reverencia para el artículo sobre la clasificación de imágenes en PyTorch . Como la última vez, la computadora de placa única Raspberry Pi 2 y su logotipo son compatibles en un solo cuadro. A diferencia del artículo anterior, en el que resolvimos el problema de clasificación y elegimos un objeto más probable para la imagen, en este caso se reconoce tanto el logotipo como la propia Frambuesa.




Parte IV: Conclusión


En conclusión, quiero decir que, a pesar de la inexperiencia de este pequeño ejemplo de trabajo con la API de detección de objetos de Tensorflow, me tomó dos días libres y parte del lunes, no me arrepiento de nada. Cuando al menos un poco de comprensión sobre cómo usarlo todo se vuelve increíblemente curioso. En el proceso de aprendizaje, comienza a considerar el modelo como uno vivo, sigue sus éxitos y fracasos.
Por lo tanto, recomiendo a todos los que no estén familiarizados con esto algún día que traten de reconocer algo propio.

Además, como ha aumentado en el proceso, ni siquiera necesita comprar una cámara web real. El hecho es que durante la preparación del artículo, logré romper mi cámara web (rompí el mecanismo de enfoque) y ya pensé que tendría que abandonar todo. Pero resultó que con la ayuda de Droidcam puede usar un teléfono inteligente en lugar de una cámara web (no cuente para publicidad). Además, la calidad de disparo resultó ser mucho mejor que la de una cámara rota, y esto influyó mucho en la calidad del reconocimiento de objetos en la imagen.

Por cierto, ya que Anaconda tiene una construcción normal de picocotolesEncontré solo para Linux, y era demasiado flojo para cambiar entre sistemas operativos, preparé este artículo completo solo con software de código abierto. Había análogos de Word y Photoshop e incluso un controlador para la impresora. La primera vez en mi vida esto sucedió. Resultó que las versiones modernas del sistema operativo Linux y los programas de aplicación pueden ser muy convenientes, incluso para una persona que usa el sistema operativo Microsoft por más de 25 años.

PD: si alguien sabe cómo ejecutar correctamente la API de detección de objetos
para Tensorflow versión 2 y superior, cancele la suscripción en PM o en un comentario.

¡Que tengas un buen día y buena salud!

All Articles