Introducci贸n al procesamiento de im谩genes en Python con OpenCV

    Introducci贸n

    En este tutorial, aprenderemos c贸mo podemos procesar im谩genes usando el lenguaje Python. No nos vamos a limitar a una biblioteca o marco; sin embargo, hay uno que usaremos con m谩s frecuencia, el CV de la biblioteca abierta . Comencemos hablando un poco sobre el procesamiento de im谩genes y luego avancemos para ver diferentes aplicaciones / escenarios en los que el procesamiento de im谩genes puede ser 煤til. 隆Entonces empecemos!

    驴Qu茅 es el procesamiento de im谩genes?

    Es importante saber qu茅 es exactamente el procesamiento de im谩genes y qu茅 papel juega en el panorama general antes de sumergirse en 茅l. El procesamiento de im谩genes se conoce com煤nmente como “procesamiento de im谩genes digitales” y el dominio m谩s utilizado es “visi贸n por computadora”. No se confunda, hablaremos sobre estos dos t茅rminos y c贸mo se conectan. Los algoritmos de procesamiento de im谩genes y los algoritmos de visi贸n por computadora (CV) aceptan im谩genes como entrada; sin embargo, en el procesamiento de im谩genes, la salida tambi茅n es una imagen, pero en la visi贸n por computadora, la salida puede contener algunas caracter铆sticas / informaci贸n sobre la imagen.

    驴Por qu茅 lo necesitamos?

    Los datos que recopilamos o generamos son en gran parte datos sin procesar, es decir, no son adecuados para su uso en aplicaciones directamente por varias razones posibles. Por lo tanto, primero debemos analizarlo, realizar el preprocesamiento necesario y luego utilizarlo.

    Por ejemplo, supongamos que quer铆amos construir un clasificador de gatos. Nuestro programa tomar铆a una imagen como entrada y luego nos dir铆a si hay un gato en la imagen o no. El primer paso para construir este clasificador fue recolectar cientos de im谩genes de gatos. Un problema com煤n es que no todas las im谩genes que escribimos ser谩n del mismo tama帽o / dimensiones, por lo que antes de enviarlas al modelo para el entrenamiento, tendr铆amos que redimensionarlas / preprocesarlas a un tama帽o est谩ndar.

    Esta es solo una de las muchas razones por las que el procesamiento de im谩genes es esencial para cualquier aplicaci贸n de visi贸n por computadora.

    Prerrequisitos

    Antes de continuar, analicemos lo que necesita para seguir este tutorial con facilidad. Primero, debe tener algunos conocimientos b谩sicos de programaci贸n en cualquier idioma. En segundo lugar, debe saber qu茅 es el Machine Learning y los conceptos b谩sicos de c贸mo funciona, ya que utilizaremos algunos algoritmos de Machine Learning para el procesamiento de im谩genes en este art铆culo. Como beneficio adicional, ser铆a 煤til si tuviera alguna divulgaci贸n b谩sica o conocimiento de Open CV antes de continuar con este tutorial. Pero esto no es obligatorio.

    Una cosa que definitivamente debe saber para seguir este tutorial es c贸mo se muestra exactamente una imagen en la memoria. Cada imagen est谩 representada por un conjunto de p铆xeles, es decir, una matriz de valores de p铆xeles. Para una imagen en escala de grises, los valores de p铆xeles est谩n entre 0 y 255 e indican la intensidad de esos p铆xeles. Por ejemplo, si tiene una imagen de 20 x 20 dimensiones, estar铆a representada por una matriz de 20×20 (valores de 400 p铆xeles en total).

    Si se trata de una imagen en color, debe saber que hay tres formas: rojo, verde y azul (RGB). Por tanto, habr铆a tres matrices de este tipo para una sola imagen.

    Instalaci贸n

    Nota: Dado que vamos a utilizar OpenCV a trav茅s de Python, es un requisito impl铆cito que ya tenga Python (versi贸n 3) instalado en su estaci贸n de trabajo.

    Windows

    $ pip install opencv-python
    

    Mac OS

    $ brew install opencv3 --with-contrib --with-python3
    

    Linux

    $ sudo apt-get install libopencv-dev python-opencv
    

    Para verificar si su instalaci贸n fue exitosa o no, ejecute el siguiente comando en un shell de Python o en el s铆mbolo del sistema:

    import cv2
    

    Algunos conceptos b谩sicos que debe saber

    Antes de pasar a utilizar el procesamiento de im谩genes en una aplicaci贸n, es importante tener una idea de los tipos de operaciones asociadas con esta categor铆a y c贸mo realizar esas operaciones. Estas operaciones, junto con otras operaciones, se utilizar铆an m谩s adelante en nuestras aplicaciones. As铆 que hag谩moslo.

    Usaremos la siguiente imagen para este art铆culo:

    Nota : La imagen se ha escalado para mostrarla en este art铆culo, pero el tama帽o original que estamos usando es de aproximadamente 1180×786.

    Probablemente haya notado que la imagen est谩 coloreada actualmente, lo que significa que hay tres formas de color, es decir, rojo, verde y azul. Cambiaremos el tama帽o de la imagen a escala de grises, adem谩s de dividir la imagen en canales individuales usando el c贸digo a continuaci贸n.

    Encontrar datos de imagen

    Despu茅s de cargar la imagen con la imread()funci贸n, podemos recuperar algunas propiedades simples sobre ella, como el n煤mero de p铆xeles y las dimensiones:

    import cv2
    
    img = cv2.imread('rose.jpg')
    
    print("Image Properties")
    print("- Number of Pixels: " + str(img.size))
    print("- Shape/Dimensions: " + str(img.shape))
    

    Salida:

    Image Properties
    - Number of Pixels: 2782440
    - Shape/Dimensions: (1180, 786, 3)
    

    Divisi贸n de im谩genes en canales individuales

    Ahora dividiremos la imagen en componentes rojo, verde y azul usando OpenCV y los mostraremos:

    from google.colab.patches import cv2_imshow
    
    blue, green, red = cv2.split(img) # Split the image into its channels
    img_gs = cv2.imread('rose.jpg', cv2.IMREAD_GRAYSCALE) # Convert image to grayscale
    
    cv2_imshow(red) # Display the red channel in the image
    cv2_imshow(blue) # Display the red channel in the image
    cv2_imshow(green) # Display the red channel in the image
    cv2_imshow(img_gs) # Display the grayscale version of image
    

    Para mayor nitidez, solo mostraremos la imagen en escala de grises.

    Imagen en escala de grises:

    Umbral de imagen

    El concepto del portal es bastante sencillo. Como se discuti贸 anteriormente en la representaci贸n de la imagen, un valor de p铆xel puede ser cualquier valor entre 0 y 255. Digamos que queremos convertir una imagen en una imagen binaria, es decir, asignando un p铆xel a un valor de 0 o 1. Para hacer esto, podemos operar un umbral. Por ejemplo, si el valor de umbral (T) es 125, se asignar铆a un valor de 1 a cada p铆xel con valores superiores a 125, y se asignar铆a un valor de 0 a cada p铆xel con valores menores que o igual a. eso es a trav茅s del c贸digo para comprender mejor.

    Imagen utilizada para el portal:

    import cv2
    
    # Read image
    img = cv2.imread('image.png', 0)
    
    # Perform binary thresholding on the image with T = 125
    r, threshold = cv2.threshold(img, 125, 255, cv2.THRESH_BINARY)
    cv2_imshow(threshold)
    

    Salida:

    Como puede ver, en la imagen resultante, se establecieron dos regiones, es decir, la regi贸n negra (valor de p铆xel 0) y la regi贸n blanca (valor de p铆xel 1). Result贸 que el umbral que establecimos estaba en el centro de la imagen, por lo que los valores de blanco y negro se dividen.

    Solicitud

    # 1: Eliminaci贸n de ruido de la imagen

    Ahora que tiene una idea b谩sica de qu茅 es el procesamiento de im谩genes y c贸mo se usa, sigamos adelante y aprendamos sobre algunas de sus funciones espec铆ficas.

    En la mayor铆a de los casos, los datos sin procesar que recopilamos contienen ruido, es decir, caracter铆sticas no deseadas que dificultan la detecci贸n de la imagen. Si bien estas im谩genes se pueden usar directamente para la extracci贸n de caracter铆sticas, la precisi贸n del algoritmo sufrir铆a mucho. Esta es la raz贸n por la que el procesamiento de im谩genes se aplica a la imagen antes de enviarla al algoritmo para una mayor precisi贸n.

    Hay muchos tipos diferentes de ruido, como el ruido gaussiano, el ruido de sal y pimienta, etc. Podemos eliminar ese ruido de una imagen aplicando un filtro que elimine ese ruido, o al menos minimice su efecto. Tambi茅n hay muchas opciones de filtros, cada una de las cuales tiene diferentes m茅ritos, por lo que es la mejor para un tipo de ruido en particular.

    Para comprender esto correctamente, vamos a agregar ruido de “sal y pimienta” a la versi贸n en escala de grises de la imagen de la rosa que consideramos anteriormente, y luego intentaremos eliminar ese ruido de nuestra imagen de ruido usando varios filtros y ver cu谩l es el m谩s adecuado para ese tipo.

    import numpy as np
    
    # Adding salt & pepper noise to an image
    def salt_pepper(prob):
          # Extract image dimensions
          row, col = img_gs.shape
    
          # Declare salt & pepper noise ratio
          s_vs_p = 0.5
          output = np.copy(img_gs)
    
          # Apply salt noise on each pixel individually
          num_salt = np.ceil(prob * img_gs.size * s_vs_p)
          coords = [np.random.randint(0, i - 1, int(num_salt))
                for i in img_gs.shape]
          output[coords] = 1
    
          # Apply pepper noise on each pixel individually
          num_pepper = np.ceil(prob * img_gs.size * (1. - s_vs_p))
          coords = [np.random.randint(0, i - 1, int(num_pepper))
                for i in img_gs.shape]
          output[coords] = 0
          cv2_imshow(output)
    
          return output
    
    # Call salt & pepper function with probability = 0.5
    # on the grayscale image of rose
    sp_05 = salt_pepper(0.5)
    
    # Store the resultant image as 'sp_05.jpg'
    cv2.imwrite('sp_05.jpg', sp_05)
    

    Bien, hemos agregado ruido a nuestra imagen de rosa, y ahora se ve as铆:

    Imagen ruidosa:

    Ahora aplique diferentes filtros y observe nuestras observaciones, es decir, qu茅 tan bien cada filtro reduce el ruido.

    Filtro aritm茅tico con n煤cleo afilado
    # Create our sharpening kernel, the sum of all values must equal to one for uniformity
    kernel_sharpening = np.array([[-1,-1,-1],
                                  [-1, 9,-1],
                                  [-1,-1,-1]])
    
    # Applying the sharpening kernel to the grayscale image & displaying it.
    print("nn--- Effects on S&P Noise Image with Probability 0.5 ---nn")
    
    # Applying filter on image with salt & pepper noise
    sharpened_img = cv2.filter2D(sp_05, -1, kernel_sharpening)
    cv2_imshow(sharpened_img)
    

    La imagen resultante se muestra a continuaci贸n, de aplicar un filtro aritm茅tico a la imagen con el ruido de sal y pimienta. En comparaci贸n con la imagen en escala de grises original, podemos ver que ilumina demasiado la imagen y tampoco puede resaltar los puntos brillantes de la rosa. Por lo tanto, se puede concluir que un filtro aritm茅tico no elimina el ruido de sal y pimienta.

    Salida de filtro aritm茅tico:

    Filtro de punto medio
    from scipy.ndimage import maximum_filter, minimum_filter
    
    def midpoint(img):
        maxf = maximum_filter(img, (3, 3))
        minf = minimum_filter(img, (3, 3))
        midpoint = (maxf + minf) / 2
        cv2_imshow(midpoint)
    
    print("nn---Effects on S&P Noise Image with Probability 0.5---nn")
    midpoint(sp_05)
    

    A continuaci贸n se muestra la imagen resultante, de aplicar el filtro de punto medio a la imagen con el ruido de sal y pimienta. Cuando se compara con la imagen en escala de grises original, podemos ver que, al igual que el m茅todo del n煤cleo anterior, aclara demasiado la imagen; sin embargo, es capaz de resaltar los puntos brillantes de la rosa. Por tanto, podemos decir que es una mejor opci贸n que el filtro aritm茅tico, pero a煤n as铆 no recupera por completo la imagen original.

    Salida de filtro de punto medio:

    Medios de filtro contraarm贸nicos

    Nota : La aplicaci贸n de estos filtros se puede encontrar f谩cilmente en l铆nea y c贸mo funcionan exactamente est谩 fuera del alcance de este tutorial. Examinaremos las aplicaciones desde un nivel abstracto / superior.

    def contraharmonic_mean(img, size, Q):
        num = np.power(img, Q + 1)
        denom = np.power(img, Q)
        kernel = np.full(size, 1.0)
        result = cv2.filter2D(num, -1, kernel) / cv2.filter2D(denom, -1, kernel)
        return result
    
    print("nn--- Effects on S&P Noise Image with Probability 0.5 ---nn")
    cv2_imshow(contraharmonic_mean(sp_05, (3,3), 0.5))
    

    La imagen resultante, de la aplicaci贸n de Contraharmonic Media, se muestra debajo de la imagen con el ruido de sal y pimienta. Cuando se compara con la imagen en escala de grises original, podemos ver que reproduc铆a pr谩cticamente la misma imagen que el original. Su nivel de intensidad / brillo es el mismo y tambi茅n resalta los puntos brillantes de la rosa. Por lo tanto, podemos concluir que el medio de filtro contraarm贸nico es muy eficaz para tratar el ruido de sal y pimienta.

    Filtro contraarm贸nico de salida promedio:

    Ahora que hemos encontrado el mejor filtro para recuperar la imagen original de una imagen de ruido, podemos pasar a la siguiente aplicaci贸n.

    # 2: Detecci贸n de bordes usando Canny Edge Detector

    La imagen de la rosa que estamos usando hasta ahora tiene un fondo estable, es decir, negro, por lo que usaremos una imagen diferente para esta aplicaci贸n para mostrar mejor las capacidades del algoritmo. La raz贸n es que, si el fondo es estable, hace que la tarea de detecci贸n de bordes sea relativamente simple, y no queremos eso.

    Hablamos sobre un clasificador de gatos anteriormente en este tutorial, avancemos ese ejemplo y veamos c贸mo el procesamiento de im谩genes juega un papel clave en eso.

    En un algoritmo de clasificaci贸n, primero se escanea la imagen en busca de ‘objetos’, es decir, cuando ingresa una imagen, el algoritmo encuentra todos los objetos en esa imagen y luego los compara con las caracter铆sticas del objeto que est谩 tratando de ver. Para un clasificador de gatos, comparar铆a todos los objetos que se encuentran en una imagen y las caracter铆sticas de una imagen de gato, y si se encuentran sirvientas, nos dice que la imagen de entrada contiene un gato.

    Dado que estamos usando el clasificador de gatos como ejemplo, es justo usar una imagen de gato a medida que avanzamos. A continuaci贸n se muestra la imagen que usaremos:

    Imagen utilizada para la detecci贸n de bordes:

    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    # Declaring the output graph's size
    plt.figure(figsize=(16, 16))
    
    # Convert image to grayscale
    img_gs = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)
    cv2.imwrite('gs.jpg', img_gs)
    
    # Apply canny edge detector algorithm on the image to find edges
    edges = cv2.Canny(img_gs, 100,200)
    
    # Plot the original image against the edges
    plt.subplot(121), plt.imshow(img_gs)
    plt.title('Original Gray Scale Image')
    plt.subplot(122), plt.imshow(edges)
    plt.title('Edge Image')
    
    # Display the two images
    plt.show()
    

    Salida de detecci贸n de margen:

    Como puede ver, la parte de la imagen que contiene un objeto, en este caso un gato, est谩 punteada / separada por detecci贸n de bordes. Ahora tienes que pensar, qu茅 es el Canny Edge Detector y c贸mo hizo que esto sucediera; as铆 que hablemos de eso ahora.

    Para comprender lo anterior, hay tres pasos principales que deben discutirse. Primero, reduce el ruido en la imagen de la misma manera que discutimos antes. En segundo lugar, utiliza la primera derivada de cada p铆xel para obtener bordes. La l贸gica detr谩s de esto es que hay un cambio repentino de intensidad, el punto donde hay un borde, que hace un pico en el valor de la primera derivada, y tambi茅n lo hace ese p铆xel como un “p铆xel de borde”.

    Al final, alcanza la hist茅resis; dijimos anteriormente que el valor de la primera derivada es un pico en un borde, pero no mencionamos ‘qu茅 tan alto’ debe ser el pico para ser clasificado como un borde – 隆esto se llama umbral! Anteriormente en este tutorial discutimos qu茅 es un umbral simple. El umbral de hist茅resis es una mejora, utiliza dos valores de umbral en lugar de uno. La raz贸n de esto es que si el valor de umbral es demasiado alto, podemos perder algunos bordes negativos reales (verdaderos) y si el valor es demasiado bajo, obtendr铆amos muchos puntos clasificados como bordes no reales (). Cosas falsas positivas) . Un valor de umbral establecido es alto y el otro es bajo. Todos los puntos por encima del ‘valor de umbral alto’ se identifican como m谩rgenes, entonces se consideran todos los puntos por encima del valor de umbral bajo pero por debajo del valor de umbral alto; los puntos que son adyacentes a puntos que se conocen como bordes o que son vecinos se identifican como bordes y el resto se destruye.

    Estos son los conceptos / m茅todos b谩sicos utilizados por el algoritmo Canny Edge Detector para identificar los bordes en una imagen.

    Conclusi贸n

    En este art铆culo, aprendimos c贸mo instalar OpenCV, la biblioteca de procesamiento de im谩genes m谩s popular en Python, en varias plataformas como Windows, MacOS y Linux, y tambi茅n c贸mo verificar que la instalaci贸n fue exitosa.

    Continuamos discutiendo qu茅 es el procesamiento de im谩genes y sus usos en el campo de la visi贸n por computadora del Machine Learning. Hablamos sobre algunos tipos comunes de ruido y c贸mo podemos eliminarlo de nuestras im谩genes usando varios filtros, antes de usar las im谩genes en nuestras aplicaciones.

    Adem谩s, aprendimos c贸mo el procesamiento de im谩genes juega un papel clave en aplicaciones de alta gama, como la detecci贸n o clasificaci贸n de objetos. Tenga en cuenta que este art铆culo fue solo la punta del iceberg, y hay mucho m谩s en el procesamiento de im谩genes digitales en la tienda que posiblemente no se puedan cubrir en un tutorial. Esto deber铆a permitirle profundizar y aprender sobre otros conceptos avanzados relacionados con el procesamiento de im谩genes. 隆Buena suerte!

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *