- 1. Operaciones bit a bit y enmascaramiento
- 2. Convolución y desenfoque
- 3. Nitidez: invertir la imagen borrosa
- 4. Trilla (binarización)
- 5. Dilatación, erosión, apertura / cierre
- 6. Detección de bordes y degradados de imagen
- 14. Perspectiva y transformación afín
- 8. Aplicación Live Sketch
En los tutoriales anteriores, aprendimos sobre OpenCV y realizamos un procesamiento básico de imágenes y luego, en el siguiente tutorial, hemos realizado algunas manipulaciones de imágenes en OpenCV como recorte, rotación, transformación de imágenes, etc. Algunas técnicas más de manipulación de imágenes como y al final del tutorial crearemos un programa python-opencv para hacer un boceto en vivo desde la transmisión en vivo de la cámara web. Esta aplicación utilizará muchas de las funciones de procesamiento de imágenes que hemos aprendido hasta ahora o que aprenderemos en este tutorial, por lo que este será un buen ejemplo práctico para cubrir todas las funciones.
Como se dijo en el tutorial anterior, OpenCV es una biblioteca Commuter Vision de código abierto que tiene interfaces C ++, Python y Java y es compatible con Windows, Linux, Mac OS, iOS y Android. Por lo que se puede instalar fácilmente en Raspberry Pi con entorno Python y Linux. Y la Raspberry Pi con OpenCV y la cámara adjunta se puede utilizar para crear muchas aplicaciones de procesamiento de imágenes en tiempo real como detección de rostros, bloqueo de rostros, seguimiento de objetos, detección de matrículas de automóviles, sistema de seguridad para el hogar, etc.
En este tutorial, veremos más manipulaciones de imágenes usando Python OpenCV. Aquí aprenderemos a aplicar la siguiente función en una imagen usando Python OpenCV:
- Operaciones y enmascaramiento bit a bit
- Convolución y desenfoque
- Nitidez: inversión de la imagen borrosa
- Umbralización (binarización)
- Dilatación, erosión, apertura / cierre
- Detección de bordes y degradados de imagen
- Perspectiva y transformación afín
- Aplicación Live Sketch
1. Operaciones bit a bit y enmascaramiento
Las operaciones bit a bit le ayudan en el enmascaramiento de imágenes y le ayudan a crear algunas imágenes simples.
Haciendo un cuadrado
import cv2 import numpy as np # usamos solo dos dimensiones porque esta es una imagen en escala de grises, si estuviéramos usando una # imagen de color, entonces hubiéramos usado un rectángulo = np.zeros ((300,300,3), np.uint8) # Hacer un cuadrado cuadrado = np.zeros ((300,300), np.uint8) cv2.rectangle (cuadrado, (50,50), (250,250), 255, -1) cv2.imshow ("cuadrado", cuadrado) cv2. waitKey (0)
Haciendo una elipse
elipse = np.zeros ((300,300), np.uint8) cv2.ellipse (elipse, (150,150), (150,150), 30,0,180,255, -1) cv2.imshow ("elipse", elipse) cv2.waitKey (0)
Experimentar con operaciones bit a bit
#AND_shows solo donde los dos se cruzan
BitwiseAND = cv2.bitwise_and (cuadrado, elipse) cv2.imshow ("Y", BitwiseAND) cv2.waitKey (0)
#OR_shows only where ya sea square or elipse is
BitwiseOR = cv2.bitwise_or (cuadrado, elipse) cv2.imshow ("OR", BitwiseOR) cv2.waitKey (0)
#XOR_shows solo donde existe por sí mismo
BitwiseXOR = cv2.bitwise_xor (cuadrado, elipse) cv2.imshow ("XOR", BitwiseXOR) cv2.waitKey (0)
#NOT_shows todo lo que no es parte de la elipse y la operación NO se puede aplicar solo a una figura
BitwiseNOT_elp = cv2.bitwise_not (elipse) cv2.imshow ("NOT_ellipse", BitwiseNOT_elp) cv2.waitKey (0) cv2.destroyAllWindows ()
2. Convolución y desenfoque
Una convolución es una operación matemática realizada en dos funciones que produce una tercera función que suele ser una versión modificada de la función original.
Imagen de salida = imagen Función Tamaño del kernel
En visión artificial usamos el kernel para especificar el tamaño sobre el que ejecutamos nuestra función de manipulación sobre nuestra imagen.
El desenfoque es una operación en la que promediamos los píxeles dentro de una región (Kernel)
OpenCV difumina una imagen aplicando kernels, un kernel le dice cómo cambiar el valor de cualquier píxel dado combinándolo con diferentes cantidades de píxeles vecinos, el kernel se aplica a cada píxel de la imagen uno por uno para producir la imagen final.
En pocas palabras, una convolución de imagen es simplemente una multiplicación de dos matrices seguida de una suma.
Simplemente podemos entenderlo con el siguiente ejemplo.
Lo anterior es un núcleo 3X3.
Multiplicamos por 1/25 para normalizar, es decir, sumamos a 1 que habíamos ido aumentando o disminuyendo la intensidad como en el caso de aclarar u oscurecer las imágenes.
Probemos un método de desenfoque de opencv filter2D, dado por la función cv2.filter2D (image, -1, kernel)
importar cv2 importar numpy como np image = cv2.imread ('elefante.jpg') cv2.imshow ('original', imagen) cv2.waitKey (0)
#creando una matriz de kernel 3x3
kernel_3x3 = np.ones ((3,3), np.float32) / 9
# usamos cv2.filter2D para convolucionar el kernel con una imagen
borroso = cv2.filter2D (imagen, -1, kernel_3x3) cv2.imshow ('3x3_blurring', borroso) cv2.waitKey (0)
#creación de una matriz de núcleo de 7x7
kernel_7x7 = np.ones ((7,7), np.float32) / 49
# usamos cv2.filter2D para convolucionar el kernel con una imagen
borroso = cv2.filter2D (imagen, -1, kernel_7x7) cv2.imshow ('7x7_blurring', borroso) cv2.waitKey (0) cv2.destroyAllWindows ()
También existen otros tipos de métodos de desenfoque:
cv2.blur: promedia el valor en una ventana específica.
cv2.GaussianBlur: similar pero utiliza una ventana gaussiana (más énfasis en los puntos alrededor del centro).
cv2.medianBlur: utiliza la mediana de todos los elementos de la ventana.
cv2.bilateralFilter: difumina mientras mantiene los bordes nítidos, conserva los bordes y los detalles de las líneas.
Veremos uno por uno a continuación, primero mostraremos la imagen original usando el siguiente código:
importar cv2 importar numpy como np image = cv2.imread ('elefante.jpg') cv2.imshow ('original', imagen) cv2.waitKey (0)
cv2.blur:
En este método, el promedio se realiza convolucionando la imagen con un filtro de caja normalizado, este toma el lugar debajo de la caja y reemplaza el elemento central. Aquí el tamaño de la caja debe ser impar y positivo .
# cv2.blur desenfoque = cv2.blur (imagen, (3,3)) cv2.imshow ('Promedio', desenfoque) cv2.waitKey (0)
cv2.GaussianBlur:
# cv2.GaussianBlur #instead de filtro de caja, vamos a tratar de Gauss kernel gaussiana = cv2.GaussianBlur (imagen, (7,7), 0) cv2.imshow ('gaussiano desenfoque', Gauss) cv2.waitKey (0)
cv2.medianBlur:
Toma la mediana de todos los píxeles debajo del área del kernel y el elemento central se reemplaza con este valor mediano.
# cv2.medianBlur # toma la mediana de todos los píxeles debajo del área del kernel y el elemento central # se reemplaza con este valor mediano. mediana = cv2.medianBlur (imagen, 5) cv2.imshow ('mediana desenfoque', mediana) cv2.waitKey (0)
cv2.bilateralFilter:
Bilateral es muy eficaz en la eliminación de ruido manteniendo los bordes afilados
# cv2.bilateralFilter #Bilateral es muy eficaz en la eliminación de ruido, manteniendo los bordes aguda = cv2.bilateralFilter (imagen, 9,75,75) bilateral cv2.imshow ('bilateral desenfoque', bilateral) cv2.waitKey (0) cv2. destroyAllWindows ()
Imagen Eliminación de ruido-no local significa Eliminación de ruido
importar cv2 importar numpy como np image = cv2.imread ('elefante.jpg') cv2.imshow ('original', imagen) cv2.waitKey (0)
# parámetro después de Ninguno es la fuerza del filtro 'h' (5-10 es un buen rango) # el siguiente es h para componentes de color, establezca el mismo valor que h nuevamente
dst = cv2.fastNlMeansDenoisingColored (imagen, Ninguno, 6,6,7,21) cv2.imshow ('Rápido significa denois', dst) cv2.waitKey (0) cv2.destroyAllWindows ()
Hay 4 variaciones de eliminación de ruido de medios no locales
cv2.fastNlMeansDenoising () - para una sola imagen en escala de grises
cv2.fastNlMeansDenoisingColored () - Imagen de un solo color
cv2.fastNlmeansDenoisingMulti () - para secuencia de imágenes en escala de grises
cv2.fastNlmeansDenoisingcoloredMulti () - para secuencia de imágenes coloreadas
3. Nitidez: invertir la imagen borrosa
La nitidez es lo opuesto a desenfocar, refuerza o enfatiza los bordes de la imagen.
Kernel =,,
Nuestra matriz de kernel suma uno, por lo que no hay necesidad de normalizar (es decir, multiplicar por un factor al mismo brillo que el original), si el kernel no se normaliza a 1, la imagen sería más brillante o más oscura.
importar cv2 importar numpy como np image = cv2.imread ('elefante.jpg') cv2.imshow ('original', imagen) cv2.waitKey (0)
kernel_sharpening = np.array (,
])
#aplicar kernel de nitidez a la imagen de entrada
afilado = cv2.filter2D (imagen, -1, kernel_sharpening) cv2.imshow ('imagen afilada', afilada) cv2.waitKey (0) cv2.destroyAllWindows ()
4. Trilla (binarización)
La creación de umbrales es el acto de convertir una imagen en forma binaria. En opencv hay una función separada para el umbral definido como
Cv2.threshold (imagen, valor de umbral, valor máximo, tipo de umbral)
Existen los siguientes tipos de umbral:
- cv2.THRESH_BINARY - más común
- cv2. THRESH_BINARY_INV - más común
- cv2.THRESH_TRUNC
- cv2.THRESH_TOZERO
- cv2. THRESH_TOZERO_INV
NOTA: la imagen debe convertirse a escala de grises antes de establecer el umbral
importar cv2 importar numpy como np #cargar imagen como imagen en escala de grises = cv2.imread ('gradient.jpg', 0) cv2.imshow ('original', imagen) cv2.waitKey (0)
#valor por debajo de 127 va a 0 (negro), y por encima de 127 va a 255 (blanco)
_, thresh1 = cv2.threshold (imagen, 127,255, cv2.THRESH_BINARY) cv2.imshow ('1 umbral', thresh1) cv2.waitKey (0)
# el valor por debajo de 127 va a 255 y los valores por encima de 127 van a 0 (al revés de arriba)
_, thresh2 = cv2.threshold (imagen, 127,255, cv2.THRESH_BINARY_INV) cv2.imshow ('2 umbrales', thresh2) cv2.waitKey (0)
#valor superior a 127 se trunca (se mantiene) en 127, el argumento 255 no se utiliza.
_, thresh3 = cv2.threshold (imagen, 127,255, cv2.THRESH_TRUNC) cv2.imshow ('3 thresh trunc', thresh3) cv2.waitKey (0)
# los valores por debajo de 127 van a 0, por encima de 127 no cambian
_, thresh4 = cv2.threshold (imagen, 127,255, cv2.THRESH_TOZERO) cv2.imshow ('4 umbrales', thresh4) cv2.waitKey (0)
# El reverso de arriba, debajo de 127 no cambia, arriba de 127 va a cero
_, thresh5 = cv2.threshold (imagen, 127,255, cv2.THRESH_TOZERO_INV) cv2.imshow ('5 umbrales', thresh5) cv2.waitKey (0) cv2.destroyAllWindows ()
5. Dilatación, erosión, apertura / cierre
Estas son las operaciones en el campo de la morfología matemática.
Dilatación: agrega píxeles a los límites del objeto en una imagen.
Erosión: elimina píxeles en los límites del objeto en una imagen.
Apertura: erosión seguida de dilatación.
Cierre: dilatación seguida de erosión.
La apertura es muy útil para eliminar el ruido de las imágenes, ya que primero adelgaza la imagen por erosión (elimina el ruido) y luego la dilata.
Confusión con dilatación y erosión
A veces hay confusión entre dilatación y erosión, generalmente en imágenes con fondo blanco, ya que opencv considera que el fondo blanco como imagen está dilatada o erosionada en lugar de la imagen original, por lo que en este caso la erosión funciona como dilatación y viceversa, como se muestra en la imagen de muestra. mostrado a continuación.
Recuerde, Dilation agrega píxeles a los límites de los objetos en una imagen, mientras que Erosion elimina píxeles en los límites de los objetos en una imagen.
importar cv2 importar numpy as np image = cv2.imread ('imagecv.png', 0) cv2.imshow ('original', image) cv2.waitKey (0)
#Erosion
# definamos nuestro tamaño de kernel
kernel = np.ones ((5,5), np.uint8)
#Ahora erosionamos la imagen, aquí la iteración no es una de las veces que desea erosionar la imagen
erosion = cv2.erode (imagen, kernel, iteraciones = 1) cv2.imshow ('Erosion', erosion) cv2.waitKey (0)
#dilatación
dilatación = cv2.dilate (imagen, núcleo, iteraciones = 1) cv2.imshow ('dilatación', dilatación) cv2.waitKey (0)
#apertura, bueno para eliminar el ruido
apertura = cv2.morphologyEx (imagen, cv2.MORPH_OPEN, kernel) cv2.imshow ('apertura', apertura) cv2.waitKey (0)
#closing, bueno para eliminar el ruido
cerrando = cv2.morphologyEx (imagen, cv2.MORPH_CLOSE, kernel) cv2.imshow ('cerrando', cerrando) cv2.waitKey (0) cv2.destroyAllWindows ()
6. Detección de bordes y degradados de imagen
La detección de bordes es un área muy importante en la visión por computadora, especialmente cuando se trata de contornos.
Los bordes se pueden definir como límites de la imagen, en realidad son bordes que definen el objeto en las imágenes y conservan mucha información sobre la imagen.
Formalmente, los bordes se pueden definir como cambios repentinos (discontinuidades) en una imagen y pueden codificar tanta información como píxeles.
La imagen de arriba muestra cómo la visión por computadora identifica y reconoce la imagen.
Algoritmos de detección de bordes: - Hay tres tipos principales de algoritmos de detección de bordes
- Sobel: para enfatizar las imágenes verticales u horizontales.
- Laplaciano: óptimo debido a la baja tasa de error, bordes bien definidos y detección precisa.
- Algoritmo de detección de Canny Edge (desarrollado por john.F.Canny en 1986)
1. Aplica desenfoque gaussiano
2. Encuentra el gradiente de intensidad de la imagen.
3. aplica una supresión no máxima (es decir, elimina los píxeles que no son bordes).
4. La histéresis aplica el umbral (es decir, si el píxel está dentro del umbral superior e inferior, se considera un borde)
import cv2 import numpy as np image = cv2.imread ('input.jpg', 0) height, width = image.shape
#sobel
# extracción de bordes de sobel
sobel_x = cv2.Sobel (imagen, cv2.CV_64F, 0,1, ksize = 5) sobel_y = cv2.Sobel (imagen, cv2.CV_64F, 1,0, ksize = 5) cv2.imshow ('original', imagen) cv2.waitKey (0) cv2.imshow ('sobelx', sobel_x) cv2.waitKey (0)
#Sobely
cv2.imshow ('sobely', sobel_y) cv2.waitKey (0)
sobel_OR = cv2.bitwise_or (sobel_x, sobel_y) cv2.imshow ('sobelOR', sobel_OR) cv2.waitKey (0)
#laplaian
laplacian = cv2.Laplacian (imagen, cv2.CV_64F) cv2.imshow ('Laplacian', laplacian) cv2.waitKey (0)
#El algoritmo de detección de bordes canny usa valores de gradiente como umbrales
#en canny necesitamos proporcionar dos valores: umbral1 y umbral2.
# Cualquier gradiente mayor que el umbral 2 se considera un borde.
# Cualquier gradiente mayor que el umbral 1 no se considera un borde.
#Los valores entre el umbral 1 y el umbral 2 son como borde o sin borde
# según cómo se conectan sus intensidades, en este caso cualquier valor por debajo de 60 se considera
# sin bordes, mientras que cualquier valor por encima de 120 se considera como bordes.
canny = cv2.Canny (imagen, 60,120) cv2.imshow ('astuto', astuto) cv2.waitKey (0) cv2.destroyAllWindows ()
14. Perspectiva y transformación afín
Demos un paso atrás y echemos un vistazo a las transformaciones afines y no afines, la imagen original que se muestra a continuación es claramente una imagen no afín, ya que los bordes se van a encontrar en algún momento, sin embargo, podemos enderezarla deformando y tomando la perspectiva transformar.
Para esta transformación de perspectiva, necesitamos las cuatro coordenadas de la imagen original y luego los cuatro puntos de la imagen de salida, que se indican mediante puntos_A y puntos_B. En primer lugar, con la ayuda de estos puntos, calculamos una matriz de transformación, M, con la ayuda de la función getPerspectiveTransform.
Y luego esta matriz se le da a la función warpPerspective para generar la salida final.
Ahora intentemos primero la transformación de perspectiva.
import cv2 import numpy as np import matplotlib.pyplot as plt image = cv2.imread ('paper.jpg') cv2.imshow ('original', image) cv2.waitKey (0)
#coordinado de 4 esquinas de la imagen original
puntos_A = np.float32 (,,,])
#coordenadas de las 4 esquinas de la salida deseada
#utilizamos una proporción de papel A4 1: 1,41
puntos_B = np.float32 (,,,])
#utilice los dos conjuntos de dos puntos para calcular la matriz de transformación prespectiva , M
M = cv2.getPerspectiveTransform (puntos_A, puntos_B) warped = cv2.warpPerspective (imagen, M, (420,594)) cv2.imshow ('warpprespective', warped) cv2.waitKey (0) cv2.destroyAllWindows ()
La transformación afín es más fácil que la no afín, ya que solo necesitamos tres puntos para obtener la transformación. Todo el proceso es el mismo, pero en lugar de la transformación de perspectiva ahora tenemos una transformación afín y también definimos columnas y filas en warpAffine a partir de la función de forma en lugar de ingresarla manualmente.
import cv2 import numpy as np import matplotlib.pyplot as plt image = cv2.imread ('box.jpg') rows, cols = image.shape cv2.imshow ('original', image) cv2.waitKey (0)
#coordinada de 3 esquinas de la imagen original
puntos_A = np.float32 (,,])
#coordenadas de 3 esquinas de la salida deseada
#usamos una proporción de papel A4 1: 1,41
puntos_B = np.float32 (,,])
#utilice los dos conjuntos de dos puntos para calcular la matriz de transformación # afín
, M
M = cv2.getAffineTransform (puntos_A, puntos_B) warped = cv2.warpAffine (imagen, M, (columnas, filas)) cv2.imshow ('warpaffine', warped) cv2.waitKey (0) cv2.destroyAllWindows ()
8. Aplicación Live Sketch
En primer lugar, felicítese por haber realizado este mini proyecto después de leer todas las funciones de manipulación de imágenes anteriores. Entonces, en este mini proyecto de Python OpenCV vamos a aprender algunos conceptos nuevos de bucles y funciones. Si está familiarizado con la programación, debe tener una idea más amplia de lo que son la función y los bucles. Sin embargo, en Python el concepto básico de bucles y funciones sigue siendo el mismo, pero el método para definirlos cambia un poco.
Entonces, al comienzo de este programa, podemos ver un cierto grupo de declaraciones bajo el encabezado “ def sketch (imagen): ” esta es una definición formal de una función, un grupo de declaraciones que trabajan juntas para una determinada salida.
Entonces este boceto es una función, en Python la función está definida por "def" y termina con una marca ":". Además, las declaraciones que deben estar dentro de la función o puede decir cuáles son necesarias para que la función funcione correctamente, se alinean lateralmente automáticamente por la función. Entonces, para salir de las funciones, las declaraciones debían estar totalmente alineadas a la izquierda. Para obtener más referencias, puede consultar en Google sobre cómo se definen las funciones en Python.
Entonces, en esta función de boceto, hemos introducido varias capas de procesamiento de imágenes que se combinan para dar una salida. En primer lugar, la imagen se convierte en escala de grises para que opencv pueda procesarla fácilmente y luego se aplica un desenfoque gaussiano a la imagen en escala de grises para reducir el ruido. Luego, los bordes se extraen con la ayuda del algoritmo de detección de bordes del canny, luego se aplica un inverso binario en la imagen definida por el borde, aquí el inverso binario también podría realizarse mediante bitwise_NOT pero habíamos elegido deliberadamente este inverso binario de umbral ya que da libertad para establecer sus parámetros hasta que obtengamos una imagen clara.
También tenga en cuenta que la función toma la imagen de los argumentos y devuelve los dos argumentos ret y mask. Mientras que ret es el booleano que indica que la función se ejecuta correctamente o no y la máscara es la salida final de la función, es decir, la imagen procesada.
Luego, el segundo concepto es el funcionamiento de la cámara web en opencv que se realiza mediante la función cv2.VideoCapture (0) , que almacena la imagen en una tapa de objeto que la tapa se puede leer con la función cap.read () , también aquí para notar esa tapa. read () está dentro del bucle while infinito, ya que tenía que capturar continuamente las imágenes, para darle una sensación de video en vivo, donde la velocidad de fotogramas del video sería la velocidad de fotogramas de su cámara web, que en su mayoría está entre 24 y 60 fps.
cap.read () devuelve ret y frame, donde ret es el booleano que indica que la función se ejecutó correctamente o no y el frame contiene la imagen tomada por la cámara web.
A continuación se muestra el código Python OpenCV completo para ejecutar Live Sketch
importar cv2 importar numpy as np # función de generación de bocetos def sketch (imagen): #convertir imagen a escala de grises img_gray = cv2.cvtColor (imagen, cv2.COLOR_BGR2GRAY) # limpiar la imagen usando el desenfoque gaussiano img_gray_blur = cv2.GaussianBlur (img_gray, 5,5), 0) #extraer bordes canny_edges = cv2.Canny (img_gray_blur, 10,70) #hacer una inversión binarizar la imagen ret, mask = cv2.threshold (canny_edges, 70,255, cv2.THRESH_BINARY_INV) return mask #initialize webcam, cap es el objeto proporcionado por la captura de video # contiene un booleano que indica si fue exitoso (ret) # también contiene las imágenes recopiladas de la cámara web (marco) cap = cv2.VideoCapture (0) while True: ret, frame = cap.read () cv2.imshow ('livesketcher', sketch (frame)) if cv2.waitKey (1) == 13: # 13 es la tecla enter key break #release camera and close window, recuerde liberar la cámara web con la ayuda de cap.release () cap.release () cv2.destroyAllWindows ()
Así que este es el final de la Parte 2 de Manipulaciones de imágenes en Python-OpenCV. Para comprender bien la visión por computadora y OpenCV, lea los artículos anteriores (Comenzando con Python OpenCV y manipulaciones de imágenes en Python OpenCV (Parte 1) y podrá hacer algo genial con Computer Vision.