Skip to content

Instantly share code, notes, and snippets.

@jerivas
Last active November 19, 2020 00:16
Show Gist options
  • Save jerivas/ff44a964f230ad403f01 to your computer and use it in GitHub Desktop.
Save jerivas/ff44a964f230ad403f01 to your computer and use it in GitHub Desktop.
Seguimiento de objetos por color. El script detecta objetos en base a colores y selecciona el más grande (por área). Se calcula la distancia del centroide del objeto al centro de la imagen.
*.pyc
*.pyo
*.db
.DS_Store
.coverage
*.sublime-project
*.sublime-workspace
*~
(lp1
(lp2
I30
aI50
aI60
aa(lp3
I45
aI255
aI255
aa.
numpy==1.15.2
opencv-python==3.4.3.18
# -*- coding: utf-8 -*-
# SCRIPT DE SEGUIMIENTO DE OBJETOS POR COLOR
# El script detecta objetos en base a colores y selecciona el más grande
# (por área). Se calcula la distancia del centroide del objeto al centro
# de la imagen. Se aplica acción controladora para mantener el objeto al
# centro de la imagen. Está acción se logra a través de servos conectados
# a un Arduino, el cual es controlado por el puerto serie de la PC.
# Por David Escobar, Ángel Moreno, Eduardo Rivas
# para la Universidad Don Bosco - Ciclo 2 - 2014
# Desarrollado en Python 2.7, OpenCV 2.4.8, Ubuntu 14.04
# Importar las librerías
import cv2 # OpenCV
import numpy as np # NumPy
# from serial import Serial # Puerto serie
import cPickle as pickle # Datos persistentes
def set_pallete_values(val):
"""
Callback que establece todos los valores de umbral HSV cada vez que cambia
uno en los sliders de control. También dibuja la paleta de colores.
"""
global colors, pallete
# Obtener los colores de los sliders iterando sobre ellos
for i, k in enumerate(["Low", "High"]):
for j, l in enumerate(["H", "S", "V"]):
colors[i][j] = cv2.getTrackbarPos(" ".join([k, l]), "Control")
# Actualizar la paleta de colores
cv2.rectangle(pallete, (0, 0), (149, 149), colors[0].tolist(), -1)
cv2.rectangle(pallete, (150, 0), (299, 149), colors[1].tolist(), -1)
pallete = cv2.cvtColor(pallete, cv2.COLOR_HSV2BGR)
cv2.imshow("Control", pallete)
# Nuevo puerto serie (para hablar con el Arduino)
# arduino = Serial("/dev/ttyACM0", 9600)
# Constantes relacionadas a los servos
servo_x = servo_y = 90 # Ángulo de inicio de los servos
step = 3 # Cantidad de ángulos que se ajustará en cada paso
threshold = 50 # Umbral de error (deadzone)
servo_max = 179 # Ángulo máximo
servo_min = 0 # Ángulo mínimo
# Establecer los servos a sus posiciones medias
# arduino.write("%s,%s\n" % (servo_x, servo_y))
# Ancho y alto del video que se desea capturar
frame_w = 640
frame_h = 480
# Coordenadas del centro del video
center_x = int(frame_w/2)
center_y = int(frame_h/2)
# Indices de las propiedades de video (no editar)
FRAME_PROP_WIDTH = 3
FRAME_PROP_HEIGHT = 4
# Cargar los colores a partir del archivo "colors.pickle"
with open("colors.pickle", "rb") as f:
colors = pickle.load(f)
colors[0] = np.array(colors[0], dtype=np.uint8) # Umbral inferior
colors[1] = np.array(colors[1], dtype=np.uint8) # Umbral superior
# Crear ventana de control
cv2.namedWindow("Control", flags=cv2.WINDOW_NORMAL)
cv2.resizeWindow("Control", 300, 600)
cv2.moveWindow("Control", 0, 0)
# Crear sliders de control con los valores de colores precargados
cv2.createTrackbar("Low H", "Control", colors[0][0], 179, set_pallete_values)
cv2.createTrackbar("Low S", "Control", colors[0][1], 255, set_pallete_values)
cv2.createTrackbar("Low V", "Control", colors[0][2], 255, set_pallete_values)
cv2.createTrackbar("High H", "Control", colors[1][0], 179, set_pallete_values)
cv2.createTrackbar("High S", "Control", colors[1][1], 255, set_pallete_values)
cv2.createTrackbar("High V", "Control", colors[1][2], 255, set_pallete_values)
# Crear paleta de colores y mostrarla en la ventana de control
pallete = np.zeros([150, 300, 3], dtype=np.uint8)
cv2.imshow("Control", pallete)
# Actualizar la paleta con los colores actuales
set_pallete_values(None)
# Iniciar captura de video con el tamaño deseado
cap = cv2.VideoCapture(0)
cap.set(FRAME_PROP_WIDTH, frame_w)
cap.set(FRAME_PROP_HEIGHT, frame_h)
# Repetir mientras halla señal de video
while cap.isOpened():
# Leer un frame
_, img = cap.read()
# Aplicar desenfoque para eliminar ruido
frame = cv2.blur(img, (15, 15))
# Convertir frame de BRG a HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# Aplicar threshold a la imagen y extraer los pixeles en el rango de color
thresh = cv2.inRange(hsv, colors[0], colors[1])
# Encontrar los contornos en la imagen extraída
img2, cnts, h = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# Encontrar el contorno de mayor área y especificarlo como best_cnt
max_area = 0
for cnt in cnts:
area = cv2.contourArea(cnt)
if area > max_area:
max_area = area
best_cnt = cnt
# Ejecutar este bloque solo si se encontró un área
if max_area > 0:
# Encontrar el centroide del mejor contorno y marcarlo
M = cv2.moments(best_cnt)
obj_x, obj_y = int(M["m10"]/M["m00"]), int(M["m01"]/M["m00"])
cv2.circle(img, (obj_x, obj_y), 5, 255, -1)
# Dibujar un rectángulo alrdedor del objeto
x, y, w, h = cv2.boundingRect(best_cnt)
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
# Dibujar una línea del centro del frame al centroide
cv2.line(img, (obj_x, obj_y), (center_x, center_y), 255, 2)
# Calcular el error en X y Y
error_x = center_x - obj_x
error_y = center_y - obj_y
# Este bloque if/else corresponde a dos controladores ON/OFF
# Controlador para error_x
if error_x < -threshold:
if servo_x < servo_max:
servo_x += step
else:
servo_x = servo_max
elif error_x > threshold:
if servo_x > servo_min:
servo_x -= step
else:
servo_x = servo_min
# Controlador para error_y
if error_y < -threshold:
if servo_y < servo_max:
servo_y += step
else:
servo_y = servo_max
elif error_y > threshold:
if servo_y > servo_min:
servo_y -= step
else:
servo_y = servo_min
# Si hay error, se envía la corrección calculada por los controladores
# al Arduino a través del puerto serie
# if (abs(error_x) > threshold) or (abs(error_y) > threshold):
# arduino.write("%s,%s\n" % (servo_x, servo_y))
# print(error_x, error_y, servo_x, servo_y)
# Se muestra el error en X y Y y la posición de los servos en pantalla
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, str(error_x), (30, 30), font, 0.8, 255, 2, 8)
cv2.putText(img, str(error_y), (120, 30), font, 0.8, 244, 2, 8)
cv2.putText(img, str(servo_x), (210, 30), font, 0.8, 244, 2, 8)
cv2.putText(img, str(servo_y), (280, 30), font, 0.8, 244, 2, 8)
# Mostrar la imagen original con todos los overlays
cv2.imshow("img", img)
# Mostrar la máscara con los pixeles extraídos
# cv2.imshow('thresh', thresh)
# Salir del bucle si se presiona ESC
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
# Limpieza y fin de programa
# arduino.close()
cap.release()
# Se guardan los colores configurados por los slider para la siguiente vez
with open("colors.pickle", "wb") as f:
pickle.dump([colors[0].tolist(), colors[1].tolist()], f)
cv2.destroyAllWindows()
# -*- coding: utf-8 -*-
# SCRIPT DE SEGUIMIENTO DE OBJETOS POR COLOR
# El script detecta objetos en base a colores y selecciona el más grande
# (por área). Se calcula la distancia del centroide del objeto al centro
# de la imagen.
# Por David Escobar, Ángel Moreno, Eduardo Rivas
# para la Universidad Don Bosco - Ciclo 2 - 2014
# Desarrollado en Python 2.7, OpenCV 2.4.8, Ubuntu 14.04
# Importar las librerías OpenCV y Numpy
import cv2
import numpy as np
from pwm import PWMPin
px = PWMPin(pin=10, freq=50, level=49)
py = PWMPin(pin=11, freq=50, level=49)
# Ancho y alto del video que se desea capturar
frame_w = 640
frame_h = 480
# Coordenadas del centro del video
fcx = int(frame_w/2)
fcy = int(frame_h/2)
# Indices de las propiedades de video (no editar)
FRAME_PROP_WIDTH = 3
FRAME_PROP_HEIGHT = 4
# Definir rango de color a identificar (HSV)
lower_color = np.array([90, 90, 90], dtype=np.uint8)
upper_color = np.array([120, 255, 255], dtype=np.uint8)
# Iniciar captura de video con el tamaño deseado
cap = cv2.VideoCapture(0)
cap.set(FRAME_PROP_WIDTH, frame_w)
cap.set(FRAME_PROP_HEIGHT, frame_h)
px.enable = py.enable = 1
# Repetir mientras halla señal de video
while cap.isOpened():
# Leer un frame
_, img = cap.read()
# Aplicar desenfoque para eliminar ruido
frame = cv2.blur(img, (15, 15))
# Convertir frame de BRG a HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# Aplicar umbral a la imagen y extraer los pixeles en el rango de colores
thresh = cv2.inRange(hsv, lower_color, upper_color)
# Encontrar los contornos en la imagen extraída
cnts, h = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# Encontrar el contorno de mayor área y especificarlo como best_cnt
max_area = 0
for cnt in cnts:
area = cv2.contourArea(cnt)
if area > max_area:
max_area = area
best_cnt = cnt
# Ejecutar este bloque solo si se encontró un área
if max_area > 0:
# Encontrar el centroide del mejor contorno y marcarlo
M = cv2.moments(best_cnt)
cx, cy = int(M['m10']/M['m00']), int(M['m01']/M['m00'])
cv2.circle(img, (cx, cy), 5, 255, -1)
# Dibujar un rectángulo alrdedor del objeto
x, y, w, h = cv2.boundingRect(best_cnt)
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
# Dibujar una línea del centro del frame al centroide
cv2.line(img, (cx, cy), (fcx, fcy), 255, 2)
# Calcular el error en X y Y y mostrarlo como texto
errx = fcx - cx
erry = fcy - cy
if errx > 100:
if px.level < 79:
px.level += 1
else:
px.level = 79
elif errx < -100:
if px.level > 19:
px.level -= 1
else:
px.level = 19
if erry < -100:
if py.level < 79:
py.level += 1
else:
py.level = 79
elif erry > 100:
if py.level > 19:
py.level -= 1
else:
py.level = 19
# print(errx, erry, px.level, py.level)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, str(errx), (30, 30), font, 0.8, 255, 2, 8)
cv2.putText(img, str(erry), (120, 30), font, 0.8, 244, 2, 8)
cv2.putText(img, str(px.level), (210, 30), font, 0.8, 244, 2, 8)
cv2.putText(img, str(py.level), (280, 30), font, 0.8, 244, 2, 8)
# Mostrar la imagen original con todos los overlays
cv2.imshow('img', img)
# Mostrar la máscara con los pixeles extraídos
cv2.imshow('thresh', thresh)
# Salir del bucle si se presiona ESC
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
# Limpieza y fin de programa
px.level = py.level = 49
px.enable = py.enable = 0
cap.release()
cv2.destroyAllWindows()
@aliculin
Copy link

hola tienes el codigo en version actual de python

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment