Logo Studenta

Práctica 7

¡Este material tiene más páginas!

Vista previa del material en texto

1 
 
INSTITUCIÓN: TECNOLÓGICO DE LA LAGUNA 
 
CARRERA: MECATRÓNICA 
 
MATERIA: SENSORES INTELIGENTES 
 
DOCENTE: HERRERA CARRILLO NAZLE EDITH 
 
ALUMNO: RODRÍGUEZ GUERRA EDUARDO ANTONIO 
 
MATRICULA: 19131252 
 
PRÁCTICA 7: DETECCIÓN DE COLORES EN VIDEO 
 
FECHA DE ENTREGA: 31 DE MARZO DE 2023 
 
2 
 
La finalidad de la presente practica es que una vez que adquirimos las competencias necesarias, para la 
extracción de información a imágenes y videos, por medio de diferentes elementos, trabajemos con dicha 
información a fin de re accionar un servomotor dependiendo de la posición de un objeto por medio de Arduino. 
Es importante destacar que el reconocimiento y el procesamiento del video lo realizamos por medio Python y 
open cv, el Arduino solo lo usamos para expresar la salida ante determinados datos arrojados por los programas 
antes mencionados. 
 
 
Básicamente abriremos el video y en tiempo real encontraremos la posición de objetos de un cierto color, colocando en la pantalla la posición del objeto 
detectado, aparte usaremos de una librería “serial” para comunicarnos con el Arduino y accionar diferentes ángulos de un servo, son solo recibir palabras 
diferentes al detectar el color. 
Programa en Python: 
import cv2 
import NumPy as np 
import serial 
 
COM = 'COM5' 
BAUD = 9600 
ser = serial.Serial(COM, BAUD) 
 
cap = cv2.VideoCapture(0) 
azulBajo = np.array([90, 100, 20], np.uint8) 
azulAlto = np.array([120, 255, 255], np.uint8) 
while True: 
 ret, frame = cap.read() 
 if ret: 
 frame = cv2.flip(frame, 1) 
 frameHSV = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) 
 mascara = cv2.inRange(frameHSV, azulBajo, azulAlto) 
 contornos, _ = cv2.findContours(mascara, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 
 cv2.drawContours(frame, contornos, -1, (255, 0, 0), 4) 
 
 for c in contornos: 
 area = cv2.contourArea(c) 
 if area > 6000: 
 M = cv2.moments(c) 
 if M["m00"] == 0: 
3 
 
 M["m00"] = 1 
 x = int(M["m10"] / M["m00"]) 
 y = int(M['m01'] / M['m00']) 
 cv2.circle(frame, (x, y), 7, (0, 0, 255), -1) 
 font = cv2.FONT_HERSHEY_SIMPLEX 
 cv2.putText(frame, '{},{}'.format(x, y), (x + 10, y), font, 1.2, (0, 0, 255), 2, cv2.LINE_AA) 
 nuevoContorno = cv2.convexHull(c) 
 cv2.drawContours(frame, [nuevoContorno], 0, (255, 0, 0), 3) 
 
 if x < 200: 
 print("Mover a la izquierda 100%") 
 ser.write(b"izq1\n") 
 elif 420 > x >= 200: 
 print("Mover a la izquierda 60%") 
 ser.write(b"izq2\n") 
 elif 520 > x >= 420: 
 print("Mover a la izquierda 30%") 
 ser.write(b"izq3\n") 
 # Mover al centro 
 elif 520 <= x < 650: 
 print("Mover al centro") 
 ser.write(b"ctr\n") 
 elif 650 <= x < 860: 
 print("moviendo a la derecha 30%") 
 ser.write(b"der3\n") 
 elif 860 <= x < 1080: 
 print("moviendo a la derecha 60%") 
 ser.write(b"der2\n") 
 elif x >= 1080: 
 print("Moviendo a la derecha 100%") 
 ser.write(b"der1\n") 
 
 # cv2.imshow('mascaraAzul', mascara) 
 cv2.imshow('frame', frame) 
 if cv2.waitKey(1) & 0xFF == ord('s'): 
 ser.close() 
 break 
cap.release() 
cv2.destroyAllWindows() 
 
4 
 
Asignamos las librerías para el procesamiento de imágenes (open cv, numpy), además de una librería para escribir en el puerto serial 
import cv2 
import numpy as np 
import serial 
 
Después asignamos el puerto COM al que este conectad el Arduino, seguido de la velocidad de transmisión de datos para Arduino (9600), en caso de que use otra tarjeta 
variar este dato en función de la datasheet, ser es una variable. 
COM = 'COM5' 
BAUD = 9600 
ser = serial.Serial(COM, BAUD) 
 
 
Este comando mágico, nos da acceso a la cámara de la computadora para tomar prestada la imagen que esta detecte dentro del paréntesis ira un numero de acuerdo a 
la cantidad de cámaras que tenga el dispositivo. 
cap = cv2.VideoCapture(0) 
 
Ahora si viene lo emocionante, en las siguientes variables designaremos un rango de colores que detectará el programa para la extracción de datos, ósea si someto la 
cámara a colores dentro de otro rango simplemente no los reconocerá. Cabe destacar que el rango se selecciona de acuerdo a esta gama de colores en HSV. 
 
 
 
5 
 
azulBajo = np.array([90, 100, 20], np.uint8) 
azulAlto = np.array([120, 255, 255], np.uint8) 
 
“Dentro del ciclo while tendremos el código que se ejecutará continuamente. Aquí vamos a describir la primer línea: ret, frame = cap.read() con ella obtenemos dos 
variables ret y frame. En ret se almacena un true si se realizó una captura de manera correcta y frame es la imagen capturada por la webcam.” 
AbrahamG-2021 
En caso de que tengamos un objeto frente la cámara dentro del rango de colores, ingresaremos al if . 
Dentro del if reflejamos la imagen para ser capaces de analizarla mejor, y sigue esta parte del código frameHSV = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) 
Convertimos el espacio de color BGR a HSV, BGR es el formato en que se toma la imagen atreves de la cámara del equipo. 
Después crea una mascara con los limites superior e inferior de los colores que deseemos detectar, así le aplicamos una operación para detectar contornos, y por último 
dibujamos los contornos sobre la imagen original. Para dibujarla utilizamos la función cv2.drawContours además le agregamos el color que deseamos que utilice para 
destacar los contornos, en mi caso elegí un color azul muy marcado (255,0,0) recordando que OpenCV utiliza un formato (B,G,R). 
while True: 
 ret, frame = cap.read() 
 if ret: 
 frame = cv2.flip(frame, 1) 
 frameHSV = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) 
 mascara = cv2.inRange(frameHSV, azulBajo, azulAlto) 
 contornos, _ = cv2.findContours(mascara, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 
 cv2.drawContours(frame, contornos, -1, (255, 0, 0), 4) 
 
De ahí sigue la verificación del centroide, ósea por medio del if preguntamos si el área del contorno es mayor a 600 entonces buscará centroide. 
for c in contornos: 
 area = cv2.contourArea(c) 
 if area > 6000: 
 
Ahora calculamos los momentos M = cv2.moments(c) y revisamos que si el momento «m00» es igual a cero, lo igualamos a 1, ya que realizaremos una división y dividir 
entre 0 es infinito y luego aparecerá un error. 
M = cv2.moments(c) 
 if M["m00"] == 0: 
 M["m00"] = 1 
 x = int(M["m10"] / M["m00"]) 
 y = int(M['m01'] / M['m00']) 
 
6 
 
Una vez que hicimos las divisiones dibujamos un círculo, que contendrá las coordenadas del centroide en color rojo, lo que le sigue del código solo da más formato a 
dicho texto: 
cv2.circle(frame, (x, y), 7, (0, 0, 255), -1) 
 font = cv2.FONT_HERSHEY_SIMPLEX 
 cv2.putText(frame, '{},{}'.format(x, y), (x + 10, y), font, 1.2, (0, 0, 255), 2, cv2.LINE_AA) 
 
Crearemos un nuevo contorno en caso de que la figura sea irregular, colocando puntos y cerrando la imagen, para trabajarla como lo hicimos anteriormente. 
nuevoContorno = cv2.convexHull(c) 
cv2.drawContours(frame, [nuevoContorno], 0, (255, 0, 0), 3) 
 
Ojo con esta imagen ya que el autor original 
 Dividirá la imagen para establecer fronteras así asignará en que momentos el servo cambiará de posición. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
if x < 200: 
 print("Mover a la izquierda 100%") 
 ser.write(b"izq1\n")elif 420 > x >= 200: 
 print("Mover a la izquierda 60%") 
 ser.write(b"izq2\n") 
 elif 520 > x >= 420: 
 print("Mover a la izquierda 30%") 
 ser.write(b"izq3\n") 
 # Mover al centro 
 elif 520 <= x < 650: 
 print("Mover al centro") 
 ser.write(b"ctr\n") 
 elif 650 <= x < 860: 
 print("moviendo a la derecha 30%") 
 ser.write(b"der3\n") 
 elif 860 <= x < 1080: 
 print("moviendo a la derecha 60%") 
 ser.write(b"der2\n") 
 elif x >= 1080: 
 print("Moviendo a la derecha 100%") 
 ser.write(b"der1\n") 
7 
 
Establecemos lo que hará el programa cuando las coordenadas del centroide superan algunas de las fronteras 
La tabla anexada nos muestra lo que realizara el Arduino ante determinados comandos que reciba en el serial port. 
En el ultimo fragmento del programa en Python mostramos la imagen ya con todos los contornos y centroides que tenga, 
además de agregar el gran detalle de que en caso de que en medio de la ejecución aprietes la tecla S el programa se detendrá 
por sí solo. 
 
 
 
 
 
 
 
cv2.imshow('frame', frame) 
 if cv2.waitKey(1) & 0xFF == ord('s'): 
 ser.close() 
 break 
cap.release() 
cv2.destroyAllWindows() 
 
 
 
 
 
 
 
 
 
 
 
 
8 
 
Codigo para arduino: 
#include <Servo.h> 
Servo servo1; 
 
String entradaSerial = ""; // String para almacenar entrada 
bool entradaCompleta = false; // Indicar si el String está completo 
 
int pin = 9; // pin de conexión PWM al servo 
int pulsoMinimo = 580; // Duración en microsegundos del pulso para girar 0º 
int pulsoMaximo = 2500; // Duración en microsegundos del pulso para girar 180º 
int angulo = 0; // Variable para guardar el angulo que deseamos de giro 
 
void setup() 
{ 
 servo1.attach(pin, pulsoMinimo, pulsoMaximo); 
 Serial.begin(9600); 
} 
 
void loop() 
{ 
 if (entradaCompleta) { 
 if (entradaSerial == "izq1\n") { 
 Serial.print("0 grados\n"); 
 // Mandamos escribir el angulo deseado del giro. 
 servo1.write(0); 
 } 
 else if (entradaSerial == "izq2\n") { 
 Serial.print("30 grados\n"); 
 // Mandamos escribir el angulo deseado del giro. 
 servo1.write(30); 
 } 
 else if (entradaSerial == "izq3\n") { 
 Serial.print("60 grados\n"); 
 // Mandamos escribir el angulo deseado del giro. 
 servo1.write(60); 
 } 
 else if (entradaSerial == "ctr\n") { 
 Serial.print("Centro 90 grados\n"); 
 // Mandamos escribir el angulo deseado del giro. 
 servo1.write(90); 
 } 
 else if (entradaSerial == "der3\n") { 
 Serial.print("120 grados\n"); 
 // Mandamos escribir el angulo deseado del giro. 
 servo1.write(120); 
 } 
 else if (entradaSerial == "der2\n") { 
 Serial.print("150 grados\n"); 
 // Mandamos escribir el angulo deseado del giro. 
 servo1.write(150); 
 } 
 else if (entradaSerial == "der1\n") { 
 Serial.print("180 grados\n"); 
 // Mandamos escribir el angulo deseado del giro. 
 servo1.write(180); 
 } 
 else { // Cualquier otro dato recibido 
 Serial.println("El dato recibido es inválido!!"); 
 } 
 entradaSerial = ""; 
 entradaCompleta = false; 
9 
 
 } 
} 
 
// Función que se activa al recibir algo por 
// el puerto serie, Interrupción del Puerto Serie. 
void serialEvent() { 
 while (Serial.available()) { 
 // Obtener bytes de entrada: 
 char inChar = (char)Serial.read(); 
 // Agregar al String de entrada: 
 entradaSerial += inChar; 
 // Para saber si el string está completo, se detendrá al recibir 
 // el caracter de retorno de línea ENTER \n 
 if (inChar == '\n') { 
 entradaCompleta = true; 
 } 
 } 
} 
 
 
Empleamos de la libreria para girar el servomotor conforme reciba indicaciones del serial port. 
Imágenes de ejecución de práctica: 
10 
 
 
11 
 
 
12 
 
Conclusiones: 
En lo particular esta ha sdio mi práctica favorita ya que aparte de ser la más dificil fue la primera donde empleamos del analisis de imagenes para controlar un proceso, esto se está poniendo interesante, es importante destacar que tal y 
como indica el autor, la luz altera mucho la caidad del video, pues al correr el programa en mi casa como estoy debajo de la lampara, tengo una iluminación considerable, pues dichailuminación me provocaba detecciones de objetos que 
no existian, para correguir eso solo tuve que cambiar el coigo justo en el if de 6000, o una idea que se me ocurrio en un principio ir a un lugar con iluminación más variada. 
Y tambien esta prática me permitio comprender mejor la importancia del orden dentro de la programación en python ya que dure media hora buscando un error de sintaxis en el programa, y solo era que los ultimos comandos estaban 
un paso delante de su posición, me quedaré con el codigo para cerrar programas al apretar una tecla, valla que me será util, por ultimo me gustaria destacar que tengo que abrir python como administrador ya que de lo contrario no me 
dejaba leer el puerto donde estuviese el arduino de ahí en fuera todo chid, hasta el tiempo de respuesta, que era fluido para considerar la complejidad de lo que estaba llevando acabo.

Continuar navegando