You are on page 1of 68

qwertyuiopasdfghjklzxcvbnmqw

p
TECNOLÓGICO NACIONAL DE MEXICO
Instituto Tecnológico Superior de Pátzcuaro

ertyuiopasdfghjklzxcvbnmqwert
yuiopasdfghjklzxcvbnmqwertyui
opasdfghjklzxcvbnmqwertyuiopa
sdfghjklzxcvbnmqwertyuiopasdf
Manual de Prácticas de Procesamiento
Avanzado de Imágenes
ghjklzxcvbnmqwertyuiopasdfghj
klzxcvbnmqwertyuiopasdfghjklz
Academia de Ingeniería Biomédica

xcvbnmqwertyuiopasdfghjklzxcv
MTI Mario Salvador Castro Zenil

bnmqwertyuiopasdfghjklzxcvbn
mqwertyuiopasdfghjklzxcvbnmq
wertyuiopasdfghjklzxcvbnmqwe
rtyuiopasdfghjklzxcvbnmqwerty
uiopasdfghjklzxcvbnmqwertyuio
pasdfghjklzxcvbnmqwertyuiopas
dfghjklzxcvbnmqwertyuiopasdfg
hjklzxcvbnmqwertyuiopasdfghjk
lzxcvbnmrtyuiopasdfghjklzxcvbn
Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro
Pátzcuaro, Michoacan, México. C.P. 61615 1
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Introducción OpenCV Python

Tutorial de introducción a la programación de aplicaciones de visión por computador usando la


biblioteca OpenCV 3.x desde el lenguaje de programación Python 3.x.

Leer y guardar archivos de imagen

La tarea más simple y común que realizaremos será cargar imagen a partir de una archivo en
disco, para hacerlo disponemos de la función imread() , mientras que imwrite() nos
permitirá guardar una imagen.

Al cargar una imagen esta es almacenada en memoria usando el formato de color BGR, por
defecto, este es igual al espacio de color RGB pero con los canales invertidos, aquí se
almacena la información para cada uno de los canales azul, verde y rojo.

Opcionalmente se puede indicar el modo, por defecto, IMREAD_COLOR, si deseamos cargar


la imagen a escala de grises usaremos, IMREAD_GRAYSCALE, mientras que el modo
IMREAD_UNCHANGED cargará la imagen en el formato de color definido por el archivo.

import cv2

# cargar el archivo PNG indicado


img = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE)

# guardar la imagen en formato JPG


cv2.imwrite('save.jpg', img)

Al guardar la imagen se utilizara el formato definido por la extensión que le demos al nombre
de la imagen, siempre que el mismo este soportado, algunos de estos formatos son: PNG,
BMP, TIFF, JPG, otros.

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 2
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Mostrar una imagen

Cuando hayamos cargado una imagen en memoria es posible mostrarla en una ventana, para
este propósito tenemos la función imshow() , con ella creamos una ventana y desplegamos la
imagen deseada, debemos indicar el nombre y el objeto que deseamos mostrar, ejemplo:

import cv2

# cargar el archivo PNG indicado


img = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE)

# mostrar la imagen en una ventana


cv2.imshow('titulo', img)

# esperar hasta que se presiona una tecla


cv2.waitKey(0)

Al final vemos una llamada a waitKey(0) , con esto impedimos que la ventana se cierre
inmediatamente, el valor cero indica que se debe esperar indefinidamente hasta que se
presione una tecla, si establecemos un valor mayor que cero este será la cantidad de
milisegundos que se debe esperar.

Esta función devuelve el código ASCII de la tecla presionada, por ejemplo, 27 para la tecla
ESC.

Cuando deseemos destruir una ventana usaremos destroyWindow('ventana') indicando el


nombre de la ventana que deseamos eliminar, si tenemos varias ventanas y deseamos
destruirlas todas disponemos de destroyAllWindows()

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 3
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Capturar video de la webcam

No solo podemos trabajar con imágenes cargadas desde archivos, también podemos leer
imágenes desde la cámara web de nuestro PC, si capturamos una serie de imágenes
sucesivas tendremos un video en tiempo real, veamos como se hace.

Para capturar imágenes provenientes de la cámara usaremos un objeto VideoCapture(0)


debemos indicar el índice de la cámara que deseamos utilizar, por ejemplo, si tenemos dos
habilitadas, indicamos cero para la primera, uno para la siguiente y así sucesivamente.

En lugar de indicar el índice de cámara, también es posible indicar el nombre de un archivo de


video, si el formato esta soportado este se visualizará.

import cv2

cap = cv2.VideoCapture(0)

while(True):
ret, frame = cap.read()

if ret:
cv2.imshow('video', frame)

if cv2.waitKey(1) & 0xFF == 27:


break

cap.release()
cv2.destroyAllWindows()

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 4
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Para capturar un cuadro de video usamos cap.read() este devuelve un booleano que indica
si la captura es válida y el objeto imagen que representa la captura, de aquí en adelanta
tratamos la captura como si fuese cualquier otra imagen, al terminar
usaremos cap.release() para liberar recursos.

Guardar un archivo de video

Para escribir un archivo de video necesitaremos un objeto VideoWriter indicaremos el


nombre del archivo, el codec a utilizar, el fps (cuadros por segundo) y el tamaño del video.

Los codec que podemos utilizar dependen de cada sistema, es decir si no tienes los codec
para FLV no podrás ver ni escribir en este formato, utilizaremos un código de 4 bytes para
identificar cada uno de ellos, puedes encontrar la lista en, fourcc.org, para indicarlo tenemos la
función: cv2.VideoWriter_fourcc('M','J','P','G') para MJPG.

import cv2

cap = cv2.VideoCapture('video.avi')

# Definir el codec y crear el objeto VideoWriter


fourcc = cv2.VideoWriter_fourcc('M','S','V','C')
out = cv2.VideoWriter('output.avi', fourcc, 25.0, (720, 528))

while(True):
# capturar el cuadro
ret, frame = cap.read()

if ret:
# procesar la captura, convertir a grises
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# escribir el cuadro procesado

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 5
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

out.write(gray)

# mostar la captura actual


cv2.imshow('video', gray)

# esperar, si se presiona la tecla ESC salir


if cv2.waitKey(1) & 0xFF == 27:
break

cap.release()
out.release()

cv2.destroyAllWindows()

Carga de imágenes y videos


Práctica De acuerdo a los códigos anteriores carga una imagen y un video de la
1.1 webcam de tu computadora. Reporta el código y las impresiones de pantalla
en el formato de práctica

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 6
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Manipular pixeles OpenCV Python

Veremos cómo aplicar las operaciones básicas sobre imágenes cargadas en memoria
mediante OpenCV, veremos cómo acceder a los pixeles de una imagen y modificarlos,
aprenderemos a seleccionar una región de interés (ROI) y mostraremos como trabajar con los
distintos canales de una imagen.

Para utilizar correctamente OpenCV desde Python se requiere tener un buen conocimiento de
Numpy.

Obtener y modificar un pixel

Luego de cargar una imagen podemos acceder a cada uno de los pixeles de la misma, para
una imagen a color obtendremos los canales: azul, verde y rojo, si la imagen es a escala de
grises solo tendremos un canal, el cual indica la intensidad de gris de dicho pixel.

import cv2

image = cv2.imread('lena.jpg')

# obtener el valor BGR del pixel en la posicion (10, 50)


b, g, r = image[10, 50]

print('pixel:', b, g, r)

De manera similar podemos modificar el valor de un pixel:

image[100,100] = [255,255,255]

Un modo más eficiente de acceder a un pixel es usando las funciones


Numpy: array.item() y array.itemset() .

import cv2

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 7
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

image = cv2.imread('lena.jpg')

x = 240
y = 178

b = image.item(y, x, 0)
g = image.item(y, x, 1)
r = image.item(y, x, 2)

print('pixel:', b, g, r)

Para modificar un pixel usaremos:

image.itemset((y, x, 0), 255)


image.itemset((y, x, 1), 255)
image.itemset((y, x, 2), 255)

Con esto modificamos las componente BGR del pixel ubicado en la posición (x, y).

Propiedades de una imagen

Podemos acceder a las distintas propiedades de una imagen, por ejemplo:

Obtener el numero de filas, columnas y canales que componen una imagen, si la imagen es
ha escala de grises la tupla devuelta solo contiene los dos primeros valores.

>>> image.shape
(512, 512, 3)

Para obtener el numero total de pixel que componen la imagen.

>>> image.size
786432

Cuando deseemos obtener el tipo de datos usado para almacenar los pixeles.

>>> image.dtype

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 8
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

dtype('uint8')

Copiar una región

En ocasiones deseamos trabajar con una porción de la imagen original, en esos casos
podemos usar el indexing de Numpy para seleccionar y copiar la región rectangular deseada,
ejemplo:

import cv2

image = cv2.imread('lena.jpg')
roi = image[240:375, 215:365]

cv2.imshow('roi', roi)
cv2.imshow('original', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Para indicar la región que seleccionaremos indicamos primero el valor de las


coordenadas y0 y y1 luego x0 y x1 de este modo: img[y0:y1, x0:x1]

roi = image[240:375, 215:365]

Este código genera el siguiente resultado:

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 9
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Manipulación de Pixeles
Práctica De acuerdo a los códigos anteriores carga una imagen y escoge un valor que
1.2 quieras resaltar de la imagen. Reporta el código y las impresiones de pantalla
en el formato de práctica

Funciones de dibujo OpenCV Python

OpenCV nos proporciona varias funciones que nos permiten dibujas diversas figuras de una
menara rápida y sencilla, para esta práctica haremos uso del trackbar y el ratón para dibujar
figuras como círculos, rectángulos y líneas, además veremos las funciones usadas para pintar
elipses, polígonos y texto.

Las funciones de dibujo tienen los siguientes parámetros en común:

 img: imagen sobre la que se desea dibujar, siempre es el primero que indicamos.
 color: color con que se debe pintar la figura.
 thickness: grosor del contorno de la figura, -1 rellena la figura, el valor por defecto es 1.
 lineType: define el tipo de línea, por defecto es cv2.LINE_8, la opción cv2.LINE_AA
usa anti-aliased por lo que el resultado será mejor, también puedes usar cv2.LINE_4.

Para esta primera demostración crearemos una aplicación que nos permitirá dibujar líneas,
círculos, y rectángulos usando el mouse, por ejemplo, para crear una línea hacemos clic
izquierdo en el punto inicial de la misma y arrastramos hasta el punto final, al soltar el botón
izquierdo la línea será dibujada.

import cv2
import numpy as np
from math import sqrt

mode = 'circle'
color = (0, 0, 255)

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 10
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

pt = None
tk = 1

def on_track(value):
global tk

# el valor -1 dibuja una figura rellena


tk = -1 if value == 0 else value

# no se puede rellenar una line


if mode == 'line' and tk == -1:
tk = 1

def on_mouse(event, x, y, flags, param):

global pt, draw

if event == cv2.EVENT_LBUTTONDOWN:
pt = (x, y)
print('Dibujando ', mode, ', en el punto: ', pt)

elif event == cv2.EVENT_LBUTTONUP:

if mode == 'circle':
rad = sqrt(pow(pt[0] - x, 2) + pow(pt[1] - y, 2))
cv2.circle(param, pt, int(rad), color, tk, cv2.LINE_AA)

elif mode == 'rectangle':


cv2.rectangle(param, pt, (x, y), color, tk, cv2.LINE_AA)

elif mode == 'line':


cv2.line(param, pt, (x, y), color, tk, cv2.LINE_AA)

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 11
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

if __name__ == "__main__":

title = 'Drawing'
image = np.zeros((600, 800, 3), np.uint8)

cv2.namedWindow(title)
cv2.createTrackbar('RELLENO', title, 1, 10, on_track)
cv2.setMouseCallback(title, on_mouse, image)

while(1):
cv2.imshow(title, image)
key = cv2.waitKey(20) & 0xFF;

if key == ord('c'):
mode = 'circle'
elif key == ord('r'):
mode = 'rectangle'
elif key == ord('l'):
mode = 'line'
elif key == 27:
break

cv2.destroyAllWindows()

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 12
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Esta es la aplicación completa, consta de las siguientes partes:

if __name__ == "__main__":

title = 'Drawing'
image = np.zeros((600, 800, 3), np.uint8)

cv2.namedWindow(title)
cv2.createTrackbar('RELLENO', title, 1, 10, on_track)
cv2.setMouseCallback(title, on_mouse, image)

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 13
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

while(1):
cv2.imshow(title, image)
key = cv2.waitKey(20) & 0xFF;

if key == ord('c'):
mode = 'circle'
elif key == ord('r'):
mode = 'rectangle'
elif key == ord('l'):
mode = 'line'
elif key == 27:
break

cv2.destroyAllWindows()

Aquí inicia la aplicación, se crea la imagen sobre la que dibujaremos de tamaño 800x600 de 3
canales de tipo uint8, creamos también la ventana, le agregamos un trackbar y el manejador
de eventos para el mouse.

El bucle inferior nos permite cambiar la figura que deseamos dibujar usando las teclas: c, r, l,
para dibujar círculos, rectángulos y líneas respectivamente, presionando ESC salimos de la
aplicación, al terminar el bucle destruimos la ventana.

def on_track(value):
global tk

# el valor -1 dibuja una figura rellena


tk = -1 if value == 0 else value

# no se puede rellenar una line


if mode == 'line' and tk == -1:
tk = 1

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 14
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Esta es la función invocada cada vez que cambia el valor del trackbar, este valor será usado
para definir el thickness de la figura, si el valor es cero lo cambiamos a -1 para dibujar una
figura rellena, debemos tener en cuenta que una línea no se puede rellenar.

def on_mouse(event, x, y, flags, param):

global pt, draw

if event == cv2.EVENT_LBUTTONDOWN:
pt = (x, y)
print('Dibujando ', mode, ', en el punto: ', pt)

elif event == cv2.EVENT_LBUTTONUP:

if mode == 'circle':
rad = sqrt(pow(pt[0] - x, 2) + pow(pt[1] - y, 2))
cv2.circle(param, pt, int(rad), color, tk, cv2.LINE_AA)

elif mode == 'rectangle':


cv2.rectangle(param, pt, (x, y), color, tk, cv2.LINE_AA)

elif mode == 'line':


cv2.line(param, pt, (x, y), color, tk, cv2.LINE_AA)

Aquí controlamos los eventos del mouse, al hacer clic izquierdo EVENT_LBUTTONDOWN
guardamos la posición del mouse, cunado soltamos dicho botón verificamos cual es la figura a
dibujar, obtenemos la posición actual y dibujamos la figura.

El parámetro llamado param corresponde a la imagen en donde se debe dibujar, este


parámetro fue enviado desde la función principal.

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 15
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Dibujar un círculo

Usamos la función cv2.circle() debemos indicar la imagen destino, el punto inicial y el


radio, los demás parámetros ya los conocimos al principio del tutorial.

if mode == 'circle':
rad = sqrt(pow(pt[0] - x, 2) + pow(pt[1] - y, 2))
cv2.circle(param, pt, int(rad), color, tk, cv2.LINE_AA)

Para obtener el radio calculamos la distancia que hay desde el primer punto hasta el punto
actual.

Dibujar un rectángulo

Para esta figura requerimos indicar dos puntos además de los parámetros comunes, el primer
punto corresponde a la esquina superior izquierda y el segundo a la esquina inferior derecha
del rectángulo, la función es cv2.rectangle() .

elif mode == 'rectangle':


cv2.rectangle(param, pt, (x, y), color, tk, cv2.LINE_AA)

Dibujar líneas

Con cv2.line() pintamos una líneas solo debemos indicar el punto inicial y final de la
misma.

elif mode == 'line':


cv2.line(param, pt, (x, y), color, tk, cv2.LINE_AA)

Existen otras funciones de dibujo que no hemos incluido en esta primera demostración, ellas
son para dibujar: textos, elipses y polígonos, veamos un ejemplo de como utilizarlas.

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 16
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

import cv2
import numpy as np

if __name__ == "__main__":

title = 'Drawing'
img = np.zeros((600, 800, 3), np.uint8)

font = cv2.FONT_HERSHEY_TRIPLEX
cv2.putText(img, 'OpenCV Python', (5, 560), font, 3, (255,255,255),
1, cv2.LINE_AA)

pts = np.array([[403, 75], [587, 312], [216, 150], [588, 155],


[215, 313]], np.int32)
cv2.polylines(img, [pts], True, (0, 255, 255), 5, cv2.LINE_AA)

cv2.ellipse(img, (400, 360), (100, 50), 0, 45, 360, (255, 0, 255),


-1, cv2.LINE_AA)

cv2.imshow(title, img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 17
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Explicación de cada una de las funciones utilizadas, al igual que las anteriores usamos los
parámetros comunes previamente explicados, el primer parámetro es la imagen en donde se
desea dibujar.

Dibujar Texto

Para pintar un texto tenemos la función cv2.putText() , le pasamos el texto, luego la


ubicación, sigue la fuente y su tamaño.

font = cv2.FONT_HERSHEY_TRIPLEX
cv2.putText(img, 'OpenCV Python', (5, 560), font, 3, (255,255,255), 1,
cv2.LINE_AA)

Las fuentes disponibles son las siguientes:

 FONT_HERSHEY_SIMPLEX
 FONT_HERSHEY_PLAIN
 FONT_HERSHEY_DUPLEX
 FONT_HERSHEY_COMPLEX
 FONT_HERSHEY_TRIPLEX

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 18
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

 FONT_HERSHEY_COMPLEX_SMALL
 FONT_HERSHEY_SCRIPT_SIMPLEX
 FONT_HERSHEY_SCRIPT_COMPLEX

Dibujar un polígono

Usando la función cv2.polylines() podemos dibujar una serie de líneas, debemos crear un
conjunto de puntos que definen la figura, esto puntos serán unidos usando líneas, de este
modo podemos crear figuras complejas, ejemplo, la estrella que vemos en la imagen superior.

pts = np.array([[403, 75], [587, 312], [216, 150], [588, 155], [215,
313]], np.int32)
cv2.polylines(img, [pts], True, (0, 255, 255), 5, cv2.LINE_AA)

La variable pts guarda cada uno de los puntos requeridos para formar la estrella, estos
corresponden a las puntas de la misma, el booleano que en nuestro caso hemos establecido a
True indica si se debe conectar el último punto con el primero.

Si deseamos dibujar una figura con relleno en su interior debemos


usar cv2.fillPoly(...) se utiliza de manera similar con la diferencia de que se rellena el
interior de la figura, ejemplo:

cv2.fillPoly(img, [pts], (0, 125, 125), cv2.LINE_AA)

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 19
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Otra función que trabaja de manera similar es cv2.fillConvexPoly(...) .

Dibujar una elipse

Para esta tarea usamos cv2.ellipse() de la siguiente manera:

cv2.ellipse(img, (400, 360), (100, 50), 0, 45, 360, (255, 0, 255), -1,
cv2.LINE_AA)

Los parámetros para la función son:

Esta función nos permite tener mucho control sobre la figura dibujar, para una explicación más
detallada de cada uno de los parámetros visita la documentación oficial.

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 20
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Dibujar marcadores

OpenCV nos proporciona la función cv2.drawMarker(...) que nos permite dibujar uno de
los marcadores seleccionado, debemos indicar su posición, el marcador, su color y
opcionalmente el tamaño del mismo, por ejemplo:

for marker in range(0, 7):


offset = 60 * marker
cv2.drawMarker(img, (100 + offset, 20), (0,255,0), marker)
cv2.drawMarker(img, (100 + offset, 60), (0,0,255), marker, 40, 1,
cv2.LINE_AA)
cv2.drawMarker(img, (100 + offset, 120), (255,0,0), marker, 40, 2)

Estos son los marcadores disponibles:

 MARKER_CROSS
 MARKER_TILTED_CROSS
 MARKER_STAR
 MARKER_DIAMOND
 MARKER_SQUARE
 MARKER_TRIANGLE_UP
 MARKER_TRIANGLE_DOWN

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 21
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Dibujar una flecha

Esta es la última función de dibujo que veremos cv2.arrowedLine() nos sirve para dibujar
una flecha, solo será necesario indicar el punto de inicio y final de la misma, ejemplo:

cv2.arrowedLine(img, (10, 20), (100, 20), (255, 100, 100), 1,


cv2.LINE_AA)
cv2.arrowedLine(img, (10, 40), (150, 40), (255, 100, 100), 2,
cv2.LINE_AA, 0, 0.3)
cv2.arrowedLine(img, (10, 60), (100, 60), (255, 100, 100), 2,
cv2.LINE_4)

Al dibujar la flecha del medio cambiamos el porcentaje que ocupa la punta de la fecha a 0.3.

Dibujo de formas
Práctica
Ejecuta los códigos anteriores, cambia algunos parámetros de color y tamaño.
1.3
Reporta el código y las impresiones de pantalla en el formato de práctica

Uso del mouse y trackbar OpenCV

El mouse y el trackbar son componentes de la GUI que nos ayudarán a interactuar con la
aplicación OpenCV que estemos desarrollando, esta la biblioteca nos permite agregar
manejadores de eventos para responder a eventos del ratón, de igual manera podemos
agregar una barra desplazable a una ventana y obtener el valor de la misma.

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 22
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Programación con trackbar

Para agregar este elemento a una ventana usamos la


función cv2.createTrackbar() debemos indicarle el titulo o etiqueta que mostrará, el
nombre de la ventana a la que pertenece, el valor actual, el valor máximo y la función callback
que será llamada cada vez que se cambie el valor del control.

title = 'Drawing'

cv2.namedWindow(title)
cv2.createTrackbar('Grosor', title, 5, 50, on_trackbar)

La función on_trackbar se define como sigue:

def on_trackbar(value):
print(value)

Este pequeño ejemplo imprime el valor actual del control, otra forma de obtener el valor es
usando la función cv2.getTrackbarPos('Grosor', 'Drawing') primero indicamos el
nombre del trackbar y luego la ventana en la que se encuentra, el valor devuelto por esta
función corresponde al valor del control indicado.

Programación con el ratón

Para agregar un manejador de eventos para el mouse usamos la


función cv2.setMouseCallback() el primer parámetro es el nombre de la ventana, seguido
de la función callback y luego opcionalmente podemos enviar un parámetro cualquiera a la
función callback, por ejemplo una imagen, de este modo evitamos usar variables globales.

title = 'Drawing'
image = np.zeros((600, 800, 3), np.uint8)

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 23
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

cv2.namedWindow(title)
cv2.setMouseCallback(title, on_mouse, image)

La función on_mouse es invocada cada vez que se produce un evento del mouse, esta
función tiene la siguiente forma:

def on_mouse(event, x, y, flags, param):

global start
pt = (x, y)

if event == cv2.EVENT_LBUTTONDOWN:
start = True
elif event == cv2.EVENT_LBUTTONUP:
start = False
elif start and event == cv2.EVENT_MOUSEMOVE:
ventana = 'Drawing'
grosor = cv2.getTrackbarPos('Grosor', ventana)

cv2.circle(param, pt, grosor, (255, 0, 255), -1)

En esta función x, y contienen la posición actual del mouse, param hace referencia al
parámetro opcional enviado desde la función principal.

El evento se identifica mediante event y puede tener los siguientes valores:

 EVENT_MOUSEMOVE movimiento del mouse


 EVENT_LBUTTONDOWN botón izquierdo presionado
 EVENT_RBUTTONDOWN botón derecho presionado
 EVENT_MBUTTONDOWN botón central presionado
 EVENT_LBUTTONUP botón izquierdo liberado
 EVENT_RBUTTONUP botón derecho liberado

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 24
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

 EVENT_MBUTTONUP botón central liberado


 EVENT_LBUTTONDBLCLK doble clic izquierdo
 EVENT_RBUTTONDBLCLK doble clic derecho
 EVENT_MBUTTONDBLCLK doble clic central
 EVENT_MOUSEWHEEL giro de la rueda vertical
 EVENT_MOUSEHWHEEL giro de la rueda horizontal

La variable flags nos proporciona la siguiente información:

 EVENT_FLAG_LBUTTON el botón izquierdo está presionado


 EVENT_FLAG_RBUTTON el botón derecho está presionado
 EVENT_FLAG_MBUTTON el botón central está presionado
 EVENT_FLAG_CTRLKEY la tecla Ctrl está presionada
 EVENT_FLAG_SHIFTKEY la tecla Shift está presionada
 EVENT_FLAG_ALTKEY la tecla Alt está presionada

Pintar con el mouse

Para la demostración de la teoría explicada crearemos una aplicación que nos permite pintar
usando los movimiento del mouse, usaremos el trackbar para definir el grosor del pincel.

Para dibujar debemos mantener presionado el botón izquierdo y movernos sobre el área que
deseamos pintar, para hacer esto simplemente dibujamos un circulo del grosor indicado en el
trackbar y la posición definida por el movimiento del mouse.

import cv2
import numpy as np

start = False

def on_trackbar(value):

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 25
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

pass

def on_mouse(event, x, y, flags, param):

global start
pt = (x, y)

if event == cv2.EVENT_LBUTTONDOWN:
start = True
elif event == cv2.EVENT_LBUTTONUP:
start = False
elif start and event == cv2.EVENT_MOUSEMOVE:
ventana = 'Drawing'
grosor = cv2.getTrackbarPos('Grosor', ventana)

cv2.circle(param, pt, grosor, (255, 0, 255), -1)

if __name__ == "__main__":

title = 'Drawing'
image = np.zeros((600, 800, 3), np.uint8)

cv2.namedWindow(title)
cv2.createTrackbar('Grosor', title, 5, 50, on_trackbar)
cv2.setMouseCallback(title, on_mouse, image)

while(1):
cv2.imshow(title, image)
if cv2.waitKey(20) & 0xFF == 27:
break

cv2.destroyAllWindows()

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 26
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Si ejecutamos, el resultado es:

La función que usamos para dibujar es cv2.circle(...) .

Uso del Mouse y Trackbar


Práctica Agregar tres controles más para definir el color del pincel, los tres controles
1.4 corresponden a los canales BGR del color. Reporta el código y las impresiones
de pantalla en el formato de práctica

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 27
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Filtrado y suavizado de imágenes


Filtrado de imágenes. Convolución 2D
Las imágenes pueden ser filtradas por varios tipos de filtros, tales como filtros paso-bajo,
filtros paso-alto, etc.
 Un filtro paso-bajo atenúa las frecuencias altas y mantiene sin variaciones las
frecuencias bajas. El resultado en el dominio espacial es equivalente al de un filtro de
suavizado, donde las altas frecuencias que son filtradas se corresponden con los
cambios fuertes de intensidad. Consigue reducir el ruido suavizando las transiciones
existentes.
 Un filtro paso-alto atenúa las frecuencias bajas manteniendo invariables las frecuencias
altas. Puesto que las altas frecuencias corresponden en las imágenes a cambios bruscos
de densidad, este tipo de filtros es usado en la detección de bordes en el dominio
espacial, ya que estos contienen gran cantidad de dichas frecuencias. Refuerza los
contrastes que se encuentran en la imagen.

El proceso de filtrado puede llevarse a cabo sobre los dominios de frecuencia y/o espacio. De aquí
en adelante nos centraremos en filtros en el dominio del espacio.

Las operaciones espaciales de filtrado se definen en un entorno de vecindad del punto a


transformar (x,y). Para realizar un filtrado en el dominio del espacio se realiza una convolución
(barrido) del kernel sobre la imagen. Para ello se sigue el Teorema de Convolución en el espacio:

g(x,y)=h(x,y)*f(x,y)

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 28
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

La máscara o kernel es una matriz de coeficientes donde:


 El entorno del punto que se considera en la imagen para obtener el resultado final está
determinado por el tamaño y forma de la máscara.
 El tipo de filtrado está determinado por el contenido de la máscara.

OpenCV proporciona la función cv2.filter2D() para realizar la convolución de una imagen con
un kernel determinado. Por ejemplo, un kernel de tamaño 3x3 para un filtro de promedio se puede
definir de la siguiente forma:

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 29
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

El procedimiento de filtrado es el siguiente: para cada píxel de la imagen, una ventana de tamaño
3x3 es centrada en él, realizándose el sumatorio de la multiplicación del kernel por los píxeles
contiguos, dividiéndose entre 9. Esto equivale a realizar la media de los valores de los píxeles de
dentro de la ventana. Esta operación se realiza para cada uno de los píxeles de la imagen.

En cuanto a la función cv2.filter2D(), los parámetros son los siguientes:


 src – input image.
 ddepth – desired depth of the destination image; if it is negative, it will be the same as
src.depth().
 kernel - kernel convolutivo.

Ejemplo 2.1. Filtrado de imagen con un kernel 3x3.


In [ ]:
import cv2
import numpy as np

image_file = 'examples/images/rabbit.jpg'
img = cv2.imread(image_file)

kernel = np.ones((3, 3), np.float32) / 9


dst = cv2.filter2D(src=img, ddepth=-1, kernel=kernel)

# Show
cv2.imshow('Original', img)
cv2.imshow('Filtered', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 30
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Filtrado 2D
Práctica
Descargar una imagen y aplicar un filtrado 2D con un kernel de tamaño 5x5 ponderado.
2.1
Probar a cambiar los distintos valores del kernel.

Suavizado de imágenes
El suavizado de imágenes se logra realizando la convolución de la imagen con un filtro paso-bajo,
y suele utilizarse para la reducción y/o eliminación del ruido, ya que se elimina el contenido de
altas frecuencias. OpenCV proporciona varias técnicas para el suavizado de imágenes. A
continuación veremos varias de ellas.

Promedio
El filtro de la media es el más simple, intuitivo y fácil de implementar para suavizar imágenes. Esta
operación se realiza mediante la convolución de la imagen con un filtro normalizado. Simplemente
calcula la media de los píxeles que están bajo el área del kernel y reemplaza el valor del elemento
central.

En OpenCV, esta operación se realiza mediante la función cv2.blur(). En la llamada, debe


especificarse el tamaño del kernel, tanto el ancho como el alto.

Ejemplo 2.2. Filtrado de imagen: filtro promedio.

import cv2

# Load image
image_path = 'examples/images/sunset.jpg'
image = cv2.imread(image_path)

# Blur
k = 5
blur = cv2.blur(image, (k, k))

# Show
cv2.imshow('Original', image)
cv2.imshow('Filtered', blur)
cv2.waitKey(0)
cv2.destroyAllWindows()

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 31
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Promedio
Práctica
Descargar una imagen con muchos colores. Cambiar el tamaño del kernel y comprobar
2.2
qué ocurre.

En cuanto a las desventajas del filtro promedio o de la media, encontramos que es bastante sensible a
cambios locales. Además, puede crear nuevas intensidades de color que no aparecían en la imagen
original.

Filtro Gaussiano
El filtro gaussiano se usa para emborronar imágenes y eliminar ruido. Es similar al filtro de media
pero se usa una máscara diferente, modelizando la función gaussiana.

Si queremos utilizar un kernel Gaussiano, deberemos utilizar la función cv2.GaussianBlur(). Al


igual que en el caso anterior, debemos especificar el ancho y alto del kernel, que debe ser un

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 32
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

número impar positivo. Además, también debe especificarse la desviación estándar en las
direcciones X e Y, a través de los parámetros sigmaX y sigmaY respectivamente. Si sólo se
especifica el valor para el parámetro sigmaX, la función asigna el mismo valor para el
parámetro sigmaY.

Ejemplo 8. Filtrado de imagen: filtro Gaussiano.

import cv2

# Load image
image_path = 'examples/images/sunset.jpg'
image = cv2.imread(image_path)

# Gaussian blur
k = 5
sigma = 0
blur = cv2.GaussianBlur(image, (k, k), sigma)

# Show
cv2.imshow('Original', image)
cv2.imshow('Filtered', blur)
cv2.waitKey(0)
cv2.destroyAllWindows()

Práctica Gaussiano
2.3 Cambiar el tamaño del kernel y el valor del parámetro sigma y comprobar qué ocurre.

Una de las razones por las que los filtros de tipo Gaussiano son tan importantes es que son muy
efectivos para eliminar ruido Gaussiano de la imagen. Este filtro produce un suavizado más uniforme
que el filtro promedio.

Ejemplo 9. Filtrado de imagen: filtro Gaussiano sobre imagen con mucho ruido.

import cv2

# Load image
image_path = 'images/taj-noise.jpg'
image = cv2.imread(image_path)

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 33
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

# Gaussian blur
k = 5
sigma = 1
blur = cv2.GaussianBlur(image, (k, k), sigma)

# Show
cv2.imshow('Original with noise', image)
cv2.imshow('Filtered', blur)
cv2.waitKey(0)
cv2.destroyAllWindows()

Práctica Gaussiano con Ruido


2.4 Buscar una imagen con ruido y aplicar filtro Gaussiano para reducir el nivel de ruido.

Mediana
El filtro mediana se aplica mediante la función cv2.medianBlur(). En él, se calcula la mediana de
todos los píxeles que están bajo el área del kernel, y el elemento central se sustituye por el valor
de la mediana. El valor para el tamaño del kernel debe ser un número impar positivo.

Este filtro es muy efectivo para eliminar el ruido impulsional, llamado "sal y pimienta".
 https://en.wikipedia.org/wiki/Salt-and-pepper_noise

Ejemplo. Filtrado de imagen: filtro mediana sobre imagen con ruido de tipo "sal y pimienta".

import cv2
# Load image
image_path = 'examples/images/salt_pepper_noise.png'
image = cv2.imread(image_path)
# Gaussian blur
k = 5
blur = cv2.medianBlur(image, k)
# Show
cv2.imshow('Original', image)
cv2.imshow('Filtered', blur)
cv2.waitKey(0)
cv2.destroyAllWindows()

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 34
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Ruido Sal yPiminta


Práctica
Buscar una imagen con ruido impulsional ("sal y pimienta") y aplicar el filtro mediana para
2.5
reducir el nivel de ruido.

Gradientes
En este apartado vamos a mostrar varios filtros paso-alto que nos permitirán filtrar las imágenes
para extraer bordes y gradientes.

Sobel
El operador Sobel, también conocido como el operador Sobel–Feldman, realiza un gradiente
espacial 2D sobre una imagen y de esta forma enfatiza las regiones con altas frecuencias
espaciales, que se corresponden con bordes.

El operador Sobel calcula el gradiente de la intensidad de una imagen en cada punto (píxel). Así,
para cada punto, este operador da la magnitud del mayor cambio posible, la dirección de éste y el
sentido desde oscuro a claro. El resultado muestra cómo de abruptamente o suavemente cambia
una imagen en cada punto analizado y, en consecuencia, cuán probable es que éste represente un
borde en la imagen y, también, la orientación a la que tiende ese borde. En la práctica, el cálculo
de la magnitud -probabilidad de un borde- es más fiable y sencillo de interpretar que el cálculo de
la dirección y sentido.

El operador utiliza dos máscaras o kernels de tamaño 3x3 los cuales son convolucionados con la
imagen original para calcular aproximaciones de las derivativas, una para cambios en el eje
horizontal y otra para cambios en el eje vertical.

Kernels de convolución Sobel: Estos kernels están diseñados para responder ante ejes
verticales y horizontales. Pueden ser aplicados de forma separada a la imagen de entrada para
producir mediciones separadas, o por el contrario, pueden ser combinados para encontrar y
delimitar ejes en ambas direcciones.

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 35
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

La función disponible en OpenCV que realiza este filtrado es cv2.Sobel(). Se puede especificar la
dirección de los gradientes, vertical u horizontal, mediante los
argumentos xorder/dx e yorder/dy respectivamente. Además, también se puede especificar el
tamaño del kernel mediante el argumento ksize.

Ejemplo. Filtros de Sobel.

import cv2
import numpy as np

# Load image
image = cv2.imread('examples/images/sudoku.jpg', cv2.IMREAD_GRAYSCALE)

# Sobel
k = 3
sobelx = cv2.Sobel(image, ddepth=cv2.CV_64F, dx=1, dy=0, ksize=k)
sobely = cv2.Sobel(image, ddepth=cv2.CV_64F, dx=0, dy=1, ksize=k)

# Show
cv2.imshow('Original', image)
cv2.imshow('Sobel X', sobelx)
cv2.imshow('Sobel Y', sobely)
cv2.waitKey(0)
cv2.destroyAllWindows()

Laplacian
El operador Laplacian es una medida isotrópica 2D de la segunda derivada espacial de una
imagen. Aplicar un filtro Laplacian sobre una imagen consigue resaltar las regiones en las que se
producen cambios bruscos de intensidad, y es por tanto utilizada para detección de bordes.
Normalmente, el filtro Laplacian es aplicado sobre una imagen que ha sido previamente filtrada
con un filtro Gaussiano para poder reducir la sensibilidad ante ruido.

La función que proporciona OpenCV para aplicar un filtro Laplacian es cv2.Laplacian(). Los
argumentos obligatorios son la imagen de entrada y la profundidad de la imagen de salida.

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 36
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Ruido Sal yPiminta


Práctica Buscar una imagen (con ruido) de edificios y aplicar el filtro Laplacian sobre la
2.6 imagen sin filtrar y sobre la imagen filtrada
(http://docs.opencv.org/3.1.0/d5/d0f/tutorial_py_gradients.html)

Canny edge detector


El algoritmo de Canny es un método desarrollado por John F. Canny en 1986 que utiliza un
algoritmo de múltiples etapas para detectar una amplia gama de bordes en imágenes.

Las etapas del algoritmo son las siguientes:


1. Reducción de ruido. Debido a que la detección de bordes puede verse afectada por el
ruido que contenga la imagen, el primer paso es la eliminación del ruido en la imagen
mediante un filtro Gaussiano con un kernel de tamaño 5x5.
2. Búsqueda de gradientes de intensidad. El borde de una imagen puede apuntar a
diferentes direcciones, por lo que el algoritmo de Canny utiliza cuatro filtros para detectar
los bordes en las direcciones horizontal, vertical y diagonales.
3. Supresión de no máximos. Después de obtener las magnitudes de gradiente y
dirección, se realiza un análisis de toda la imagen para eliminar los píxeles no deseados
que no constituyan ningún eje. Para ello, cada píxel es examinado comprobando si es un
máximo local en su vecindario en la dirección del gradiente. Si el píxel no es un máximo
local, se establece a cero. En resumen, el resultado que se obtiene es una imagen
binaria con "ejes estrechos".

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 37
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

4. Umbrales. En esta última etapa del algoritmo, se decide sobre todos los ejes obtenidos
cuáles de ellos son realmente ejes y cuáles de ellos no. Para ello, se establecen dos
valores umbral, minVal y maxVal. Todos los ejes con una intensidad de gradiente mayor
que el valor umbral maxVal se consideran de forma segura como ejes. Todos los ejes
con una intensidad de gradiente menor que el valor umbral minVal se consideran de
forma segura como no ejes, y por tanto, son descartados. Aquellos que se encuentran
entre los valores minVal y maxVal son clasificados dependiendo de su conexión. Si están
conectados a los píxeles con valor mayor a maxVal son considerados parte de los ejes.
En cualquier otro caso son descartados.

5.

OpenCV proporciona la implementación del detector de bordes Canny mediante la


función cv2.Canny(). El primer argumento de la función es la imagen. El segundo y el tercer
argumento son los valores de los parámetros minVal y maxVal respectivamente. El cuarto
argumento es el valor para establecer el tamaño del kernel del filtro Sobel (por defecto tiene
asignado el valor 3).

Ejemplo . Detector de bordes Canny a través de la webcam.

import cv2
import numpy as np

webcam_id = 0
cap = cv2.VideoCapture(webcam_id)

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 38
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

# Cany edge detector thresholds


threshold_one = 50
threshold_two = 150
aperture_size = 3

while(cap.isOpened()):
# Capture frame-by-frame
ret, frame = cap.read()
if ret == True:
# Operations on the frame
edges = cv2.Canny(frame, threshold_one, threshold_two, aperture_size)

# Display
cv2.imshow("Original", frame)
cv2.imshow("Canny edge detection", edges)

# Exit?
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break

# Release everything if job is finished


cap.release()
cv2.destroyAllWindows()

Práctica Ruido Sal yPimienta


2.7 Buscar una imagen aérea de una ciudad y aplicar el filtro Canny.

Histogramas
Un histograma es un gráfico que nos da una idea general sobre la distribución de la intensidad de
una imagen. Generalmente, es un gráfico en el que en el eje X se establece el rango [0, 255] y en
el eje Y se muestra la cantidad de píxeles con dicha intensidad.

Es otra forma de entender una imagen. Mirando el histograma de una imagen, podemos intuir el
contraste, el brillo y la distribución de la intensidad de una imagen.

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 39
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Dentro de los parámetros básicos de un histograma, destacan los siguientes:


 BINS. Establece el rango de valores que son mostrados en el eje X. Normalmente
mostraremos 256 valores (de 0 a 255), pero podría darse el caso que quisiéramos
agrupar las intensidades. Por ejemplo, podríamos mostrar los valores de 0 a 15, de 16 a
31, ..., de 240 a 255. De esta forma sólo tendríamos 16 valores que representar en el
histograma.
 DIMS. Número de dimensiones. Es el número de parámetros para los cuales se hace el
cálculo. En este caso la dimensión será 1 ya que únicamente estamos calculando la
intensidad.
 RANGO. Es el rango de intensidades que se desea medir. Normalmente será [0, 255],
es decir, todo el rango de valores.
OpenCV proporciona la función cv2.calcHist para calcular el histograma de una imagen. Esta
función tiene los siguientes parámetros:
 images. Imagen fuente. El parámetro es una lista de imágenes.
 channels. Índice del canal sobre el cual se desea calcular el histograma.
 mask. Máscara de imagen. Si se desea calcular el histograma de la imagen completa,
deberá establecerse a None.
 histSize. Representa el contador BIN. También es una lista. En nuestro caso,
utilizaremos [256].
 ranges. Este es el RANGO. Normalmente, utilizaremos [0, 255].

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 40
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Ejemplo. Calcular el histograma sobre una imagen en escala de grises y mostrar el gráfico.

import cv2
import numpy as np
from matplotlib import pyplot as plt

# Load
image_path = 'examples/images/rabbit.jpg'
image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)

# Show image
cv2.imshow('Image', image)
cv2.waitKey(0)

# Histogram
hist = cv2.calcHist([image], channels=[0], mask=None, histSize=[256], ranges=[0,
255])

# Plot
plt.plot(hist)
plt.xlim([0, 255])
plt.show()

cv2.destroyAllWindows()

Ruido Sal yPimienta


Práctica
Mostrar en un único gráfico los 3 histogramas de la imagen anterior para cada uno de los
2.8
canáles de color RGB.

Gráfico con Matplotlib


La librería Matplotlib también posee una función para mostrar
histogramas: matplotlib.pyplot.hist(). La propia función directamente calcula el histograma y lo
genera. Por tanto, no es necesario hacer uso de la función cv2.calcHist() de OpenCV.

Nota: el algoritmo de OpenCV está más optimizado y es más rápido.


Ejemplo. Cálculo y generación de histograma mediante la función matplotlib.pyplot.hist().

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 41
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

import cv2
from matplotlib import pyplot as plt

# Load
image_path = 'examples/images/rabbit.jpg'
image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)

# Histogram & plot


plt.hist(image.ravel(), 256, [0, 255]);
plt.xlim([0, 255])
plt.show()

Template matching
Template matching es un método de procesamiento digital de imágenes para buscar y encontrar la
localización/posición de una imagen template dentro de otra imagen. Es una técnica para
encontrar pequeñas partes de una imagen que se ajusten a una imagen template.

OpenCV viene con una función para este propósito: cv2.matchTemplate. De forma resumida, el
algoritmo símplemente desliza la imagen template sobre la imagen general, como si se tratara de
una convolución 2D, y compara la plantilla con esa zona de la imagen. El resultado es una imagen
en escala de grises donde cada píxel denota cuánto se aproxima a la imagen templateatendiendo
a su vecindario. Mediante la función cv2.minMaxLoc() se puede buscar posteriormente dónde
está el máximo/mínimo para poder localizar la imagen.

En OpenCV existen varios métodos de comparación:

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 42
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

 http://docs.opencv.org/3.1.0/df/dfb/group__imgproc__object.html#ga3a7850640f1fe1f58fe91a
2d7583695d

Ejemplo. Detección y localización de la señal de la imagen mediante template matching.

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('examples/images/hobbiton.jpg', 0)
img2 = img.copy()
template = cv2.imread('examples/images/template.png', 0)
w, h = template.shape[::-1]

# All the 6 methods for comparison in a list


methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
'cv2.TM_CCORR_NORMED','cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']

for meth in methods:


img = img2.copy()
method = eval(meth)

# Apply template Matching


res = cv2.matchTemplate(img,template,method)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

# If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum


if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)

cv2.rectangle(img, top_left, bottom_right, 255, 2)

plt.subplot(121),plt.imshow(res,cmap = 'gray')
plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img,cmap = 'gray')

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 43
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

plt.title('Detected Point'), plt.xticks([]), plt.yticks([])


plt.suptitle(meth)
plt.show()

Ruido Sal yPimienta


Práctica
Descargar una imagen en la que se esté practicando algún deporte, recortar la cara de la
3.1
jugadora o del jugador, y localizar esa cara en la imagen.

Detección de caras
La detección de objetos mediante el uso de clasificadores en cascada basados en la extracción de
características con filtros de base Haar, es un método efectivo de detección de objetos propuesto
por Paul Viola y Michael Jones en 2001. Es un método basado en las técnicas de aprendizaje
automático donde una función cascada es entrenada mediante una gran cantidad de imágenes
positivas y negativas, posibilitando la detección de objetos en otras imágenes. Las imágenes
deben tener un tamaño prefijado.

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 44
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Primero, un clasificador es entrenado con unos pocos cientos de ejemplos de un objeto en


particular, en este caso caras, llamados ejemplos positivos. Además, también es entrenado con
imágenes arbitrarias del mismo tamaño, llamadas ejemplos negativos.

Tras ser entrenado el clasificador, puede ser aplicado a una región de interés en una imagen de
entrada. El clasificador generará como salida "1" si la región es como el objeto buscado o "0" en
otro caso. Para buscar el objeto en la imagen completa, la ventana de búsqueda se moverá a
traves de la imagen. Además, el clasificador está diseñado para poder cambiar su tamaño, para
buscar objetos de diferentes tamaños.

Se denomina "en cascada" porque el clasificador está formado por varios clasificadores simples en
diferentes etapas, los cuales son aplicados de forma sucesiva hasta que en una etapa se rechaza
o por el contrario se avanza hasta el final.

OpenCV viene tanto con un entrenador como con un detector. Si se desea entrenar un clasificador
propio para cualquier tipo de objeto (trenes, coches, perros, etc.), se puede utilizar OpenCV para
crearlo. Además, OpenCV también viene muchos clasificadores previamente entrenados para
caras, ojos, sonrisas, etc. Esos ficheros se encuentran almacenados en la siguiente ruta:

 opencv/data/haarcascades/

Las funciones que proporciona OpenCV son las siguientes:


 cv2.CascadeClassifier()
 cv2.detectMultiScale()

Ejemplo Detección de caras Haar-cascade a través de la webcam.

import cv2
import sys

# Load XML classifieres


cas_path = 'examples/haarcascade/haarcascade_frontalface_default.xml'
face_cascade = cv2.CascadeClassifier(cas_path)

# Webcam
webcam_id = 0
video_capture = cv2.VideoCapture(webcam_id)

# Detect multi-scale flags


if cv2.__version__.startswith('2.4'):

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 45
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

dmf_flag = cv2.cv.CV_HAAR_SCALE_IMAGE
else:
dmf_flag = cv2.CASCADE_SCALE_IMAGE

while True:
# Capture frame-by-frame
ret, frame = video_capture.read()

# Gray image
gray_image = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# Detect faces
faces = face_cascade.detectMultiScale(
gray_image,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30),
flags=dmf_flag
)

# Draw a rectangle around the faces


for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)

# Display the resulting frame


cv2.imshow('Video', frame)

if cv2.waitKey(1) & 0xFF == ord('q'):


break

# When everything is done, release the capture


video_capture.release()
cv2.destroyAllWindows()

Ejemplo. Detección de caras y ojos a través de la webcam.


In [ ]:
import cv2
import sys

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 46
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

# Load XML classifieres


cas_path = 'examples/haarcascade/haarcascade_frontalface_default.xml'
eye_path = 'examples/haarcascade/haarcascade_eye.xml'
face_cascade = cv2.CascadeClassifier(cas_path)
eye_cascade = cv2.CascadeClassifier(eye_path)

# Webcam
webcam_id = 0
video_capture = cv2.VideoCapture(webcam_id)

# Detect multi-scale flags


if cv2.__version__.startswith('2.4'):
dmf_flag = cv2.cv.CV_HAAR_SCALE_IMAGE
else:
dmf_flag = cv2.CASCADE_SCALE_IMAGE

while True:
# Capture frame-by-frame
ret, frame = video_capture.read()

# Gray image
gray_image = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# Detect faces
faces = face_cascade.detectMultiScale(
gray_image,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30),
flags=dmf_flag
)

# Draw a rectangle around the faces


for (x, y, w, h) in faces:
cv2.rectangle(frame, (x,y), (x+w,y+h), (255,0,0), 2)

# Detect eyes
roi_gray = frame[y:y+h, x:x+w]

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 47
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

roi_color = frame[y:y+h, x:x+w]


eyes = eye_cascade.detectMultiScale(roi_gray)

# Draw a rectangle around the eyes


for (ex,ey,ew,eh) in eyes:
cv2.rectangle(roi_color, (ex,ey), (ex+ew,ey+eh), (0,255,0), 2)

# Display the resulting frame


cv2.imshow('Video', frame)

if cv2.waitKey(1) & 0xFF == ord('q'):


break

# When everything is done, release the capture


video_capture.release()
cv2.destroyAllWindows()

Reconocimiento de caras
Práctica
Realizar un programa que identifique caras en una imagen donde al menos aparezcan 8
3.1
personas

Práctica Reconocimiento de sonrisas


3.2 Realizar un programa que identifique sonrisas a través de la webcam y en una imagen

Colores y espacios de color


En OpenCV hay más de 150 métodos de conversión distintos entre espacios de colores. Hasta
ahora, ya hemos aprendido a convertir imágenes RGB en escala de grises. Ahora vamos a
aprender a convertir imágenes al espacio de color HSV (del inglés Hue, Saturation, Value – Matiz,
Saturación, Valor).

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 48
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Espacio de color RGB

Espacio de color HSV

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 49
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Para la conversión del espacio de color, debemos utilizar la función cv2.cvtColor(input_image,


flag), donde el flag indica el tipo de conversión a realizar. El flag para convertir de RGB a HSV
es *cv2.COLOR_BGR2GRAY.

Seguimiento de objetos
Ahora que conocemos cómo convertir una imagen RGB a HSV, ya estamos en disposición de
extraer objetos de un determinado color. En HSV, es más fácil representar un color que en el
espacio de color RGB. El método para la extracción de objetos de un cierto color es el siguiente:
 Obtención de cada frame del vídeo
 Conversión del espacio de color: de RGB a HSV
 Creación de una máscara de color
 Extracción de la imagen aquellos objetos del color definido

Ejemplo. Filtrado de colores.


import cv2
import numpy as np

# Webcam
webcam_id = 0
cap = cv2.VideoCapture(webcam_id)

while True:
_, frame = cap.read()

# Convert BGR to HSV


hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

# Define range in HSV


lower_color = np.array([85, 50, 50])
upper_color = np.array([145, 255, 255])

# Mask: threshold the HSV image to get only defined colors


mask = cv2.inRange(hsv, lower_color, upper_color)

# Bitwise-AND mask and original image


res = cv2.bitwise_and(frame, frame, mask=mask)

# Show

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 50
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

cv2.imshow('Frame', frame)
cv2.imshow('Mask', mask)
cv2.imshow('Color', res)

# Exit?
if cv2.waitKey(1) & 0xFF == ord('q'):
break

cv2.destroyAllWindows()
cap.release()
Filtrado de colores
Práctica
Descargar un vídeo y filtrar los objetos de un color determinado
3.3
(https://videos.pexels.com/video-license).

Detección y extracción de características (feature


detection)

Features
La mayoría de nosotros alguna vez ha jugado a montar puzles. En ellos, partiendo de un gran
número de pequeñas piezas de una imagen, se debe reconstruir la imagen original la cual tiene un
tamaño mayor. La pregunta es ¿cómo eres capaz de resolverlo?

La respuesta está en la búsqueda de patrones específicos o características específicas que sean


únicas, que puedan ser fácilmente rastreadas y comparadas. Si buscamos una definición para
definir qué es una característica, encontraremos que es una tarea difícil de expresar en palabras,
pero en el fondo sabemos qué son. Si alguien nos pregunta que le señalemos una buena
característica para que pueda ser comparada entre varias imágenes, seguramente seremos

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 51
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

capaces de señalarla. Esta es la razón por la cual los niños pequeños pueden simplemente jugar a
montar puzles.

No existe una definición universal o exacta de qué constituye una característica, y la definición
concreta a menudo depende del problema o del tipo de aplicación que se esté analizando. Dicho
esto, una característica es definida como una parte interesante de una imagen, y suelen utilizarse
como punto de partida para muchos algoritmos de visión por computador. Por tanto, al ser el punto
de partida, la calidad global del algoritmo dependerá de lo bueno que sea su detector de
características. Consecuentemente, la propiedad deseable para cualquier detector de
características es la repetibilidad/reproducibilidad, es decir, si es capaz o no de detectar la misma
características en dos o más imágenes diferentes de la misma escena.

El proceso de detección y extracción de características es una operación a bajo nivel y


ocasionalmente puede ser computacionalmente costosa.

En la parte superior de la imagen anterior se muestran 6 pequeñas imágenes. Intenta buscar y


localizar la posición de esas imágenes.
 Como se puede observar, las imágenes A y B están repartidas por gran parte de la
imagen. Es difícil encontrar la localización exacta de esas imágenes.

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 52
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

 Las imágenes C y D son mucho más simples, ya que son bordes del edificio y es más
fácil encontrar una posición aproximada, pero la posición exacta sigue siendo difícil de
determinar. Esto es porque el patrón es el mismo a lo largo de todo el borde.
 Finalmente, las imágenes E y F son diferentes esquinas del edificio y como se observa,
es fácil determinar su posición. Por tanto, pueden ser consideradas como
buenas features.

Harris corner detection


Como ya sabemos, las esquinas son regiones en la imagen con una gran variación en la
intensidad en todas las direcciones. Una de las primeras aproximaciones para
encontrar corners fue propuesta por Chris Harris y Mike Stephens en su publicación "A Combined
Corner and Edge Detector" en 1988. Por tanto, hoy en día se le conoce como Harris Corner
Detector.

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 53
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

OpenCV proporciona la función cv2.cornerHarris() para la localización de esquinas mediante el


algoritmo propuesto por Chris Harris y Mike Stephens. Los argumentos de la función son los
siguientes:
 img - Imagen de entrada. Debe ser una imagen en escala de grises y de tipo float32.
 blockSize - Es el tamaño de la vecindad considerada para la detección de esquinas.
 ksize - Parámetro de apertura del filtro de Sobel.
 k - Parámetro libre de la ecuación de Harris.

Ejemplo. Detección de esquinas mediante el método de Harris.

import cv2
import numpy as np

filename = 'images/taj-noise.jpg'
img = cv2.imread(filename)

# RGB -> Grayscale


gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Input image should be grayscale and float32 type


gray = np.float32(gray)

# Corner detection
dst = cv2.cornerHarris(gray, blockSize=2, ksize=3, k=0.04)

# Threshold for an optimal value, it may vary depending on the image.


img[dst>0.01*dst.max()]=[0,0,255]

# Show
cv2.imshow('dst', img)

# Exit?
if cv2.waitKey(0) & 0xFF == ord('q'):
cv2.destroyAllWindows()

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 54
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Harris
Práctica
Descargar una imagen con un abundante número de corners y aplicar el algoritmo de
4.1
Harris.

ORB (Oriented FAST and Rotated BRIEF)


ORB es un algoritmo creado en los "laboratorios de OpenCV", publicado en 2011 por Ethan
Rublee, Vincent Rabaud, Kurt Konolige y Gary R. Bradski en el artículo "An efficient alternative to
SIFT or SURF". Como indica el título del artículo, es una alternativa a los
algoritmos SIFT y SURF de uso libre, ya que al estar patentados esos algoritmos, para utilizarlos
hay que pagar un canon.
 SIFT: http://docs.opencv.org/3.2.0/da/df5/tutorial_py_sift_intro.html
 SURF: http://docs.opencv.org/3.2.0/df/dd2/tutorial_py_surf_intro.html
De forma resumida, podemos decir que ORB es una fusión del detector de esquinas FAST y el
algoritmo BRIEF, con ciertas modificaciones, que también hace uso de detector de esquinas de
Harris.
 FAST: http://docs.opencv.org/3.2.0/df/d0c/tutorial_py_fast.html
 BRIEF: http://docs.opencv.org/3.2.0/dc/d7d/tutorial_py_brief.html

Para crear un objeto de tipo ORB, OpenCV proporciona la función cv2.ORB(). Una vez creado,
para detectar los keypoints y descriptors tendremos que utilizar el
método orb.detectAndCompute(). Toda la información viene descrita en el siguiente enlace:
 http://docs.opencv.org/3.1.0/d1/d89/tutorial_py_orb.html
Ejemplo. Uso del algoritmo ORB para la detección de esquinas sobre una fotografía del castillo de
Bratislava.

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 55
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

In [ ]:
import numpy as np
import cv2
from matplotlib import pyplot as plt

# Load image
path = 'examples/images/bratislava_castle.jpg'
img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)

# Initiate ORB detector


if cv2.__version__.startswith('2.4'):
orb = cv2.ORB()
else:
orb = cv2.ORB_create()

# Find the keypoints and descriptors with ORB


kp, des = orb.detectAndCompute(img, None)

# Draw only keypoints location, not size and orientation


img2 = cv2.drawKeypoints(img, kp, None, color=(0, 255, 0), flags=0)
cv2.imshow('Keypoints', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

Práctica ORB
4.2 Aplicar el algoritmo ORB sobre la imagen descargada para el ejercicio anterior.

ORB II
Práctica
Aplicar los algoritmos ORB, SIFT y FAST y comparar visualmente los resultados que se
4.3
obtienen.

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 56
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Correspondencia entre características (Feature Matching)


A continuación describiremos la técnica de búsqueda de correspondencia entre características de
diferentes imágenes Brute-Force matcher. El proceso es simple: se selecciona el descriptor de una
característica en el primer conjunto y se compara con todas las características del segundo
conjunto mediante un cálculo de distancias, devolviendo la característica que más se le aproxime.

En OpenCV, primero debemos crear el objeto BFMatcher mediante la función cv2.BFMatcher(). El


método tiene dos parámetros: normType (método de cálculo de distancias)
y crossCheck (devuelve los descriptores de ambos conjuntos). Una vez creado, el
método BFMatcher.match() devolverá la mejor correspondencia. Por último, el
método cv2.drawMatches() nos ayudará a dibujar las correspondencias, poniendo las dos
imágenes juntas de forma horizontal y dibujando líneas entre las dos imágenes con las mejores
correspondencias.

El resultado del método match es una lista de objetos de tipo DMatch. Este objeto tiene los
siguientes atributos:
 DMatch.distance - Distancia entre descriptores. Mejor cuanto menor sea.
 DMatch.trainIdx - Índice del descriptor en la imagen train.
 DMatch.queryIdx - Índice del descriptor en la imagen query
 DMatch.imgIdx - Índice de la imágen train.

Ejemplo. Correspondencia de características entre dos imágenes, mediante el método Brute-


Force matcher.

import numpy as np
import cv2
import matplotlib.pyplot as plt

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 57
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

def drawMatches(img1, kp1, img2, kp2, matches):


"""
My own implementation of cv2.drawMatches as OpenCV 2.4.9
does not have this function available but it's supported in
OpenCV 3.0.0

This function takes in two images with their associated


keypoints, as well as a list of DMatch data structure (matches)
that contains which keypoints matched in which images.

An image will be produced where a montage is shown with


the first image followed by the second image beside it.

Keypoints are delineated with circles, while lines are connected


between matching keypoints.

img1,img2 - Grayscale images


kp1,kp2 - Detected list of keypoints through any of the OpenCV keypoint
detection algorithms
matches - A list of matches of corresponding keypoints through any
OpenCV keypoint matching algorithm
"""

# Create a new output image that concatenates the two images together
# (a.k.a) a montage
rows1 = img1.shape[0]
cols1 = img1.shape[1]
rows2 = img2.shape[0]
cols2 = img2.shape[1]

out = np.zeros((max([rows1,rows2]),cols1+cols2,3), dtype='uint8')

# Place the first image to the left


out[:rows1,:cols1] = np.dstack([img1, img1, img1])

# Place the next image to the right of it


out[:rows2,cols1:] = np.dstack([img2, img2, img2])

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 58
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

# For each pair of points we have between both images


# draw circles, then connect a line between them
for mat in matches:

# Get the matching keypoints for each of the images


img1_idx = mat.queryIdx
img2_idx = mat.trainIdx

# x - columns
# y - rows
(x1,y1) = kp1[img1_idx].pt
(x2,y2) = kp2[img2_idx].pt

# Draw a small circle at both co-ordinates


# radius 4
# colour blue
# thickness = 1
cv2.circle(out, (int(x1),int(y1)), 4, (255, 0, 0), 1)
cv2.circle(out, (int(x2)+cols1,int(y2)), 4, (255, 0, 0), 1)

# Draw a line in between the two points


# thickness = 1
# colour blue
cv2.line(out, (int(x1),int(y1)), (int(x2)+cols1,int(y2)), (255, 0, 0), 1
)

# Show the image


cv2.imshow('Matched Features', out)
cv2.waitKey(0)
cv2.destroyWindow('Matched Features')

# Also return the image if you'd like a copy


return out

# Query image
img1 = cv2.imread('examples/images/r2d2.jpg', 0)
# Train image

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 59
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

img2 = cv2.imread('examples/images/starwars.jpg', 0)

# Initiate ORB detector


if cv2.__version__.startswith('2.4'):
orb = cv2.ORB()
else:
orb = cv2.ORB_create()

# Find the keypoints and descriptors with ORB


kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

# create BFMatcher object


bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

# Match descriptors.
matches = bf.match(des1, des2)

# Sort them in ascending order of their distances so that best


# matches (with low distance) come to front
matches = sorted(matches, key = lambda x:x.distance)

# Then we draw only first 10 matches (Just for sake of visibility


drawMatches(img1, kp1, img2, kp2, matches[:10])

Feature Matching
Práctica
Descargar un par de fotos de internet en la que la imagen query aparezca dentro de la
4.4
imagen train. Aplicar el algoritmo Brute-Force matcher.

Aprendizaje automático
k-Nearest Neighbour
El método kNN (k-nearest neighbour o k-vecinos más cercanos) es uno de los algoritmos de
clasificación más simples dentro de los métodos de clasificación supervisada. Este es un método
de clasificación no paramétrico, que estima el valor de la función de densidad de probabilidad o

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 60
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

directamente la probabilidad a posteriori de que un elemento pertenezca a la clase a


partir de la información proporcionada por el conjunto de prototipos.

En la imagen, vemos dos tipos de objetos, los cuadrados azules y los triángulos rojos. A cada tipo
de objeto distinto lo llamamos clase. Los objetos son mostrados en un plano al que
llamaremos feature space.

Ahora imaginemos que queremos clasificar un nuevo objeto (círculo verde), teniendo que elegir si
pertenece al grupo de objetos azules o rojos. A este proceso lo llamamos clasificación. El algoritmo
va a intentar clasificar al objeto nuevo dependiendo de cuáles sean los vecinos más cercanos, que
dependerá del parámetro k. En cuanto a la elección de este parámetro, dependerá
fundamentalmente de los datos; generalmente, valores grandes de k reducen el efecto de ruido en
la clasificación, pero crean límites entre clases parecidas.

El método kNN está disponible en OpenCV. Lo primero que tenemos que hacer es obtener una
instancia mediante el método knn = cv2.KNearest(). Tras esto, deberemos realizar el proceso de
entrenamiento mediante el método knn.train(). Por último, para realizar el proceso de clasificación
haremos uso del método knn.find_nearest().

Ejemplo. Ejemplo de clasificación mediante el algoritmo k-nearest neighbour (kNN).

import cv2
import numpy as np
import matplotlib.pyplot as plt

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 61
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

# Feature set containing (x,y) values of 25 known/training data


trainData = np.random.randint(0, 100, (25, 2)).astype(np.float32)

# Labels each one either Red or Blue with numbers 0 and 1


responses = np.random.randint(0, 2, (25, 1)).astype(np.float32)

# Take Red families and plot them


red = trainData[responses.ravel()==0]
plt.scatter(red[:,0], red[:,1], 80, 'r', '^')

# Take Blue families and plot them


blue = trainData[responses.ravel()==1]
plt.scatter(blue[:,0], blue[:,1], 80, 'b', 's')

# New object
newcomer = np.random.randint(0, 100, (1, 2)).astype(np.float32)
plt.scatter(newcomer[:,0], newcomer[:,1], 80, 'g', 'o')

# Classification
k = 5
if cv2.__version__.startswith('2.4'):
knn = cv2.KNearest()
knn.train(trainData, responses)
ret, results, neighbours, dist = knn.find_nearest(newcomer, k)
else:
knn = cv2.ml.KNearest_create()
knn.train(trainData, cv2.ml.ROW_SAMPLE, responses)
ret, results, neighbours, dist = knn.findNearest(newcomer, k)

print("result: " + str(results))


print("neighbours: " + str(neighbours))
print("distance: " + str(neighbours))

plt.show()

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 62
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

K-means
El algoritmo de las K-medias (K-means en inglés), presentado por MacQueen en 1967, es uno de
los algoritmos de aprendizaje no supervisado más simples para resolver el problema de la
clusterización. El procedimiento aproxima por etapas sucesivas un cierto número (prefijado) de
clusters haciendo uso de los centroides de los puntos que deben representar.
¿Cómo funciona?

Considera el conjunto de datos de la siguiente imagen. Se requiere clasificar estos datos en dos
grupos diferentes.

En el primer paso, el algoritmo escoge dos centroides. Tras esto, en el segundo paso, el
algoritmo calculará la distancia desde cada punto a cada uno de los centroides. Si uno de los datos
está más cerca, entonces ese dato se le asignará la etiqueta del centroide. Si por el contrario está
más cerca del centroide , en ese caso se le asignará la etiqueta del centroide .

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 63
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

En el tercer paso del algoritmo, para cada uno de los centroides, se realiza el cálculo de la media
de todos los puntos asignados a ese centroide, siendo ésta la nueva posición a la que se
desplazará el centroide (centro de masas).

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 64
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Por último, los pasos dos y tres serán iterados hasta que todos los centroides converjan a puntos
fijos. Además, también pueden aplicarse otros criterios de parada, como son el número máximo de
iteraciones o la obtención de una precisión determinada.

El resultado final sería el siguiente:

OpenCV proporciona la función cv2.kmeans() para la clusterización de datos mediante el


algoritmo de las K-medias.

Los parámetros de entrada del algoritmo son los siguientes:


 samples: datos de entrada (tipo de dato np.float32).
 nclusters: número de clusters requeridos al final de la ejecución.
 criteria: criterio de parada.
 attempts: número de veces que el algoritmo es ejecutado utilizando diferentes
inicializaciones.
 flags: indica cómo son los centroides elegidos al inicio.

Los parámetros de salida del algoritmo son los siguientes:


 compactness: suma de la distancia cuadrática desde cada punto hasta su
correspondiente centroide.
 labels: array con las etiquetas.
 centers: array de centroides de los clusters.

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 65
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

Ejemplo 23. El problema de la talla de camiseta


(http://docs.opencv.org/3.1.0/de/d4d/tutorial_py_kmeans_understanding.html y http://docs.opencv.o
rg/3.1.0/d1/d5c/tutorial_py_kmeans_opencv.html).

import numpy as np
import cv2
from matplotlib import pyplot as plt

X = np.random.randint(25, 53, (25, 2))


Y = np.random.randint(57, 85, (25, 2))
Z = np.vstack((X,Y))

# Convert to np.float32
Z = np.float32(Z)

# Define criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)

# Define number of cluters


K = 2

# Attempts
attempts = 10

# Apply kmeans
if cv2.__version__.startswith('2.4'):
ret, label, center = cv2.kmeans(Z, K, criteria, attempts, cv2.KMEANS_RANDOM_
CENTERS)
else:
ret, label, center = cv2.kmeans(Z, K, None, criteria, attempts, cv2.KMEANS_R
ANDOM_CENTERS)

# Now separate the data, Note the flatten()


A = Z[label.ravel() == 0]
B = Z[label.ravel() == 1]

# Plot the data


plt.figure(1)

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 66
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

plt.subplot(211)
plt.scatter(A[:,0], A[:,1], c = 'gray')
plt.scatter(B[:,0], B[:,1], c = 'gray')
plt.xlabel('Height')
plt.ylabel('Weight')

plt.subplot(212)
plt.scatter(A[:,0], A[:,1])
plt.scatter(B[:,0], B[:,1], c = 'r')
plt.scatter(center[:,0], center[:,1], s = 80, c = 'y', marker = 's')
plt.xlabel('Height')
plt.ylabel('Weight')
plt.show()

Color Quantization

En el campo de gráficos por computador o visión artificial, se denomina color quantization al


proceso de reducción del número de colores distintos presentes en una imagen, utilizado
usualmente con la intención de obtener una nueva imagen que sea visualmente similar a la imagen
original pero con un menor número de colores, consiguiendo de esta forma reducir el tamaño de la
imagen. Muchas veces, algunos dispositivos tienen la limitación de producir únicamente un
conjunto reducido de colores. En esos casos, se puede realizar el proceso de cuantización para
reducir los colores, haciendo uso del algoritmo k-means.

A continuación se presenta un ejemplo de cuantización. Aquí tendremos tres características, es


decir, los tres canales de color R,G,B. Por tanto, necesitamos hacer un reshape de la imagen a un
array de tamaño Mx3 (siendo M el número de píxeles de la imagen). Después de realizar la
clusterización, se aplicarán los valores de los centroides a todos los píxeles, obteniendo una
imagen con el número de colores especificado (K).

Ejemplo. Cuantización de colores de una imagen.

import numpy as np
import cv2

img = cv2.imread('images/machu_picchu.jpg')
Z = img.reshape((-1,3))

# Convert to np.float32
Z = np.float32(Z)

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 67
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx
TECNOLÓGICO NACIONAL DE MEXICO
p Instituto Tecnológico Superior de Pátzcuaro

# Define criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)

# Define number of clusters(K)


K = 8

# Attempts
attempts = 10

# Apply kmeans
if cv2.__version__.startswith('2.4'):
ret, label, center = cv2.kmeans(Z, K, criteria, attempts, cv2.KMEANS_RANDOM_
CENTERS)
else:
ret, label, center = cv2.kmeans(Z, K, None, criteria, attempts, cv2.KMEANS_R
ANDOM_CENTERS)

# Now convert back into uint8, and make original image


center = np.uint8(center)
res = center[label.flatten()]
final_image = res.reshape((img.shape))

cv2.imshow('Original image', img)


cv2.imshow('Color Quantization', final_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Carretera Pátzcuaro-Morelia Av. Tecnológico No.1, Zurumutaro


Pátzcuaro, Michoacan, México. C.P. 61615 68
Tel. (434) 542-5049, 5063, 5067, e-mail: direccion@itspa.edu.mx
www.itspa.edu.mx

You might also like