?️ Marcador o Lápiz virtual | OpenCV – Python
Te doy la bienvenida a un nuevo post, en el que te mostraré como puedes realizar un marcador o lápiz virtual (similar a paint), con el que ¡podrás dibujar en el aire!. Además podrás escoger de entre algunos colores así como el grosor de línea, también veremos como borrar la pantalla completa, es decir borrar todos los trazos realizados.
CONTENIDO:
- Declarando variables
- Leemos frame y aplicamos cv2.flip
- Transformamos de BGR a HSV
- Creación de un lienzo
- Construcción de la sección superior de la pantalla, en donde estarán las opciones de dibujo
- Detección del color del objeto (marcador / lápiz virtual)
- Encontrando contornos
- Estableciendo un área mínima para la detección y obteniendo las coordenadas para realizar los trazos
- Seleccionando colores para dibujar
- Seleccionando el grosor de los trazos para dibujar
- Seleccionando ‘Limpiar pantalla’
- Dibujando los trazos
- Dibujando sobre el videostreaming
- Programación completa
- Referencias
Lo primero que haremos es detectar un color, que corresponderá al color del objeto con el que vamos a dibujar, luego construiremos en la parte superior de la visualización un pequeño menú para elegir los colores con los cuales dibujar, limpiar la pantalla y elegir el grosor de los trazos.
NOTA: Te recomiendo visitar el link que tomé como referencia para la realización de este post.
Declarando variables
Empezaremos a declarar algunas variables que nos serán de ayuda para esta aplicación, veamos:
import cv2 import numpy as np cap = cv2.VideoCapture(0,cv2.CAP_DSHOW) celesteBajo = np.array([75, 185, 88], np.uint8) celesteAlto = np.array([112, 255, 255], np.uint8) # Colores para pintar colorCeleste = (255,113,82) colorAmarillo = (89,222,255) colorRosa = (128,0,255) colorVerde = (0,255,36) colorLimpiarPantalla = (29,112,246) # Solo se usará para el cuadro superior de 'Limpiar Pantalla' # Grosor de línea recuadros superior izquierda (color a dibujar) grosorCeleste = 6 grosorAmarillo = 2 grosorRosa = 2 grosorVerde = 2 # Grosor de línea recuadros superior derecha (grosor del marcador para dibujar) grosorPeque = 6 grosorMedio = 1 grosorGrande = 1 #--------------------- Variables para el marcador / lápiz virtual ------------------------- color = colorCeleste # Color de entrada, y variable que asignará el color del marcador grosor = 3 # Grosor que tendrá el marcador #------------------------------------------------------------------------------------------ x1 = None y1 = None imAux = None
Línea 1 y 2: Importamos OpenCV y Numpy.
Línea 4: Indicamos que vamos a realizar un video Streaming.
Línea 6 y 7: Declaramos las variables que corresponden al rango del color que deseamos detectar en el espacio de color HSV. En mi caso usaré la tapa de un bolígrafo de color celeste, por ello he determinado celesteBajo
y celesteAlto
que me ayudarán a detectar dicho color. Si tienes alguna duda con respecto a este procedimiento, puedes visitar estos posts: Detección de colores en OpenCV – Python (En 4 pasos) y DETECCIÓN DE COLORES Y Tracking en OpenCV – Parte2 en donde explico de forma más extendida este tema.
Línea 10 a 14: De la línea 10 a la 13 asignamos a variables los colores con los que deseamos dibujar, y en la línea 14 en cambio asignamos el color que va a obtener el rectángulo ‘Limpiar Ventana’.
Línea 17 a 20: Estas variables nos ayudarán con el grosor de los recuadros de la parte superior izquierda, en donde el usuario podrá escoger de entre los 4 colores: celeste, amarillo, rosa y verde. Además podremos resaltar el color seleccionado.
Línea 23 a 25: Estas variables en cambio nos ayidarán para los recuadros de la parte superior derecha, en donde se podrá el distinto tamaño o grosor de línea. Además podremos resaltar el recuadro seleccionado.
Línea 28: Declaramos la variable color
, a este le asignaremos por defecto el color azul/celeste para que dibuje este en un inicio. A esta variable además se le asignará los colores del 10 al 13, dependiendo de lo que haya elegido el usuario.
Línea 29: Declaramos la variable grosor
, esta nos servirá para asignar el grosor que tendrá la línea a dibujar. A esta variable además se le asignarán otros valores, de acuerdo a lo que elija el usuario.
Línea 32 y 33: Declaramos x1
y y1
como None
, a estas dos variables luego se les asignará la posición anterior, de acuerdo a como se vaya moviendo el objeto.
Línea 34: Declaramos imAux
como None
, esta variable nos ayudará luego, para construir un lienzo en donde se dibujarán los trazos.
Leemos frame y aplicamos cv2.flip
Lo primero que haremos es leer los fotogramas, luego aplicaremos cv2.flip
para obtener el efecto de espejo.
while True: ret,frame = cap.read() if ret==False: break frame = cv2.flip(frame,1)
Línea 38: Se leen los fotogramas y se almacenan en frame
.
Línea 41: Aplicamos cv2.flip
, a la variable frame
, para poder obtener el efecto espejo (puedes visitar este post: cv2.flip y Efecto ESPEJO en Python – OpenCV si deseas más información sobre esta función).
Transformar de BGR a HSV
Para realizar la transformación de espacios de color, necesitaremos de la función cv2.cvtColor
.
frameHSV = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
Creación de un lienzo
Vamos a crear un imagen o matriz de ceros, del mismo tamaño de frame
, sobre ella luego realizaremos los trazos.
if imAux is None: imAux = np.zeros(frame.shape,dtype=np.uint8)
Construcción de la sección superior de la pantalla, en donde estarán las opciones de dibujo
Ahora necesitamos distribuir las opciones de dibujo en la parte superior de la pantalla, veamos:
#------------------------ Sección Superior ------------------------------------------ # Cuadrados dibujados en la parte superior izquierda (representan el color a dibujar) cv2.rectangle(frame,(0,0),(50,50),colorAmarillo,grosorAmarillo) cv2.rectangle(frame,(50,0),(100,50),colorRosa,grosorRosa) cv2.rectangle(frame,(100,0),(150,50),colorVerde,grosorVerde) cv2.rectangle(frame,(150,0),(200,50),colorCeleste,grosorCeleste) # Rectángulo superior central, que nos ayudará a limpiar la pantalla cv2.rectangle(frame,(300,0),(400,50),colorLimpiarPantalla,1) cv2.putText(frame,'Limpiar',(320,20),6,0.6,colorLimpiarPantalla,1,cv2.LINE_AA) cv2.putText(frame,'pantalla',(320,40),6,0.6,colorLimpiarPantalla,1,cv2.LINE_AA) # Cuadrados dibujados en la parte superior derecha (grosor del marcador para dibujar) cv2.rectangle(frame,(490,0),(540,50),(0,0,0),grosorPeque) cv2.circle(frame,(515,25),3,(0,0,0),-1) cv2.rectangle(frame,(540,0),(590,50),(0,0,0),grosorMedio) cv2.circle(frame,(565,25),7,(0,0,0),-1) cv2.rectangle(frame,(590,0),(640,50),(0,0,0),grosorGrande) cv2.circle(frame,(615,25),11,(0,0,0),-1) #-----------------------------------------------------------------------------------
Línea 47 a 50: Creamos 4 cuadrados en la parte superior izquierda, que corresponderán a los 4 colores que podremos escoger para dibujar. Su orden será: cuadrado de color amarillo, luego rosa, verde y por último celeste.
Línea 53 a 55: Creamos un rectángulo en la sección central superior de la pantalla, dentro de este se visualizará 'Limpiar Pantalla'
.
Línea 58 a 63: Creamos 3 cuadrados en la parte superior derecha de la pantalla, dentro de estos se podrán visualizar círculos correspondientes a los distintos grosores a escoger.
Detección del color del objeto (marcador / lápiz virtual)
Como te decía, voy a usar la tapa de un lapicero celeste para poder realizar los trazos, por lo que ahora necesitamos encontrar en frameHSV
el color celeste, para ello usamos el rango que habíamos establecido en las líneas 6 y 7.
# Detección del color celeste maskCeleste = cv2.inRange(frameHSV, celesteBajo, celesteAlto)
Como puedes ver en la figura 3 al lado izquierdo, tenemos una imagen binaria en donde la región en blanco representa la presencia del color celeste que buscamos detectar, sin embargo no solo se ha detectado la tapa sino que hay más regiones en blanco debajo de ella, entonces para mejorar la detección podemos aplicar algunas transformaciones morfológicas, veamos:
maskCeleste = cv2.erode(maskCeleste,None,iterations = 1) maskCeleste = cv2.dilate(maskCeleste,None,iterations = 2) maskCeleste = cv2.medianBlur(maskCeleste, 13)
En las líneas 68 y 69 estoy aplicando erosión y dilatación finalmente he aplicado cv2.medianBlur
para suavizar un poco los bordes del área blanca.
Como vemos en la figura 4, la detección del color celeste ha mejorado.
Encontrando contornos
Ahora que hemos detectado el color celeste y tenemos en maskCeleste
una imagen binaria en donde la región en blanco representa la presencia de dicho color, mientras en color negro la ausencia del mismo, vamos a proceder a encontrar los contornos, parra luego analizarlos de acuerdo a su área.
cnts,_ = cv2.findContours(maskCeleste, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:1]
Línea 71: Nos ayudamos de cv2.findContours
para encontrar los contornos presentes en maskCeleste
(puedes profundizar más esta función aquí).
NOTA: Si tienes la versión 3 de OpenCV, y obtienes un error en la línea 71, por favor prueba de este modo: _,cnts,_ = cv2.findContours(maskCeleste, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
Línea 72: Vamos a ordenar los contornos en forma descendente, y escogeremos el más grande que se almacenará en cnts
.
Estableciendo un área mínima para la detección y obteniendo las coordenadas para realizar los trazos
Una vez que tenemos el contorno más grande presente dentro de la imagen vamos a realizar otro filtrado, para saber que en realidad se trata del objeto que deseemos detectar. Para ello estableceremos un área mínima, objetos menores a esta área serán descartados.
for c in cnts: area = cv2.contourArea(c) if area > 1000: x,y2,w,h = cv2.boundingRect(c) x2 = x + w//2
Línea 75 y 76: Obtenemos el área del contorno y a continuación comparamos para que solo objetos celestes que tengan un área mayor a 1000 pixeles sean tomados en cuenta. Cuando el área del contorno sea menor se asignará a x1,y1 = None
, como lo podrás ver más adelante en la línea 133.
Línea 77: A través de cv2.boundingRect
encontramos las coordendas, ancho y alto del rectángulo que rodee el objeto celeste. Como puedes darte cuenta he declarado y2
, esto debido a que será la coordenada en y
que me ayudará a dibujar los trazos.
Línea 78: Tomamos la coordenada en x
y la sumamos a la mitad del ancho del rectángulo que rodea el objeto. Esto permitirá encontrar la coordenada x2
. Ahora con la línea 77 y 78 ya tenemos las coordenadas de los puntos que nos permitirán realizar los trazos.
Seleccionando colores para dibujar
Ahora basados en las coordenadas x2,y2
podemos darle funcionalidad a nuestra aplicación para que el usuario pueda elegir de entre distintos colores, para ello usaremos un par de if.
if x1 is not None: if 0 < x2 < 50 and 0 < y2 < 50: color = colorAmarillo # Color del lápiz/marcador virtual grosorAmarillo = 6 grosorRosa = 2 grosorVerde = 2 grosorCeleste = 2 if 50 < x2 < 100 and 0 < y2 < 50: color = colorRosa # Color del lápiz/marcador virtual grosorAmarillo = 2 grosorRosa = 6 grosorVerde = 2 grosorCeleste = 2 if 100 < x2 < 150 and 0 < y2 < 50: color = colorVerde # Color del lápiz/marcador virtual grosorAmarillo = 2 grosorRosa = 2 grosorVerde = 6 grosorCeleste = 2 if 150 < x2 < 200 and 0 < y2 < 50: color = colorCeleste # Color del lápiz/marcador virtual grosorAmarillo = 2 grosorRosa = 2 grosorVerde = 2 grosorCeleste = 6
Línea 80: Si x1
no es igual a None
, es decir cuando se haya almacenado alguna coordenada en x1
, se procederá con la selección de los colores y/o dibujo de los trazos.
Línea 81 a 86: Para seleccionar el color amarillo necesitaremos que el objeto se encuentre en el eje x, de 0 a 50, mientras en en y de 0 a 50, por ello hemos puesto el if de la línea 81. Cuando esto pase, la variable color
tomará el colorAmarillo
y para resaltar el recuadro del color seleccionado en la sección superior izquierda se actualiza grosorAmarillo = 6
, mientras que los otros recuadros permanecen con grosor 2.
Línea 87 a 92: Ahora procedemos con la posible selección del color rosa, para ello el objeto debe encotnrarse en x de 50 a 100, mientras que en y de 0 a 50. Cuando esto suceda a variable color
tomará el colorRosa
y para resaltar el recuadro del color seleccionado en la sección superior izqueirda se actualiza grosorRosa = 6
mientras que los otros recuadros permanecerapn en grosor 2.
Línea 93 a 104: Como te pudiste haber dado cuenta, seguimos el mismo procedimiento tanto para el color verde y celeste.
Seleccionando el grosor de los trazos para dibujar
Seguiremos un procedimiento similiar, para poder seleccionar de entre los 3 tamaños de los trazos, que se ubican en la parte superior derecha.
if 490 < x2 < 540 and 0 < y2 < 50: grosor = 3 # Grosor del lápiz/marcador virtual grosorPeque = 6 grosorMedio = 1 grosorGrande = 1 if 540 < x2 < 590 and 0 < y2 < 50: grosor = 7 # Grosor del lápiz/marcador virtual grosorPeque = 1 grosorMedio = 6 grosorGrande = 1 if 590 < x2 < 640 and 0 < y2 < 50: grosor = 11 # Grosor del lápiz/marcador virtual grosorPeque = 1 grosorMedio = 1 grosorGrande = 6
Línea 105 a 109: Para seleccionar el grosor más pequeño, el objeto debe estar ubicado en el eje x de 490 a 540, mientras en y de 0 a 50. Cuando esto pase, la variable grosor
tomará el valor de 3 y para resaltar el cuadrado del grosor seleccionado en la sección superior derecha se actualiza grosorPeque = 6
, mientras que los otros recuadros permanecen con grosor 1.
Línea 110 a 114: Ahora para seeleccionar el grosor mediano, el objeto debe estar ubicado en el eje x de 540 a 590, mientras que en y de 0 a 50. Cuando esto pase, la variable grosor
tomará el valor de 7 y para resaltar el cuadrado del grosor seleccionado en la sección superior derecha se actualiza grosorMedio = 6
, mientras que los otros recuadros permanecen con grosor 1.
Tendremos que realizar el mismo procedimiento de la línea 115 a 119.
Seleccionando ‘Limpiar pantalla’
Para seleccionar ‘Limpiar pantalla’ bastará que el objeto se encuentre sobre dicho recuadro, veamos como hacerlo:
if 300 < x2 < 400 and 0 < y2 < 50: cv2.rectangle(frame,(300,0),(400,50),colorLimpiarPantalla,2) cv2.putText(frame,'Limpiar',(320,20),6,0.6,colorLimpiarPantalla,2,cv2.LINE_AA) cv2.putText(frame,'pantalla',(320,40),6,0.6,colorLimpiarPantalla,2,cv2.LINE_AA) imAux = np.zeros(frame.shape,dtype=np.uint8)
Línea 120: Para limpiar la pantalla, el objeto debe estar ubicado en el eje x de 300 a 4000, mientras en y de 0 a 50. Cuando esto pase, se resaltará el rectángulo y el texto, mientras que para limpliar la pantalla emplearemos la línea 124, asignando a imAux = np.zeros(frame.shape,dtype=np.uint8)
, ¿te diste cuenta que esta línea es similar a la línea 43?, con esto podremos limpiar los trazos que realicemos.
Dibujando los trazos
Ahora pasemos al dibujo de los trazos, según las coordenadas que presente el objeto.
if 0 < y2 < 60 or 0 < y1 < 60 : imAux = imAux else: imAux = cv2.line(imAux,(x1,y1),(x2,y2),color,grosor) cv2.circle(frame,(x2,y2),grosor,color,3) x1 = x2 y1 = y2 else: x1, y1 = None, None
Línea 125 a 126: He añadido estas líneas para que no se dibuje en la sección superior de la imagen, en donde se selecciona el color, el grosor del trazo, además de limpiar la pantalla.
Hasta ahora habíamos estado trabajando sobre la parte superior de la pantalla, es hora de que sedibujen los trazos sobre el resto de dicha pantalla.
Línea 127 y 128: Si el objeto no está en la sección superior, pasaremos a la línea 128, en donde dibujamos una línea que conecte las coordenadas x1,y1
con x2,y2
. Aquí se usarán las variables color
y grosor
que habíamos usado en líneas anteriores.
Línea 129: Procedemos a dibujar un círculo, para indicar la coordenada x2,y2.
Línea 130 y 131: Acualizamos los valores x1,y1
asignándoles los valores de x2,y2
, esto nos servirá para poder dibujar los trazos, conforme se vaya moviendo el objeto. Esto lo tenemos en la línea 127.
Línea 132 y 133: Como te había dicho anteriormente, si el contorno no cumple un área mínima de 100, entonces x1,y1
serán asignados con None
.
En la figura 5, podemos ver que con el proceso que hemos realizado hasta aquí, ya se dibujan los trazos, pero estos solo se están dibujando en imAux
, es por ello que a continuación veremos el procedimiento para que se dibujen sobre los fotogramas.
Dibujando sobre el VideoStreaming
Para poder dibujar sobre los fotogramas podemos pensar en usar cv2.add
, y así sumar frame
eimAux
, sin embargo te mostraré a continuación los resultados de realizar este proceso:
Como puedes ver en la parte derecha de la figura 6, al aplicar frame = cv2.add(frame,imAux)
, los trazos no aparecen de color azul/celeste, sino que toman colores más claros, esto es porque se está sumando la intensidad de los pixeles de las imagenes. Es por esta razón que antes de aplicar cv2.add
necesitamos de un par de procesos más, veamos:
imAuxGray = cv2.cvtColor(imAux,cv2.COLOR_BGR2GRAY) _, th = cv2.threshold(imAuxGray,10,255,cv2.THRESH_BINARY) thInv = cv2.bitwise_not(th) frame = cv2.bitwise_and(frame,frame,mask=thInv) frame = cv2.add(frame,imAux) #cv2.imshow('maskCeleste', maskCeleste) cv2.imshow('imAux',imAux) cv2.imshow('frame', frame) k = cv2.waitKey(1) if k == 27: break cap.release() cv2.destroyAllWindows()
Línea 135: Transformamos imAux
de BGR a escala de grises.
Línea 136: Aplicamos umbralización simple aimAuxGray
para obtener una imagen binaria (puedes visitar este post, para más información sobre la umbralización simple o simple thresholding).
Línea 137: Aplicamos el operador not, con cv2.bitwise_not
a la imagen binaria.
Línea 138: Nos ayudaremos de cv2.bitwise_and
para construir una nueva imagen, en donde esté el fotograma, y los trazos dibujados tomen color negro o valor de cero.
NOTA: Para más información sobre los operadores bit a bit puedes visitar el post Operadores BITWISE (AND-OR-NOT-XOR) con OpenCV y Python.
Línea 139: Ahora con la nueva imagen obtenida en la línea 138, podemos aplicar cv2.add
y ver que resultados obtenemos.
Como puedes apreciar en la figura 7, ¡ya podemos dibujar en el aire!. ¿Qué te pareció?.
Por cierto, puedes pegar un papel o cinta de otro color en la parte trasera del objeto que vas a utilizar para realizar los trazos, de este modo al voltear el objeto puedes dibujar y dejar de dibujar, ya que a ciertos momentos detectará el color y en otros no.
Programación completa
import cv2 import numpy as np cap = cv2.VideoCapture(0,cv2.CAP_DSHOW) celesteBajo = np.array([75, 185, 88], np.uint8) celesteAlto = np.array([112, 255, 255], np.uint8) # Colores para pintar colorCeleste = (255,113,82) colorAmarillo = (89,222,255) colorRosa = (128,0,255) colorVerde = (0,255,36) colorLimpiarPantalla = (29,112,246) # Solo se usará para el cuadro superior de 'Limpiar Pantalla' # Grosor de línea recuadros superior izquierda (color a dibujar) grosorCeleste = 6 grosorAmarillo = 2 grosorRosa = 2 grosorVerde = 2 # Grosor de línea recuadros superior derecha (grosor del marcador para dibujar) grosorPeque = 6 grosorMedio = 1 grosorGrande = 1 #--------------------- Variables para el marcador / lápiz virtual ------------------------- color = colorCeleste # Color de entrada, y variable que asignará el color del marcador grosor = 3 # Grosor que tendrá el marcador #------------------------------------------------------------------------------------------ x1 = None y1 = None imAux = None while True: ret,frame = cap.read() if ret==False: break frame = cv2.flip(frame,1) frameHSV = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) if imAux is None: imAux = np.zeros(frame.shape,dtype=np.uint8) #------------------------ Sección Superior ------------------------------------------ # Cuadrados dibujados en la parte superior izquierda (representan el color a dibujar) cv2.rectangle(frame,(0,0),(50,50),colorAmarillo,grosorAmarillo) cv2.rectangle(frame,(50,0),(100,50),colorRosa,grosorRosa) cv2.rectangle(frame,(100,0),(150,50),colorVerde,grosorVerde) cv2.rectangle(frame,(150,0),(200,50),colorCeleste,grosorCeleste) # Rectángulo superior central, que nos ayudará a limpiar la pantalla cv2.rectangle(frame,(300,0),(400,50),colorLimpiarPantalla,1) cv2.putText(frame,'Limpiar',(320,20),6,0.6,colorLimpiarPantalla,1,cv2.LINE_AA) cv2.putText(frame,'pantalla',(320,40),6,0.6,colorLimpiarPantalla,1,cv2.LINE_AA) # Cuadrados dibujados en la parte superior derecha (grosor del marcador para dibujar) cv2.rectangle(frame,(490,0),(540,50),(0,0,0),grosorPeque) cv2.circle(frame,(515,25),3,(0,0,0),-1) cv2.rectangle(frame,(540,0),(590,50),(0,0,0),grosorMedio) cv2.circle(frame,(565,25),7,(0,0,0),-1) cv2.rectangle(frame,(590,0),(640,50),(0,0,0),grosorGrande) cv2.circle(frame,(615,25),11,(0,0,0),-1) #----------------------------------------------------------------------------------- # Detección del color celeste maskCeleste = cv2.inRange(frameHSV, celesteBajo, celesteAlto) maskCeleste = cv2.erode(maskCeleste,None,iterations = 1) maskCeleste = cv2.dilate(maskCeleste,None,iterations = 2) maskCeleste = cv2.medianBlur(maskCeleste, 13) cnts,_ = cv2.findContours(maskCeleste, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:1] for c in cnts: area = cv2.contourArea(c) if area > 1000: x,y2,w,h = cv2.boundingRect(c) x2 = x + w//2 if x1 is not None: if 0 < x2 < 50 and 0 < y2 < 50: color = colorAmarillo # Color del lápiz/marcador virtual grosorAmarillo = 6 grosorRosa = 2 grosorVerde = 2 grosorCeleste = 2 if 50 < x2 < 100 and 0 < y2 < 50: color = colorRosa # Color del lápiz/marcador virtual grosorAmarillo = 2 grosorRosa = 6 grosorVerde = 2 grosorCeleste = 2 if 100 < x2 < 150 and 0 < y2 < 50: color = colorVerde # Color del lápiz/marcador virtual grosorAmarillo = 2 grosorRosa = 2 grosorVerde = 6 grosorCeleste = 2 if 150 < x2 < 200 and 0 < y2 < 50: color = colorCeleste # Color del lápiz/marcador virtual grosorAmarillo = 2 grosorRosa = 2 grosorVerde = 2 grosorCeleste = 6 if 490 < x2 < 540 and 0 < y2 < 50: grosor = 3 # Grosor del lápiz/marcador virtual grosorPeque = 6 grosorMedio = 1 grosorGrande = 1 if 540 < x2 < 590 and 0 < y2 < 50: grosor = 7 # Grosor del lápiz/marcador virtual grosorPeque = 1 grosorMedio = 6 grosorGrande = 1 if 590 < x2 < 640 and 0 < y2 < 50: grosor = 11 # Grosor del lápiz/marcador virtual grosorPeque = 1 grosorMedio = 1 grosorGrande = 6 if 300 < x2 < 400 and 0 < y2 < 50: cv2.rectangle(frame,(300,0),(400,50),colorLimpiarPantalla,2) cv2.putText(frame,'Limpiar',(320,20),6,0.6,colorLimpiarPantalla,2,cv2.LINE_AA) cv2.putText(frame,'pantalla',(320,40),6,0.6,colorLimpiarPantalla,2,cv2.LINE_AA) imAux = np.zeros(frame.shape,dtype=np.uint8) if 0 < y2 < 60 or 0 < y1 < 60 : imAux = imAux else: imAux = cv2.line(imAux,(x1,y1),(x2,y2),color,grosor) cv2.circle(frame,(x2,y2),grosor,color,3) x1 = x2 y1 = y2 else: x1, y1 = None, None imAuxGray = cv2.cvtColor(imAux,cv2.COLOR_BGR2GRAY) _, th = cv2.threshold(imAuxGray,10,255,cv2.THRESH_BINARY) thInv = cv2.bitwise_not(th) frame = cv2.bitwise_and(frame,frame,mask=thInv) frame = cv2.add(frame,imAux) #cv2.imshow('maskCeleste', maskCeleste) cv2.imshow('imAux',imAux) cv2.imshow('frame', frame) k = cv2.waitKey(1) if k == 27: break cap.release() cv2.destroyAllWindows()
REFERENCIAS:
Excelentisima calidad de trabajo!
Muchisimas gracias, mereces muchisimo reconocimiento 😀
Muchas gracias Aaron que bonito que te haya gustado, eres muy amable 🙂 un abrazo!
Hola muy buenos tutoriales. quisiera saber cómo puedo dibujar el desplazamiento de un objeto que esta en movimiento con select ROI. tengo el centro del objeto (cx,cy). pero no logro dibujar una linea que dibuje el recorrido del objeto. en resumen tengo un programa al apretar un botón se detiene el video y me permite, al utilizar el mouse, dibujar un rectángulo en el objeto que quiero seguir (select ROI), puedo dibujar el centro de ese objeto. pero no se como poder dibujar el recorrido que hace el objeto. lo intente un poco con el código de este tutoría, en la parte donde se dibuja la linea. pero me arrojo este error TypeError: an integer is required (got type NoneType). en conclusión me gustaría saber si sabes como hacerlo. gracias
Hola Juan Pablo, muchas gracias. Si puedes hacerlo con cv2.line, revisa el error que obtienes, puede que las coordenadas que le estés dando no sean enteros (TypeError: an integer is required), o algún parámetro no esté como entero.
Hola gaby, muy buen tutorial
una pregunta, se puede agregar más colores?
en que formato declaras los colores? RGB?
Hola me encantan tus tutos, lo haces de una forma que parecen muy sencillos de seguir. Me gustaria preguntarte sobre si es posible que en vez de colorear seguir el objeto celeste (la tapita) y colorear el trazo, si pudiera desplazarse el puntero del ratón y que de alguna forma al detectarlo fuera un click del boton izquierdo en la posición donde ha sido localizado. Se me ocurren multitud de aplicaciones para un raton virtual. Gracias por tu tiempo.
Seria posible utilizar un puntero laser (rojo) para escribir en una pared y que aparezca en toda el area de la pantalla? podria asignarle por ejemplo que un solo pulso corto sea el click izquierdo del raton y que si es continuo dibuje el trazo? esto podria ser super util para juegos y para presentaciones. Tambien seria divertido ponerse frente a la webcam y dibujar o comandar el raton con la llama de un mechero…