Tutorial de Visión por Computadora 2: Conceptos Básicos de Imágenes

Este tutorial es la base de la visión por computadora entregada como “Lección 2” de la serie; hay más lecciones próximas que hablarán sobre la construcción de sus propios proyectos de visión por computadora basados en aprendizaje profundo. Puedes encontrar el plan de estudios completo y tabla de contenido aquí.

Los puntos clave de este artículo son:

  • Cargar una imagen desde el disco.
  • Obtener la ‘Altura’, ‘Ancho’ y ‘Profundidad’ de la imagen.
  • Encontrar los componentes R, G y B de la imagen.
  • Dibujar usando OpenCV.

Cargar una Imagen desde el Disco

Antes de realizar cualquier operación o manipulación de una imagen, es importante para nosotros cargar una imagen de nuestra elección al disco. Realizaremos esta actividad utilizando OpenCV. Hay dos formas en que podemos realizar esta operación de carga. Una manera es cargar la imagen simplemente pasando la ruta de la imagen y el archivo de imagen a la función “imread” de OpenCV. La otra manera es pasar la imagen a través de un argumento de línea de comandos usando el módulo de Python argparse.

Fig 2.1 Loading an Image from Disk by hard coding the image path and name in code.

Python

 

#Cargar Imagen desde el disco

import cv2
image = cv2.imread(“C:/Sample_program/example.jpg”)
cv2.imshow(‘Image’, image)
cv2.waitKey(0)

Vamos a crear un archivo llamado Loading_image_from_disk.py en Notepad++. Primero, importamos nuestra biblioteca OpenCV, que contiene las funciones de procesamiento de imágenes. Importamos la biblioteca usando la primera línea de código como cv2. La segunda línea de código es donde leemos nuestra imagen utilizando la función cv2.imread en OpenCV, y pasamos la ruta de la imagen como parámetro; la ruta también debe contener el nombre del archivo con su extensión de formato de imagen .jpg, .jpeg, .png o .tiff.

sintaxis// image=cv2.imread(“ruta/a/tu/imagen.jpg”) //

Es necesario tener mucho cuidado al especificar el nombre de la extensión del archivo. Es probable que recibamos el siguiente error si proporcionamos la extensión incorrecta.

Python

 

ERROR :

c:\Sample_program>python Loading_image_from_disk.py
Traceback (most recent call last):
File “Loading_image_from_disk.py”, line 4, in <module>
cv2.imshow(‘Image’, image)
cv2.error: OpenCV(4.3.0) C:\projects\opencv-python\opencv\modules\highgui\src\window.cpp:376: error: (-215:Assertion failed) size.width>0 && size.height>0 in function ‘cv::imshow’

La tercera línea de código es donde realmente mostramos la imagen cargada. El primer parámetro es una cadena, o el “nombre” de nuestra ventana. El segundo parámetro es el objeto al que se cargó la imagen.

Finalmente, una llamada a cv2.waitKey pausa la ejecución del script hasta que presionamos una tecla en nuestro teclado. Usar un parámetro de “0” indica que cualquier pulsación de tecla desactivará la pausa de la ejecución. Siéntase libre de ejecutar su programa sin tener la última línea de código en su programa para ver la diferencia.

Fig 2.2 Loading an Image using Argparse module.

Python

 

#Leer imagen desde el disco usando Argparse

import cv2
import argparse

apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())

image = cv2.imread(args[“image”])
cv2.imshow(‘Image’, image)
cv2.waitKey(0)

Saber leer una imagen o archivo usando un argumento de línea de comando (argparse) es una habilidad absolutamente necesaria.

Las dos primeras líneas de código son para importar las bibliotecas necesarias; aquí, importamos OpenCV y Argparse. Repetiremos esto a lo largo del curso.

Las siguientes tres líneas de código manejan la interpretación de los argumentos de la línea de comandos. El único argumento que necesitamos es — image: la ruta de nuestra imagen en el disco. Finalmente, parseamos los argumentos y los almacenamos en un diccionario llamado args.

Tomemos un segundo y discutamos rápidamente exactamente qué es el interruptor — image. El — image “interruptor” (“interruptor” es sinónimo de “argumento de línea de comandos” y los términos pueden usarse indistintamente) es una cadena que especificamos en la línea de comandos. Este interruptor indica a nuestro script Loading_image_from_disk.py, dónde vive la imagen que queremos cargar en el disco.

Las últimas tres líneas de código se discuten anteriormente; la función cv2.imread toma args[“image’] como parámetro, que no es más que la imagen que proporcionamos en el comando prompt. cv2.imshow muestra la imagen, que ya está almacenada en un objeto de imagen desde la línea anterior. La última línea pausa la ejecución del script hasta que presionamos una tecla en nuestro teclado.

Una de las principales ventajas de usar un argparse — argumento de línea de comandos es que podremos cargar imágenes desde diferentes ubicaciones de carpetas sin tener que cambiar la ruta de la imagen en nuestro programa pasando dinámicamente la ruta de la imagen Ex — “ C:\CV_Material\image\sample.jpg “ en el comando prompt como argumento mientras ejecutamos nuestro programa de python.

Fig 2.3 Loading Images from different folder locations using Argparse.

c:\Sample_program>python Loading_image_from_disk.py — image C:\CV_Material\session1.JPG

Aquí, estamos ejecutando el Loading_image_from_disk.py archivo python desde c:\sample_program ubicación pasando el parámetro “-image” junto con la ruta de la imagen C:\CV_Material\session1.JPG.

Obtener la ‘Altura’, ‘Ancho’ y ‘Profundidad’ de la Imagen

Como las imágenes se representan como matrices de NumPy, podemos simplemente usar el atributo .shape para examinar el ancho, la altura y el número de canales.

Al utilizar el atributo .shape en el objeto de imagen que acabamos de cargar, podemos encontrar la altura, el ancho y la profundidad de la imagen. Como se discutió en la lección anterior — 1, la altura y el ancho de la imagen pueden verificarse cruzadamente abriendo la imagen en MS Paint. Consulte la lección anterior. Discutiremos sobre la profundidad de la imagen en las próximas lecciones. La profundidad también se conoce como canal de una imagen. Las imágenes en color suelen tener 3 canales debido a la composición RGB en sus píxeles y las imágenes en escala de grises tienen 1 canal. Esto es algo que habíamos discutido en la Lección-1.

Fig 2.4 Prints the Height, Width, and Depth of the Image.

Python

 

#Obtener Altura, Ancho y Profundidad de una Imagen

import cv2
import argparse

apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())

# Solo diferencia con los códigos anteriores — se aplica el atributo shape al objeto de imagen

print(f’(Height,Width,Depth) of the image is: {image.shape}’)

image = cv2.imread(args[“image”])
cv2.imshow(‘Image’, image)
cv2.waitKey(0)

Salida:

(Altura, Ancho, Profundidad) de la imagen es: (538, 723, 3)

La única diferencia con los códigos anteriores es la sentencia print que aplica el atributo shape al objeto de imagen cargado. f’ es la cadena F o cadena formateada que toma variables dinámicamente y las imprime.

f’ write anything here that you want to see in the print statement: {variables, variables, object, object.attribute,}’

Aquí, hemos utilizado {object.attribute} dentro del corchete de flor para el atributo .shape para calcular la altura, anchura y profundidad del objeto de imagen.

Python

 

#Obtener Altura, Anchura y Profundidad por separado

import cv2
import argparse

apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())

image = cv2.imread(args[“image”])

#Slicing de matriz NumPy para obtener la altura, anchura y profundidad por separado

print(“height: %d pixels” % (image.shape[0]))
print(“width: %d pixels” % (image.shape[1]))
print(“depth: %d” % (image.shape[2]))

cv2.imshow(‘Image’, image)
cv2.waitKey(0)

Salida:

anchura: 723 píxeles
altura: 538 píxeles
profundidad: 3

Aquí, en lugar de obtener la (altura, anchura y profundidad) juntas como una tupla. Realizamos el slicing de la matriz y obtenemos la altura, anchura y profundidad de la imagen individualmente. El índice 0 de la matriz contiene la altura de la imagen, el índice 1 contiene la anchura de la imagen y el índice 2 contiene la profundidad de la imagen.

Encontrar los Componentes R, G y B de la Imagen

Fig 2.5 BGR value printed after taking the pixel co-ordinate position (y,x).

Salida:

El valor del componente Azul Verde Rojo de la imagen en la posición (321, 308) es: (238, 242, 253)

Observa cómo el valor de y se pasa antes del valor de x —esta sintaxis puede parecer contraintuitiva al principio, pero es consistente con cómo accedemos a los valores en una matriz: primero especificamos el número de fila, luego el número de columna. A partir de ahí, se nos da una tupla que representa los componentes Azul, Verde y Rojo de la imagen.

También podemos cambiar el color de un píxel en una posición dada invirtiendo la operación.

Python

 

#Encontrar R, B, G de la Imagen en la posición (x, y)

import cv2
import argparse

apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())

image = cv2.imread(args[“image”])

#Recibir el valor de coordenadas de píxel como [y, x] del usuario, para el cual se deben calcular los valores RGB
[y,x] = list(int(x.strip()) for x in input().split(‘,’))

#Extraer los valores (Azul, verde, rojo) de las coordenadas de píxel recibidas
(b,g,r) = image[y,x]
print(f’The Blue Green Red component value of the image at position {(y,x)} is: {(b,g,r)}’)

cv2.imshow(‘Image’, image)
cv2.waitKey(0)

(b,g,r) = image[y,x] a image[y,x] = (b,g,r)

Aquí asignamos el color en (BGR) a la coordenada de píxel de la imagen. Intentémoslo asignando el color ROJO al píxel en la posición (321,308) y validémoslo imprimiendo el BGR del píxel en esa posición.

Python

 

# Invertir la operación para asignar el valor RGB al píxel de nuestra elección

import cv2
import argparse

apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())

image = cv2.imread(args[“image”])

# Recibir el valor de la coordenada de píxel como [y,x] del usuario, para el cual se deben calcular los valores RGB
[y,x] = list(int(x.strip()) for x in input().split(‘,’))

# Extraer los valores (Azul, Verde, Rojo) de la coordenada de píxel recibida
image[y,x] = (0,0,255)
(b,g,r) = image[y,x]
print(f’The Blue Green Red component value of the image at position {(y,x)} is: {(b,g,r)}’)

cv2.imshow(‘Image’, image)
cv2.waitKey(0)

Salida:

Los valores de los componentes Azul, Verde y Rojo de la imagen en la posición (321, 308) son (0, 0, 255)

En el código anterior, recibimos la coordenada de píxel a través del comando de la ventana de entrada introduciendo el valor como se muestra en la Figura 2.6 a continuación y asignamos la coordenada de píxel el color rojo asignando (0,0,255) es decir, (Azul, Verde, Rojo) y validamos lo mismo imprimiendo la coordenada de píxel de entrada.

Dibujar usando OpenCV

Aprendamos cómo dibujar diferentes formas como rectángulos, cuadrados y círculos usando OpenCV dibujando círculos para enmascarar mis ojos, rectángulos para enmascarar mis labios y rectángulos para enmascarar el pez mantra-ray a mi lado.

La salida debería verse así:

Fig 2.6 Masked Photo of me with the mantra-ray fish.

Esta foto está enmascarada con formas usando MS Paint; intentaremos hacer lo mismo usando OpenCV dibujando círculos alrededor de mis ojos y rectángulos para enmascarar mis labios y el pez matra-ray a mi lado.

Utilizamos el método cv2.rectangle para dibujar un rectángulo y el método cv2.circle para dibujar un círculo en OpenCV.

cv2.rectangle(image, (x1, y1), (x2, y2), (Blue, Green, Red), Thickness)

El método cv2.rectangle toma una imagen como su primer argumento en la que queremos dibujar nuestro rectángulo. Queremos dibujar en el objeto de imagen cargado, por lo que lo pasamos al método. El segundo argumento es la posición de inicio (x1, y1) de nuestro rectángulo — aquí, estamos comenzando nuestro rectángulo en los puntos (156 y 340). Luego, debemos proporcionar un punto de finalización (x2, y2) para el rectángulo. Decidimos terminar nuestro rectángulo en (360, 450). El siguiente argumento es el color del rectángulo que queremos dibujar; aquí, en este caso, estamos pasando el color negro en formato BGR, es decir, (0,0,0). Finalmente, el último argumento que pasamos es el grosor de la línea. Damos -1 para dibujar formas sólidas, como se ve en la Fig 2.6.

De manera similar, utilizamos el método cv2.circle para dibujar el círculo.

cv2.circle(image, (x, y), r, (Blue, Green, Red), Thickness)

El método cv2.circle toma una imagen como su primer argumento en la que queremos dibujar nuestro rectángulo. Queremos dibujar en el objeto de imagen que hemos cargado, por lo que lo pasamos al método. El segundo argumento es la posición central (x, y) de nuestro círculo — aquí, hemos tomado nuestro círculo en el punto (343, 243). El siguiente argumento es el radio del círculo que queremos dibujar. El siguiente argumento es el color del círculo; aquí, en este caso, estamos pasando el color ROJO en formato BGR, es decir, (0,0,255). Finalmente, el último argumento que pasamos es el grosor de la línea. Damos -1 para dibujar formas sólidas, como se ve en la Fig 2.6.

¡De acuerdo! Sabiendo todo esto, intentemos lograr lo que comenzamos. Para dibujar las formas en la imagen, necesitamos identificar las coordenadas de inicio y fin (x, y) de la región de enmascaramiento para pasarlas al método correspondiente.

¿Cómo?

Vamos a recurrir a MS Paint una vez más. Al colocar el cursor sobre una de las coordenadas (superior izquierda) o (inferior derecha) de la región a enmascarar, las coordenadas se muestran en la porción resaltada de MS Paint, como se muestra en la Figura 2.7.

Fig 2.7 MSPaint to find the co-ordinates of the masking region.

De manera similar, tomaremos todas las coordenadas (x1, y1) (x2, y2) para todas las regiones de enmascaramiento, como se muestra en la Figura 2.8.

Fig 2.8 (x.y) Co-ordinates of masking regions.

Python

 

#Dibujar usando OpenCV para enmascarar los ojos, la boca y objetos cercanos

import cv2
import argparse

apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())

image = cv2.imread(args[“image”])

cv2.rectangle(image, (415, 168), (471, 191), (0, 0, 255), -1)
cv2.circle(image, (425, 150), 15, (0, 0, 255), -1)
cv2.circle(image, (457, 154), 15, (0, 0, 255), -1)
cv2.rectangle(image, (156, 340), (360, 450), (0, 0, 0), -1)

#Mostrar la imagen de salida
cv2.imshow(“Output drawing “, image)
cv2.waitKey(0)

Resultado:



Fig 2.9 Desired Output.

Source:
https://dzone.com/articles/computer-vision-tutorial-2-image-basics