Características de HoG

En este notebook creará un conjunto de imagenes con caras y no caras mediante las que obtendremos las características de HoG que nos servirán como conjunto de entrenamiento para nuestro clasificador.

Además, estas características serán serializadas para que podamos acceder a ellas las veces que deseemos evitando su procesamiento.

Histogram of Oriented Gradients (HoG)

HoG es una técnica para la extracción de características, desarrollada en el contexto del procesamiento de imagenes, que involucra los siguientes pasos:

  1. Pre-normalizado de las imagenes. Aunque puede suponer una mayor dependencía de las características que varían segun la iluminación.
  2. Aplicar a la imagen dos filtros sensibles al brillo tanto horizontal como vertical. Lo cual nos aporta información sobre bordes, contornos y texturas.
  3. Subdividir la imagen en celdas de un tamaño concreto y calcular el histograma del gradiente para cada celda.
  4. Normalizar los histogramas, previamente calculados, mediante la comparación con sus vecinos. Eliminando así el efecto de la iluminación en la imagen.
  5. Construir un vector de caracteristicas unidimensional de la información de cada celda.

1. Crear un conjunto de entrenamiento de imagenes de caras que supongan positivos

Scikit nos proporciona un conjunto de imagenes variadas de caras que nos permitirán obtener un conjunto de entrenamiento de positivos para nuestro objetivo. Más de 13000 caras para ser concretos.


In [ ]:
from sklearn.datasets import fetch_lfw_people
faces = fetch_lfw_people()
positive_patches = faces.images
positive_patches.shape

Alternativa

Vamos a proporcionar, de manera alternativa a la anterior, nuestro propio conjunto de imagenes.


In [2]:
# from skimage import io
# from skimage.color import rgb2gray

# positive_patches = list()

# path = "../imgaug/imgs/"
# for i in range(376):
#     for j in range(63):
#         image = io.imread(path+str(i)+str(j)+".jpg")
#         positive_patches.append(rgb2gray(image))

2. Crear un conjunto de entrenamiento de imagenes de no-caras que supongan falsos-positivos

Una vez obtenido nuestro conjunto de positivos, necesitamos obtener un conjunto de imagenes que no tengan caras. Para ello, la técnica que se utiliza en el notebook en el que me estoy basando es subdividir imágenes de mayor tamaño que no contengan caras. Y, así, obtener múltiples imágenes.


In [72]:
from skimage import feature, color, data, transform

imgs_to_use = ['camera', 'text', 'coins', 'moon',
               'page', 'clock', 'immunohistochemistry',
               'chelsea', 'coffee', 'hubble_deep_field']
images = [color.rgb2gray(getattr(data, name)())
          for name in imgs_to_use]

In [73]:
import numpy as np
from sklearn.feature_extraction.image import PatchExtractor

def extract_patches(img, N, scale=1.0, patch_size=positive_patches[0].shape):
    
    extracted_patch_size = tuple((scale * np.array(patch_size)).astype(int))
    
    extractor = PatchExtractor(patch_size=extracted_patch_size,
                               max_patches=N, random_state=0)
    
    patches = extractor.transform(img[np.newaxis])
    
    if scale != 1:
        patches = np.array([transform.resize(patch, patch_size)
                            for patch in patches])
    return patches

negative_patches = np.vstack([extract_patches(im, 1000, scale)
                              for im in images for scale in [0.5, 1.0, 2.0]])
negative_patches.shape

# Alternativa
# negative_patches = np.vstack([extract_patches(im, 1000, scale, patch_size=(62,47))
#                               for im in images for scale in [0.5, 1.0, 2.0]])
# negative_patches.shape


Out[73]:
(30000, 62, 47)

3. Extraer las características de HoG del conjunto de entrenamiento

Este tercer paso resulta de especial interes, puesto que vamos a obtener las características de HoG sobre las que previamente hemos hablado.


In [74]:
from itertools import chain
positive_patches = np.array(positive_patches)
print(negative_patches.shape, positive_patches.shape)
X_train = np.array([feature.hog(im)
                    for im in chain(positive_patches,
                                    negative_patches)])
y_train = np.zeros(X_train.shape[0])
y_train[:positive_patches.shape[0]] = 1


(30000, 62, 47) (23688, 62, 47)

4. Serializamos el conjunto de entrenamiento

Simplemente almacenamos los objetos X_train e y_train para, como explicabamos al principio, evitar el recalculo de estas características cada vez que deseemos utilizarlas.


In [75]:
import pickle # Módulo para serializar

path = '../../rsc/obj/'

X_train_path = path + 'X_train.sav'
y_train_path = path + 'y_train.sav'

pickle.dump(X_train, open(X_train_path, 'wb'))
pickle.dump(y_train, open(y_train_path, 'wb'))