Operadores BITWISE (AND-OR-NOT-XOR) con OpenCV y Python
CONTENIDO
- AND ( cv2.bitwise_and )
- NOT ( cv2.bitwise_not )
- OR ( cv2.bitwise_or )
- XOR ( cv2.bitwise_xor )
- cv2.bitwise_and y mask
En este post vamos con el tema de Operadotes Bitwise AND, OR, NOT y XOR, en OpenCV y Python. Para ello, las imágenes que vamos a utilizar para aplicar cada uno de los operadores, las construiremos a continuación:
import cv2 import numpy as np img1 = np.zeros((400,600), dtype=np.uint8) img1[100:300,200:400] = 255 img2 = np.zeros((400,600), dtype=np.uint8) img2 = cv2.circle(img2,(300,200),125,(255),-1) cv2.imshow('img1',img1) cv2.imshow('img2',img2) cv2.waitKey(0) cv2.destroyAllWindows()
En la línea 1 y 2 importamos openCV con import cv2
, y numpy con import numpy as np
. En la línea 4 creamos una imagen de ceros (por lo que se visualizará de color negro) con 400
pixeles de alto y 600
de ancho, cabe resaltar que aquí estamos creando una imagen que posee un único canal, no como cuando creábamos una imagen en BGR y especificábamos 3 canales. En la línea 5 estamos creando un rectángulo dentro de la imagen img1
, este rectángulo tendrá color blanco por lo que asignamos 255
.
En la línea 6 construiremos otra imagen de ceros img2
, tal y como lo hicimos en la línea 4, con las mismas dimensiones. Luego en la línea 7 le agregamos un círculo en la parte central de la imagen con cv2.circle
. (Si quieres tener más información de como utilizar esta y otras funciones de dibujo, dale clic al link). Ahora visualicemos las imágenes creadas.
AND ( cv2.bitwise_and )
Para poder entender como funciona este operador en OpenCV, debemos recordar su tabla de verdad, en ella cuando existía al menos un valor en 0 o falso, su salida era falsa. Solo había salida 1 o verdadero cuando todas sus entradas eran 1 o verdaderas. Pues bien, esto es lo mismo que se aplica en OpenCV, con la diferencia que en vez de 1, se utiliza 255. Esto para poder representar blanco y negro.
Para emplear cv2.bitwise_and
, se necesita especificar:
- Imagen 1 (Primera matriz o escalar)
- Imagen 2 (Segunda matriz o escalar)
Ahora realicemos un pequeño programa para visualizar el resultado de aplicar cv2.bitwise_and
, a dos imágenes en blanco y negro:
import cv2 import numpy as np img1 = np.zeros((400,600), dtype=np.uint8) img1[100:300,200:400] = 255 img2 = np.zeros((400,600), dtype=np.uint8) img2 = cv2.circle(img2,(300,200),125,(255),-1) AND = cv2.bitwise_and(img1,img2) cv2.imshow('AND', AND) cv2.waitKey(0) cv2.destroyAllWindows()
Hemos añadido en la línea 9 la función cv2.bitwise_and
a las imágenes que habíamos construido, img1
e img2
. Entonces obtenemos:
NOT ( cv2.bitwise_not )
En el operador NOT, cuando una entrada es verdadera o 1, su salida es falso o 0, y viceversa. En OpenCV se realiza el mismo procedimiento, con la diferencia que en vez de 1 se emplea 255, como he dicho antes, para poder visualizar el resultado o salida en colores blanco y negro, veamos:
Para emplear el operador NOT, OpenCV usa cv2.bitwise_not
en donde se necesita especificar:
- Imagen (Matriz o escalar)
Veamos un ejemplo de como emplear esta función:
import cv2 import numpy as np img1 = np.zeros((400,600), dtype=np.uint8) img1[100:300,200:400] = 255 img2 = np.zeros((400,600), dtype=np.uint8) img2 = cv2.circle(img2,(300,200),125,(255),-1) NOT = cv2.bitwise_not(img1) cv2.imshow('NOT', NOT) cv2.waitKey(0) cv2.destroyAllWindows()
Ahora en la línea 9 hemos aplicado la función cv2.bitwise_not
, para ello procedemos a entregar la imagen a la cual va afectar dicha función, en este caso img1
. La visualización sería la siguiente:
OR ( cv2.bitwise_or )
Al igual que con AND y NOT, necesitamos recordar el funcionamiento del operador OR. Para ello cuando al menos uno de los valores de entrada es verdadero o 1, su salida también lo es. Es únicamente falso o 0, cuando todas sus entradas son 0 o falso.
Para emplear cv2.bitwise_or
, se necesita especificar:
- Imagen 1 (Primera matriz o escalar)
- Imagen 2 (Segunda matriz o escalar)
Veamos a continuación un ejemplo del uso de esta función:
import cv2 import numpy as np img1 = np.zeros((400,600), dtype=np.uint8) img1[100:300,200:400] = 255 img2 = np.zeros((400,600), dtype=np.uint8) img2 = cv2.circle(img2,(300,200),125,(255),-1) OR = cv2.bitwise_or(img1,img2) cv2.imshow('OR', OR) cv2.waitKey(0) cv2.destroyAllWindows()
Como se puede apreciar en la línea 9, el proceso para usar esta función es similar al de AND. Entonces el resultado sería el siguiente:
XOR ( cv2.bitwise_xor )
Finalmente veremos el operador XOR, en este sus salidas toman el valor de falso o 0 cuando ambas entradas poseen el mismo valor, mientras que es verdadero o 1 en los demás casos.
Para emplear cv2.bitwise_xor
, se necesita especificar:
- Imagen 1 (Primera matriz o escalar)
- Imagen 2 (Segunda matriz o escalar)
Ejemplo de aplicación de esta función:
import cv2 import numpy as np img1 = np.zeros((400,600), dtype=np.uint8) img1[100:300,200:400] = 255 img2 = np.zeros((400,600), dtype=np.uint8) img2 = cv2.circle(img2,(300,200),125,(255),-1) XOR = cv2.bitwise_xor(img1,img2) cv2.imshow('XOR', XOR) cv2.waitKey(0) cv2.destroyAllWindows()
En la línea 9 podemos ver como se está utilizando la función, cv2.bitwise_xor
, en ella especificamos las imágenes img1
e img2
. La visualización entonces es:
cv2.bitwise_and y mask
Podemos usar la función cv2.bitwise_and
, para que se visualicen únicamente ciertas áreas de una imagen, mientras que otras permanezcan en negro. Para ello vamos a utilizar una imagen en blanco y negro, como las construidas anteriormente, y cualquier imagen a color. A continuación vamos con un ejemplo empleando video streaming:
import cv2 import numpy as np captura = cv2.VideoCapture(0) mask = np.zeros((480,640),dtype=np.uint8) mask = cv2.circle(mask,(320,240),125,(255),-1) #mask=cv2.bitwise_not(mask) cv2.imshow('mask',mask) while (captura.isOpened()): ret,frame = captura.read() if ret == True: imgMask = cv2.bitwise_and(frame,frame,mask=mask) cv2.imshow('video',imgMask) if cv2.waitKey(1) & 0xFF == ord('s'): break else: break captura.release() cv2.destroyAllWindows()
El código es similar a los que hemos visto en este post. En la línea 4 iniciamos con la captura del video streaming, en la línea 5 creamos una imagen mask
del mismo alto y ancho que la imagen que obtendremos en el video streaming. En la línea 6 estamos creando un círculo que se presentará en el centro de mask
y visualizamos en la línea 8.
NOTA: Luego de que pruebes el código, puedes descomentar la línea 7 y analizar lo que ha sucedido en la imagen mask
e imgMask
.
En la línea 10 obtenemos frame
que es la imagen con la que vamos a trabajar (Si quieres recordar como realizar un video streaming en OpenCV, puedes revisar mi post anterior). En la línea 14 aplicamos la función cv2.bitwise_and
, la diferencia aquí con lo que hemos tratado en este post, es que tanto para la primera y segunda imagen especificamos frame
, que es la imagen a color del video, seguido de esto escribimos mask=mask
, que corresponde a la imagen que tenemos en la línea 7. Visualicemos:
Como podemos ver en la figura 10, a la izquierda tenemos la presencia de una imagen en blanco y negro, en donde presenta un círculo blanco. Al usar cv2.bitwise_and
especificando como primer y segundo argumento la misma imagen, seguido de una máscara, obtenemos la visualización de la derecha. Entonces, la primera imagen está actuando como una máscara, en donde la región blanca nos permitirá visualizar a frame
, que corresponde a la presencia del círculo. Mientras que lo demás se visualizará en negro.
Puedes ver otra aplicación a este procedimiento en el video: DETECCIÓN DE COLORES en OPENCV [en 4 Pasos] – Parte1
Referencias:
- https://docs.opencv.org/trunk/d2/de8/group__core__array.html#ga0002cf8b418479f4cb49a75442baee2f
- https://docs.opencv.org/trunk/d0/d86/tutorial_py_image_arithmetics.html
Hola gabi me encantas
Muy buena entrega, me sirve para lo que estoy haciendo. Gracias!
Hola, Gabriela! Tengo una duda muy grande. mask = np.zeros((480,640),dtype=np.uint8) (pondré esta linea de código como ejemplo) . Tu declaraste «mask» para contener el np.zeros… pero si yo quiero cambiar el «mask» por otra variable , no me lo acepta ,quize poner «imagen»,»A»,etc. Pero solo me funciona con el «mask» , no sé si solo debe ser esa variable o es mi compu jajajajaja . Esperando tu respuesta.
import cv2
import numpy as np
captura = cv2.VideoCapture(0)
imagen = np.zeros((480,640),dtype=np.uint8)
imagen = cv2.circle(imagen,(320,240),125,(255),-1)
#mask=cv2.bitwise_not(mask)
cv2.imshow(‘imagen»,imagen)
while (captura.isOpened()):
ret,frame = captura.read()
if ret == True:
imgMask = cv2.bitwise_and(frame,frame,imagen=imagen)
cv2.imshow(‘video’,imgMask)
if cv2.waitKey(1) & 0xFF == ord(‘s’):
break
else: break
captura.release()
cv2.destroyAllWindows()
Dejé el código cambiando esa variable. ;(
Hola Israel, puede ser porque estás llamando a la variable en la línea: imgMask = cv2.bitwise_and(frame,frame,imagen=imagen). Qué error obtienes?
Hola Gaby. Disculpa por no contestar en estos dias. El error que me sale es este : TypeError: ‘imagen’ is an invalid keyword argument for bitwise_and()
Hola, si no me equivoco el error no esta en usar la variable imagen en lugar de mask, sino en usar el «atributo» imagen en lugar de mask, es decir, la línea deberia ser:
ImgMask = cv2.bitwise_and(frame, frame, mask=imagen)–> tu usas imagen=imagen y debe ser mask=imagen
Hola al tratar de correr el cotigo de bitwise_and me sale este error imgMask = cv2.bitwise_and(frame,frame,mask=mask)
cv2.error: OpenCV(4.5.4-dev) D:\a\opencv-python\opencv-python\opencv\modules\core\src\arithm.cpp:230: error: (-215:Assertion failed) (mtype == CV_8U || mtype == CV_8S) && _mask.sameSize(*psrc1) in function ‘cv::binary_op’
ya intente con una camara IP la de la pc y un video y lo mismo me podrian ayudar
Hola Richi, yo al igual que tú, tengo el mismo problema. Leyendo y buscando, al final he hallado la causa y la solución.
Causa:
La imagen a procesar (es decir, la imagen a la que le vas a poner una máscara) y la máscara, deben tener el mismo tamaño. (es algo que en el video no se comenta, pero en el hilo de la web, si que lo especifica).
Solución:
Debes de inicializar la máscara con las mismas medidas que tenga la imagen, puedes usar:
mask = np.zeros(frame.shape[ :2], dtype= cv2.uint8)
frame.shape[ :2] te devuelve el alto x ancho de la imagen «frame» captada a través de la cámara.
si frame = (960, 1280, 3) (ancho x alto x canal color) —> frame.shape[ :2] = (960, 1280)
Problema: En el ejemplo, la mascara se dimensiona antes de la captura del frame, por lo que puedes tomar las
dimensiones del frame directamente del objeto de la captura:
captura = cv2.VideoCapture(0)
ancho = int(captura.get(cv2.CAP_PROP_FRAME_WIDTH)) #–> esto te da el ancho en float y debe ser int
alto = int(captura.get(cv2.CAP_PROP_FRAME_HEIGHT)) #–> esto te da el alto en float y debe ser int
mascara = np.zeros((alto, ancho), dtype=np.uint8) #–> dimensionas la máscara
mascara = cv2.circle(mascara,(320,240), 125, (255), -1) #–> pintas de blanco la zona a filtrar
(dentro ya del bucle while)
ret,frame = captura.read() #–> tomas el «frame» de la cámara
imMascara = cv2.bitwise_and(frame, frame, mask= mascara) #–> aplicas la mascara (y no te da error)
cv2.imshow(‘imagen con máscara’, imMascara) #—> Muestras la imagen ya filtrada
if cv2.waitKey(1) & 0XFF == ord(‘s’):
break
Que página tan genial, está todo super explicado, para los que vamos iniciando con OpenCV