Determinación de género por morfometría de ojos

Descripción general

El análisis antropométrico del rostro humano es un estudio fundamental para la realización de cirugías plásticas y reconstructivas craneofaciales. La antropometría facial se ve afectada por varios factores, como la edad, el género, el origen étnico, el nivel socioeconómico, el entorno y la región.

Los cirujanos plásticos que emprenden la reparación y reconstrucción de deformidades faciales encuentran útiles las dimensiones anatómicas de las estructuras faciales para sus cirugías. Estas dimensiones son el resultado de la apariencia física o facial de un individuo. Junto con factores como la cultura, la personalidad, el origen étnico, la edad; La apariencia y la simetría de los ojos contribuyen en gran medida a la apariencia o estética facial.

Mi objetivo es construir un modelo para escanear la imagen de un ojo de un paciente y encontrar si el género del paciente es masculino o femenino.

El modelo se evaluará utilizando Accuracy Score.

Enlace del conjunto de datos: https://drive.google.com/file/d/1f7uslI-ZHidriQFZR966_aILjlkgDN76/view?usp=sharing

from zipfile import ZipFile
with ZipFile('eye_gender_data.zip', 'r') as zf:
zf.extractall('')

Para poder realizar análisis sobre las imágenes, necesitaríamos hacer uso de bibliotecas. Las bibliotecas son como ayudas proporcionadas por python para llevar a cabo tareas específicas.

# Data analysis and manipultion tool
import pandas as pd
# Fundamental package for linear algebra and multidimensional arrays
import numpy as np
# Deep Learning Tool
import tensorflow as tf
# OS module in Python provides a way of using operating system dependent functionality
import os
# Library for image processing
import cv2
# For splitting the data into train and validation set
from sklearn.model_selection import train_test_split
from sklearn.metrics import f1_score
from sklearn.preprocessing import LabelEncoder
import matplotlib.pyplot as plt
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)

Nuestro conjunto de datos se ha dividido en dos conjuntos: conjunto de entrenamiento y conjunto de datos de prueba. El conjunto de datos de prueba se utilizará como evaluación del nivel de precisión de mi modelo.

Primero, cargaré las imágenes del conjunto de entrenamiento en un marco de datos con filas y columnas. Esto serviría como la mejor estructura para analizar las imágenes y crear un modelo. También reduciré el tamaño de las imágenes para reducir el espacio que ocupa la RAM al analizar los patrones.

#loading the labels
labels = pd.read_csv("eye_gender_data/Training_set.csv")

file_paths = [[fname, 'eye_gender_data/train/' + fname] for fname in labels['filename']]
images = pd.DataFrame(file_paths, columns=['filename', 'filepaths'])
train_data = pd.merge(images, labels, how = 'inner', on = 'filename')

#initialize an empty numpy array
data = []
#image size taken is 50 here. one can take other size too
image_size = 100
dsize = (image_size, image_size)
for i in range(len(train_data)):
# converting the image to gray scale
img_array = cv2.imread(train_data['filepaths'][i], cv2.IMREAD_GRAYSCALE)
# resizing the image array
new_img_array = cv2.resize(img_array, dsize)
data.append([new_img_array, train_data['label'][i]])

Es necesario traer todas las imágenes en la misma forma y tamaño, también convertirlas a sus valores de píxeles porque todos los modelos de aprendizaje automático o aprendizaje profundo aceptan solo los datos numéricos. También necesitamos convertir todas las etiquetas de valores categóricos a valores numéricos.

print(data[0])
plt.imshow(data[0][0])
plt.title(data[0][1])
[array([[188, 188, 189, ..., 176, 175, 175],
[189, 189, 188, ..., 174, 173, 172],
[190, 189, 188, ..., 168, 167, 167],
...,
[133, 137, 144, ..., 168, 167, 166],
[134, 138, 145, ..., 165, 164, 163],
[135, 139, 146, ..., 163, 162, 162]], dtype=uint8), 'male']
Text(0.5, 1.0, 'male')
#Initialize an empty numpy array
data2 = []

#image size taken is 100 here. one can take other size too
image_size = 100
for i in range(len(train_data)):
# converting the image to gray scale
img_array = cv2.imread(train_data['filepaths'][i], cv2.IMREAD_GRAYSCALE)
# resizing the image array
new_img_array = cv2.resize(img_array, (image_size, image_size))
data2.append([new_img_array])
train_im = np.array(data2,dtype='uint8')
train_im.shape
(9220, 1, 100, 100)
train_im = train_im.reshape(9220,100,100,1)
print(train_im.shape)
print(train_im.dtype)
(9220, 100, 100, 1)
uint8
for i in range(len(data)):
a=pd.DataFrame(data)
a.columns= ['images','gender']
labelencoder = LabelEncoder()
a['gender_cat'] = labelencoder.fit_transform(a['gender'])
a.head()

plt.imshow(train_im[5].reshape(100,100))
plt.title(a['gender'][5])
Text(0.5, 1.0, 'male')

Desde la biblioteca de preprocesamiento de Sklearn, puedo usar Label Encoder para codificar cada categoría de género en 1 y 0. Esto facilita que la computadora registre un determinado patrón de imagen para un género específico representado por 1 o 0. A continuación, Dividiré los datos en datos de entrenamiento y conjunto de datos de validación. Los datos de entrenamiento se usarían para entrenar el modelo y los datos de validación se usarían para validar la precisión del modelo.

X = train_im /255
y = a['gender_cat']

Ahora finalmente estoy listo para entrenar al modelo. Usando keras de tensorflow, crearé 10 capas de redes neuronales con capas convolutivas 2D, maxpooling, Dense y Dropout. Luego, compilo el modelo usando el optimizador ‘adam’, configurando la precisión como mi métrica de evaluación y configurando una característica para mi pérdida.

# define input shape
INPUT_SHAPE = (100,100,1)

# define sequential model
model = tf.keras.models.Sequential()
# define conv-pool layers - set 1
model.add(tf.keras.layers.Conv2D(filters=16, kernel_size=(3, 3), strides=(1, 1), activation='relu', padding='valid', input_shape=INPUT_SHAPE))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2)))
# define conv-pool layers - set 2
model.add(tf.keras.layers.Conv2D(filters=32, kernel_size=(3, 3), strides=(1, 1),
activation='relu', padding='valid', input_shape=INPUT_SHAPE))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2)))

# add flatten layer
model.add(tf.keras.layers.Flatten())

# add dense layers with some dropout
model.add(tf.keras.layers.Dense(256, activation='relu'))
model.add(tf.keras.layers.Dropout(rate=0.3))
model.add(tf.keras.layers.Dense(128, activation='relu'))
model.add(tf.keras.layers.Dropout(rate=0.3))

# add output layer
model.add(tf.keras.layers.Dense(2, activation='sigmoid'))

# compile model
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])

# view model layers
model.summary()

Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 98, 98, 16) 160

max_pooling2d (MaxPooling2D (None, 49, 49, 16) 0
)

conv2d_1 (Conv2D) (None, 47, 47, 32) 4640

max_pooling2d_1 (MaxPooling (None, 23, 23, 32) 0
2D)

flatten (Flatten) (None, 16928) 0

dense (Dense) (None, 256) 4333824

dropout (Dropout) (None, 256) 0

dense_1 (Dense) (None, 128) 32896

dropout_1 (Dropout) (None, 128) 0

dense_2 (Dense) (None, 2) 258

=================================================================
Total params: 4,371,778
Trainable params: 4,371,778
Non-trainable params: 0
_________________________________________________________________

A continuación, configuro la cantidad de épocas que quiero que mi modelo se ejecute mientras se ajusta, y también configuro la pérdida que pretendo monitorear. El conjunto de datos de validación se utiliza para medir la precisión después de cada época.

EPOCHS = 10

es_callback = tf.keras.callbacks.EarlyStopping(monitor='val_loss',
patience=3,
restore_best_weights=True,
verbose=1)
history = model.fit(X,
y,
batch_size=5,
callbacks=[es_callback],
validation_split=0.2,
epochs=EPOCHS,verbose =1)
Epoch 1/10
1476/1476 [==============================] - 1189s 792ms/step - loss: 0.5331 - accuracy: 0.7314 - val_loss: 0.4226 - val_accuracy: 0.8134
Epoch 2/10
1476/1476 [==============================] - 1296s 878ms/step - loss: 0.3896 - accuracy: 0.8312 - val_loss: 0.4120 - val_accuracy: 0.8194
Epoch 3/10
1476/1476 [==============================] - 1282s 868ms/step - loss: 0.3341 - accuracy: 0.8609 - val_loss: 0.3146 - val_accuracy: 0.8693
Epoch 4/10
1476/1476 [==============================] - 999s 677ms/step - loss: 0.2911 - accuracy: 0.8787 - val_loss: 0.3120 - val_accuracy: 0.8774
Epoch 5/10
1476/1476 [==============================] - 1014s 687ms/step - loss: 0.2437 - accuracy: 0.9001 - val_loss: 0.3055 - val_accuracy: 0.8753
Epoch 6/10
1476/1476 [==============================] - 755s 512ms/step - loss: 0.2147 - accuracy: 0.9117 - val_loss: 0.3290 - val_accuracy: 0.8726
Epoch 7/10
1476/1476 [==============================] - 980s 664ms/step - loss: 0.1774 - accuracy: 0.9298 - val_loss: 0.3612 - val_accuracy: 0.8861
Epoch 8/10
1476/1476 [==============================] - ETA: 0s - loss: 0.1489 - accuracy: 0.9425Restoring model weights from the end of the best epoch: 5.
1476/1476 [==============================] - 1272s 862ms/step - loss: 0.1489 - accuracy: 0.9425 - val_loss: 0.3741 - val_accuracy: 0.8802
Epoch 8: early stopping

A partir del resultado, el modelo deja de ajustarse en la época deseada para evitar el sobreajuste. Esto sucede cuando logramos una alta precisión tanto para el entrenamiento como para la validación de datos con muy poca pérdida y pérdida de validación.

Hemos entrenado nuestro modelo, lo evaluamos y ahora finalmente predeciremos el resultado/objetivo para los datos de prueba (es decir, Test.csv).

Cargue los datos de prueba sobre los que se realizará el envío final.

# loading the labels
test_labels = pd.read_csv("eye_gender_data/Testing_set.csv")
file_paths2 = [[fname2, 'eye_gender_data/test/' + fname2]
for fname2 in test_labels['filename']]
images_t = pd.DataFrame(file_paths, columns=['filename', 'filepaths'])
test_data = pd.merge(images_t, test_labels, how = 'inner', on = 'filename')

# initialize an empty numpy array
data_t = []
image_size = 100
# image size taken is 100 here. one can take other size too
for i in range(len(test_data)):
# converting the image to gray scale
img_array_t = cv2.imread(test_data['filepaths'][i], cv2.IMREAD_GRAYSCALE)
# resizing the image array
new_img_array_t = cv2.resize(img_array_t, (image_size, image_size))

data_t.append([new_img_array_t])

test_im = np.array(data_t,dtype='uint8')
test_im.shape
(2305, 1, 100, 100)
test_im = test_im.reshape(2305,100,100,1)
print(test_im.shape)
print(test_im.dtype)
(2305, 100, 100, 1)
uint8

plt.imshow(test_im[5].reshape(100,100))

<matplotlib.image.AxesImage at 0x1e316618a00>
test_norm = test_im / 255

Es hora de hacer una presentación!!!

prediction2 = model.predict(test_norm)
prediction2[:5]
73/73 [==============================] - 53s 682ms/step

array([[1.5717943e-01, 9.8344243e-01],
[8.6765045e-01, 1.7700831e-03],
[7.1922296e-01, 9.4394431e-02],
[9.2397380e-01, 3.9275724e-04],
[1.5497887e-01, 9.9005252e-01]], dtype=float32)

pred2_label = np.argmax(prediction2,axis=1)
submission_22=pd.DataFrame({'filename':test_labels['filename'], 'label_num':pred2_label})

submission_22["label"] = labelencoder.inverse_transform(submission_22['label_num'])
submission22 = submission_22[['filename','label']]
submission22.to_csv('submission3.csv', index = False)
print(submission22.head())
filename label
0 Image_1.jpg male
1 Image_2.jpg female
2 Image_3.jpg female
3 Image_4.jpg female
4 Image_5.jpg male

En este proyecto pudimos conocer una de las diversas aplicaciones de la visión artificial que es el análisis de imágenes. Pude analizar un conjunto de datos de imágenes, entrenar un modelo usando redes neuronales complicadas (CNN). También podemos hacer uso del modelo para hacer predicciones. Este proyecto muestra aplicaciones prometedoras para la visión artificial.

[post_relacionado id=»1231″]


Comentarios

Deja una respuesta

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