Restructure content and add notes from HolaMundo
Signed-off-by: Manuel Vergara <manuel@vergaracarmona.es>
BIN
python-total/dia_14/Empleados/Cosmo Kramer.jpg
Normal file
|
After Width: | Height: | Size: 150 KiB |
BIN
python-total/dia_14/Empleados/Elaine Benes.jpg
Normal file
|
After Width: | Height: | Size: 184 KiB |
BIN
python-total/dia_14/Empleados/Federico Garay.jpg
Normal file
|
After Width: | Height: | Size: 188 KiB |
BIN
python-total/dia_14/Empleados/George Constanza.jpg
Normal file
|
After Width: | Height: | Size: 249 KiB |
BIN
python-total/dia_14/Empleados/Jerry Seinfeld.jpg
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
python-total/dia_14/FotoA.jpg
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
python-total/dia_14/FotoB.jpg
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
python-total/dia_14/FotoC.jpg
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
python-total/dia_14/FotoD.jpg
Normal file
|
After Width: | Height: | Size: 58 KiB |
26
python-total/dia_14/README.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Día 14 - Programa un controlador de asistencia
|
||||
|
||||
## Índice
|
||||
- [Día 14 - Programa un controlador de asistencia](#día-14---programa-un-controlador-de-asistencia)
|
||||
- [Índice](#índice)
|
||||
- [14.1. - Bibliotecas](#141---bibliotecas)
|
||||
- [Ficheros y documentación](#ficheros-y-documentación)
|
||||
|
||||
## 14.1. - Bibliotecas
|
||||
|
||||
## Ficheros y documentación
|
||||
|
||||
- [asistencia.py](asistencia.py)
|
||||
- [Empleados](Empleados/)
|
||||
- [FotoA.jpg](FotoA.jpg)
|
||||
- [FotoB.jpg](FotoB.jpg)
|
||||
- [FotoC.jpg](FotoC.jpg)
|
||||
- [FotoD.jpg](FotoD.jpg)
|
||||
- [reconocimiento_facial.py](reconocimiento_facial.py)
|
||||
- [registro.csv](registro.csv)
|
||||
|
||||
[Documentación del día](../doc_curso/14_asistencia/)
|
||||
|
||||
---
|
||||
|
||||
Enlaces a todos los días: [dia 1 - creador de nombres](../dia_01/README.md) / [dia 2 - calculador de comisiones](../dia_02/README.md) / [dia 3 - analizador de texto](../dia_03/README.md) / [dia 4 - juego "adivina el número"](../dia_04/README.md) / [dia 5 - juego "El ahorcado"](../dia_05/README.md) / [dia 6 - recetario](../dia_06/README.md) / [dia 7 - cuenta bancaria](../dia_07/README.md) / [dia 8 - consola de turnos](../dia_08/README.md) / [dia 9 - buscador de números de serie](../dia_09/README.md) / [dia 10 - juego "Invasión espacial"](../dia_10/README.md) / [dia 11 - web scraping](../dia_11/README.md) / [dia 12 - gestor de restaurantes](../dia_12/README.md) / [dia 13 - asistente de voz](../dia_13/README.md) / [dia 14 - controlador de asistencia](../dia_14/README.md) / [dia 15 - machine learning](../dia_15/README.md) / [dia 16 - aplicación web de tareas pendientes](../dia_16/README.md)
|
||||
185
python-total/dia_14/asistencia.py
Normal file
@@ -0,0 +1,185 @@
|
||||
"""
|
||||
Programa dia 13 - Asistente virtual
|
||||
|
||||
Bibliotecas:
|
||||
cmake
|
||||
dlib
|
||||
face-recognition
|
||||
numpy
|
||||
opencv-python
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import cv2
|
||||
import face_recognition as fr
|
||||
import numpy
|
||||
from datetime import datetime
|
||||
|
||||
# Crear base de datos
|
||||
ruta = 'Empleados'
|
||||
mis_imagenes = []
|
||||
# Obtener nombres de las fotos
|
||||
nombre_empleados = []
|
||||
# Nombres con la extensión .jpg
|
||||
lista_empleados = os.listdir(ruta)
|
||||
|
||||
|
||||
# Cargar imágenes con loop
|
||||
for nombre in lista_empleados:
|
||||
|
||||
# Leer la imagen
|
||||
imagen_actual = cv2.imread(f'{ruta}/{nombre}')
|
||||
|
||||
# Añadimos las coordenadas de la imagen en una nueva lista
|
||||
mis_imagenes.append(imagen_actual)
|
||||
|
||||
# Añadimos tan solo el nombre del empleado
|
||||
nombre_empleados.append(os.path.splitext(nombre)[0])
|
||||
|
||||
# Mostrar lista creada
|
||||
print(nombre_empleados)
|
||||
|
||||
|
||||
def codificar(imagenes):
|
||||
""" Codificar las imágenes """
|
||||
# Crear una lista nueva
|
||||
lista_codificada = []
|
||||
|
||||
# Loop para procesar las imágenes
|
||||
for imagen in imagenes:
|
||||
# Pasar imágenes a RGB
|
||||
imagen = cv2.cvtColor(imagen, cv2.COLOR_BGR2RGB)
|
||||
|
||||
# Codificar
|
||||
codificado = fr.face_encodings(imagen)[0]
|
||||
|
||||
# Agregar a la lista codificada
|
||||
lista_codificada.append(codificado)
|
||||
|
||||
# Devolver lista codificada que se ha procesado
|
||||
return lista_codificada
|
||||
|
||||
|
||||
def registrar_ingresos(persona):
|
||||
""" Recoger los datos de las capturas """
|
||||
|
||||
# Creamos el fichero registro.csv con Nombre, Hora
|
||||
# Aquí lo abrimos para leer
|
||||
f = open('registro.csv', 'r+')
|
||||
# Hacemos un listado con las líneas del fichero
|
||||
lista_datos = f.readlines()
|
||||
# Lista vacía para almacenar los registros
|
||||
nombres_registro = []
|
||||
|
||||
for linea in lista_datos:
|
||||
# leemos separando por comas
|
||||
ingreso = linea.split(',')
|
||||
# Añadimos a la lista
|
||||
nombres_registro.append(ingreso[0])
|
||||
|
||||
if persona not in nombres_registro:
|
||||
|
||||
# Determinamos la hora actual
|
||||
ahora = datetime.now()
|
||||
# Le damos formato a la hora
|
||||
string_ahora = ahora.strftime('%H:%M:%S')
|
||||
|
||||
# Escribimos la persona
|
||||
f.writelines(f'\n{persona}, {string_ahora}')
|
||||
|
||||
|
||||
# Llamar a la función
|
||||
lista_empleados_codificada = codificar(mis_imagenes)
|
||||
|
||||
|
||||
# Mostrar número de imágenes codificadas en la función
|
||||
# print(len(lista_empleados_codificada))
|
||||
|
||||
|
||||
# Tomar una imágen de cámara web
|
||||
captura = cv2.VideoCapture(0)
|
||||
|
||||
# Configuración de la captura para Linux
|
||||
captura.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
|
||||
captura.set(cv2.CAP_PROP_FRAME_HEIGHT, 1024)
|
||||
sleep = 'sleep 3'
|
||||
os.system(sleep)
|
||||
captura.set(cv2.CAP_PROP_EXPOSURE, -8.0)
|
||||
|
||||
# Leer la imágen de la cámara
|
||||
# El método read() arroja dos elementos:
|
||||
# - Si se ha podido realizar la captura
|
||||
# - Devuelve la imágen
|
||||
exito, imagen = captura.read()
|
||||
|
||||
if not exito:
|
||||
print('No se pudo tomar la captura')
|
||||
else:
|
||||
# Primero intentamos reconocer la cara en captura
|
||||
cara_captura = fr.face_locations(imagen)
|
||||
|
||||
# Codificar la cara capturada
|
||||
cara_captura_codificada = fr.face_encodings(imagen, cara_captura)
|
||||
|
||||
# Busquemos coincidencias entre las imágenes capturadas
|
||||
# y la lista de imágenes de empleados
|
||||
for caracodif, caraubic in zip(cara_captura_codificada, cara_captura):
|
||||
# Comparación
|
||||
coincidencias = fr.compare_faces(lista_empleados_codificada, caracodif)
|
||||
|
||||
# Distancias de comparación
|
||||
distancias = fr.face_distance(lista_empleados_codificada, caracodif)
|
||||
|
||||
# La distancia menor de la lista "distancias"
|
||||
# será la que indique el parecido más cercano
|
||||
print(distancias)
|
||||
|
||||
# Buscar el valor mínimo y añadir a variable
|
||||
indice_coincidencia = numpy.argmin(distancias)
|
||||
|
||||
# Mostrar coincidencias si las hay
|
||||
if distancias[indice_coincidencia] > 0.6:
|
||||
texto = 'No coincide'
|
||||
|
||||
else:
|
||||
|
||||
# Buscar el nombre del empleado encontrado
|
||||
texto = nombre_empleados[indice_coincidencia]
|
||||
|
||||
# Crear rectangulo cara
|
||||
y1, x2, y2, x1 = caraubic
|
||||
cv2.rectangle(
|
||||
imagen,
|
||||
(x1, y1),
|
||||
(x2, y2),
|
||||
(0, 255, 0),
|
||||
2
|
||||
)
|
||||
# Crear rectangulo verde de texto
|
||||
cv2.rectangle(
|
||||
imagen,
|
||||
(x1, y2 - 35),
|
||||
(x2, y2),
|
||||
(0, 255, 0),
|
||||
cv2.FILLED
|
||||
)
|
||||
|
||||
# Crear texto
|
||||
cv2.putText(
|
||||
imagen,
|
||||
texto,
|
||||
(x1 + 6, y2 - 6),
|
||||
cv2.FONT_HERSHEY_COMPLEX,
|
||||
0.6,
|
||||
(255, 255, 255),
|
||||
2
|
||||
)
|
||||
|
||||
registrar_ingresos(nombre)
|
||||
|
||||
# Mostrar la imagen obtenida por la cámara
|
||||
cv2.imshow('Imagen web', imagen)
|
||||
|
||||
# Mantener la ventana abierta
|
||||
cv2.waitKey(0)
|
||||
99
python-total/dia_14/reconocimiento_facial.py
Normal file
@@ -0,0 +1,99 @@
|
||||
"""
|
||||
Reconocimiento facial
|
||||
|
||||
Bibliotecas:
|
||||
cmake
|
||||
dlib
|
||||
face-recognition
|
||||
numpy
|
||||
opencv-python
|
||||
|
||||
"""
|
||||
|
||||
import cv2
|
||||
import face_recognition as fr
|
||||
|
||||
# Cargar imágenes
|
||||
foto_control = fr.load_image_file('FotoD.jpg')
|
||||
foto_prueba = fr.load_image_file('FotoC.jpg')
|
||||
|
||||
# Nos aseguramos que el formato de la foto es rgb
|
||||
# Las transformamos de BGR --> RGB
|
||||
foto_control = cv2.cvtColor(foto_control, cv2.COLOR_BGR2RGB)
|
||||
foto_prueba = cv2.cvtColor(foto_prueba, cv2.COLOR_BGR2RGB)
|
||||
|
||||
# Localizar cara control
|
||||
lugar_cara_A = fr.face_locations(foto_control)[0]
|
||||
# Podríamos ver las coordenadas
|
||||
# print(lugar_cara_A)
|
||||
|
||||
# Codificar la cara
|
||||
cara_codificada_A = fr.face_encodings(foto_control)[0]
|
||||
|
||||
|
||||
# Localizar cara control
|
||||
lugar_cara_B = fr.face_locations(foto_prueba)[0]
|
||||
|
||||
# Codificar la cara
|
||||
cara_codificada_B = fr.face_encodings(foto_prueba)[0]
|
||||
|
||||
# Marcar donde está la cara con un rectángulo
|
||||
# Añadimos la foto y los índices para marcar las coordenadas
|
||||
# del vértice superior izquiero de la cara y el
|
||||
# del vértice inferior derecho.
|
||||
# Anadimos el color del rectangulo en verde
|
||||
# y el borde
|
||||
cv2.rectangle(
|
||||
foto_control,
|
||||
(lugar_cara_A[3], lugar_cara_A[0]),
|
||||
(lugar_cara_A[1], lugar_cara_A[2]),
|
||||
(0, 255, 0),
|
||||
2
|
||||
)
|
||||
|
||||
cv2.rectangle(
|
||||
foto_prueba,
|
||||
(lugar_cara_B[3], lugar_cara_B[0]),
|
||||
(lugar_cara_B[1], lugar_cara_B[2]),
|
||||
(0, 255, 0),
|
||||
2
|
||||
)
|
||||
|
||||
|
||||
# Realizar comparación
|
||||
# El método espera recibir una lista.
|
||||
# Como tenemos un único objecto lo ponemos entre corchetes
|
||||
# para que piense que es una lista de un solo objeto.
|
||||
# El tercer valor es la torelancia de distancia de comparación
|
||||
resultado = fr.compare_faces([cara_codificada_A], cara_codificada_B)
|
||||
# print(resultado)
|
||||
|
||||
|
||||
# Medida de la distancia de comparación
|
||||
# por defecto es 0.6 el valor para admitir coincidencia con True
|
||||
# Esto nos indica lo cerca que está
|
||||
distancia = fr.face_distance([cara_codificada_A], cara_codificada_B)
|
||||
# print(distancia)
|
||||
|
||||
|
||||
# Mostrar resultado con texto
|
||||
# Los parámetros son la imagén, el texto a introducir,
|
||||
# la ubicación del texto, la fuente, la escala,
|
||||
# el color y el grosor
|
||||
cv2.putText(
|
||||
foto_prueba,
|
||||
f'{resultado} {distancia.round(2)}',
|
||||
(50, 50),
|
||||
cv2.FONT_HERSHEY_COMPLEX,
|
||||
1,
|
||||
(0, 255, 0),
|
||||
2
|
||||
)
|
||||
|
||||
|
||||
# Mostrar imágenes
|
||||
cv2.imshow('Foto Control', foto_control)
|
||||
cv2.imshow('Foto Prueba', foto_prueba)
|
||||
|
||||
# Las imágenes se cierran, se necesitan mantener el programa abierto
|
||||
cv2.waitKey(0)
|
||||
1
python-total/dia_14/registro.csv
Normal file
@@ -0,0 +1 @@
|
||||
Nombre, Hora
|
||||
|