Рубрики
Без рубрики

Как автоматизировать запись посещаемости с распознаванием лица, Python и React

Посещение – довольно скучная задача. Посмотрим, как мы можем автоматизировать это с помощью искусственной Intel … Tagged с Becode, Python, React, AI.

Посещение – довольно скучная задача. Давайте посмотрим, как мы можем автоматизировать это с помощью искусственного интеллекта в Python и хорошего пользовательского интерфейса в React.

Что мы хотим?

Система, которая проверяет, находится ли сотрудник вовремя или ушла рано. Но также проверьте время прибытия и отъезда их. Мы также хотим иметь возможность Добавить или Удалить сотрудник.

Как это сделать?

Мы можем поместить камеру перед дверью, которая будет Признайте сотрудников и Сохранить время их Прибытие и отправление . С этими данными мы делаем несколько простых условий, чтобы определить, являются ли они поздно или если они Осталось ранее Анкет Мы сохраняем эту информацию в онлайн База данных Чтобы сделать его доступным из любого места.

Как пользователь сможет использовать эти данные?

С простым веб -интерфейсом. Мы просто хотим добавить и удалить сотрудника и проверить все данные, которые мы имеем о нем.

Снимок экрана:

С какими технологиями?

Чтобы создать внешний интерфейс Мы используем Реагировать что идеально подходит для обработки информации в режиме реального времени.

Для Бэк-Энд , мы используем Колба Python Чтобы создать API, который может получать запрос и данные, затем отправьте обратно и ответьте. Например, API получит имя, сделайте запрос в базу данных, чтобы иметь все данные об этом человеке и отправить эти данные.

Для База данных , мы используем Postgresql Но любой двигатель базы данных выполнят работу.

Для распознавание лица , мы используем библиотеку Python под названием « face_recognition ».

Как это будет работать?

Давайте опишем поток обработки данных нашего веб -приложения.

Как только камера обнаружит лицо, она проверит Если человек в системе И если да, то это забрает дата , имя человека и время его обнаружило Анкет Если это первый раз, когда этот сотрудник будет обнаружен сегодня, будет назначено время прибытия, как только это время будет определено, каждое последующее обнаружение в тот же день обновит его время отправления.

Давайте подробно расскажем о том, как будут проходить данные.

Первый скрипт получит видео с камерой, обнаружит людей, получает время обнаружения и отправит информацию Thoses в наш API. Затем API спросит DB, является ли сотрудник, который уже был замечен сегодня, чтобы определить, является ли время, когда он увидел, что человек – время прибытия или время отправления. Затем он проверит, находится ли сотрудник в условиях, которые должны быть вовремя, и отправлять все эти данные в БД.

Пользователь сможет спросить с фронт-энда данные о сотруднике, добавить один или удалить один.

Фронт отправит информацию в API, который запросит БД, получит информацию и отправит ее обратно на фронт.

Давайте погрузимся в код!

Хорошо. Теперь, когда мы знаем, что хотим и как это будет структурировано, пришло время кодировать!

Этот раздел будет разделен на 3 части.

  1. Распознавание лица
  2. API
  3. Фронт-Энд

1. Распознавание лица

Как упомянуто выше, для распознавание лица Мы будем использовать библиотеку Python face_recognition. Давайте быстро посмотрим, как это работает.

Мы Дайте картинку пользователя для записи своего «Личность лица» Анкет

Первая модель откопатся, есть ли лицо или нет и Определите его местоположение на фотографии.

Вторая модель будет Рассчитайте параметры лица Анкет (Расстояние между глазами, форма подбородка,…)

Мы сохраняем эти так называемые «закодированные» данные по Связывая их с именем чтобы они могли быть сравнил с будущей картиной.

Тогда мы даем Новое безымянное фото и тот же процесс будет повторяться, за исключением того, что на этот раз, а Третья модель сравнит параметры лица с теми, что это уже знает Анкет

Для получения дополнительной информации, пожалуйста, обратитесь к официальная документация .

Код:

Чтобы добавить одного пользователя с изображением:

# Import the library
import face_recognition

# Select an image to teach to the machine how to recognize

# * ---------- User 1 ---------- *
# Load the image 
user_one_face = face_recognition.load_image_file("assets/img/user-one.jpg")
# Encode the face parametres
user_one_face_encoding = face_recognition.face_encodings(user_one_face)[0]

# * ---------- User 2 ---------- *
# Load the image 
user_two_face = face_recognition.load_image_file("assets/img/user-two.jpg")
# Encode the face parametres
user_two_face_encoding = face_recognition.face_encodings(user_two_face)[0]


# Create a list of known face encodings and their names
known_face_encodings = [
    user_one_face_encoding,
    user_two_face_encoding
]

# Create list of the name matching with the position of the known_face_encodings
known_face_names = [
    "User One",
    "User Two"
]

Если мы хотим добавить больше пользователей, мы должны повторить эти шаги для каждого из них.

Остаться СУХОЙ , Давайте автоматизируем процесс «Добавить лицо», создав папку, в которой мы храним портретные фотографии наших сотрудников.

Теперь он будет автоматически Кодировать все фотографии в папке от Связывая их к Имя файла Анкет

# Import the library
import face_recognition

# Declare all the list
known_face_encodings = []
known_face_names = []
known_faces_filenames = []

# Walk in the folder to add every file name to known_faces_filenames
for (dirpath, dirnames, filenames) in os.walk('assets/img/users/'):
    known_faces_filenames.extend(filenames)
    break

# Walk in the folder
for filename in known_faces_filenames:
    # Load each file
    face = face_recognition.load_image_file('assets/img/users/' + filename)
    # Extract the name of each employee and add it to known_face_names
    known_face_names.append(re.sub("[0-9]",'', filename[:-4]))
    # Encode de face of every employee
    known_face_encodings.append(face_recognition.face_encodings(face)[0])

Вот и мы! Все наши сотрудники теперь закодированы, и мы можем их распознать.

Сравнить с изображением:

# * --------- IMPORTS --------- *
import numpy as np
import face_recognition

# * ---------- Encode the nameless picture --------- *
# Load picture
face_picture = face_recognition.load_image_file("assets/img/user-one.jpg")
# Detect faces
face_locations = face_recognition.face_locations(face_picture)
# Encore faces
face_encodings = face_recognition.face_encodings(face_picture, face_locations)

# Loop in all detected faces
for face_encoding in face_encodings:
    # See if the face is a match for the known face (that we saved in the precedent step)
    matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
    # name that we will give if the employee is not in the system
    name = "Unknown"
    # check the known face with the smallest distance to the new face
    face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)
    # Take the best one
    best_match_index = np.argmin(face_distances)
    # if we have a match:
    if matches[best_match_index]:
        # Give the detected face the name of the employee that match
        name = known_face_names[best_match_index]

В конце значение ” name ” будет ” unnk ” или иметь Имя сотрудника этот матч.

Хорошо, мы знаем, как Сравните две картинки . Но мы хотим применить это к видео подача , Правильно?

Итак, давайте просто Применить это к каждому кадру видео -канала, тогда если есть совпадение, Отправить данные к API (что мы сделаем позже) !

# * --------- IMPORTS ---------*
import cv2

# Select the webcam of the computer (0 by default for laptop)
video_capture = cv2.VideoCapture(0)

# Aplly it until you stop the file's execution
while True:
    # Take every frame
    frame = video_capture.read()
    # Process every frame only one time
    if process_this_frame:
        # Find all the faces and face encodings in the current frame of video
        face_locations = face_recognition.face_locations(frame)
        face_encodings = face_recognition.face_encodings(frame, face_locations)
        # Initialize an array for the name of the detected users
        face_names = []

        # * ---------- Initialyse JSON to EXPORT --------- *
        json_to_export = {}
        # Loop in every faces detected
        for face_encoding in face_encodings:
            # See if the face is a match for the known face(s)
            matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
            name = "Unknown"
            # check the known face with the smallest distance to the new face
            face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)
            # Take the best one
            best_match_index = np.argmin(face_distances)
            # If we have a match
            if matches[best_match_index]:
                # Save the name of the best match
                name = known_face_names[best_match_index]

                # * ---------- SAVE data to send to the API -------- *
                # Save the name
                json_to_export['name'] = name
                # Save the time
                json_to_export['hour'] = f'{time.localtime().tm_hour}:{time.localtime().tm_min}'
                # Save the date
                json_to_export[
                    'date'] = f'{time.localtime().tm_year}-{time.localtime().tm_mon}-{time.localtime().tm_mday}'
                # If you need to save a screenshot:
                json_to_export['picture_array'] = frame.tolist()

                # * ---------- SEND data to API --------- *
                # Make a POST request to the API
                r = requests.post(url='http://127.0.0.1:5000/receive_data', json=json_to_export)
                # Print to status of the request:
                print("Status: ", r.status_code)

        # Store the name in an array to display it later
        face_names.append(name)
        # To be sure that we process every frame only one time
        process_this_frame = not process_this_frame

        # * --------- Display the results ---------- *
        for (top, right, bottom, left), name in zip(face_locations, face_names):
            # Draw a box around the face
            cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)
            # Define the font of the name
            font = cv2.FONT_HERSHEY_DUPLEX
            # Display the name
            cv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1)

        # Display the resulting image
        cv2.imshow('Video', frame)

# Release handle to the webcam
video_capture.release()
cv2.destroyAllWindows()

Сейчас у нас есть сценарий, который будет распознавать кто в передняя часть камеры и Отправьте его в API Анкет

2. API

Как упомянуто выше, для API мы используем Колба Анкет Цель здесь состоит в том, чтобы получить данные от нашей модели распознавания лица и перераспределить их на фронт по запросу. Но также иметь возможность добавить нового сотрудника с его именем и фотографией и иметь возможность удалить некоторые, только восстановив его имя.

Давайте создадим приложение:

# * --------- IMPORTS --------- *
# All the imports that we will need in our API
from flask import Flask, request, jsonify
from flask_cors import CORS, cross_origin
import os
import psycopg2
import cv2
import numpy as np
import re

# We define the path of the current file, we will use it later
FILE_PATH = os.path.dirname(os.path.realpath(__file__))


# * ---------- Create App --------- *
# Init the app
app = Flask(__name__)
# To avoid cors erros
CORS(app, support_credentials=True)


# * -------------------- Run Server -------------------- *
if __name__ == '__main__':
    # * --- DEBUG MODE: --- *
    app.run(host='127.0.0.1', port=5000, debug=True)

Создайте маршрут, который будет получать данные от нашей модели распознавания лица:

Примечание: этот код должен быть ** между * Создать раздел приложения и Запустить раздел сервера Анкет *

# * --------------------  ROUTES ------------------- *
# * ---------- Get data from the face recognition ---------- *
@app.route('/receive_data', methods=['POST'])
def get_receive_data():
    if request.method == 'POST':
        # Get the data
        json_data = request.get_json()

        # Check if the user is already in the DB
        try:
            # Connect to the DB
            connection = psycopg2.connect(user="USER_NAME",
                                          password="PASSWORD",
                                          host="DB_HOST",
                                          port="PORT",
                                          database="DATABBASE_NAME")
            # Open a cursor
            cursor = connection.cursor()

            # Query to check if the user as been saw by the camera today
            is_user_is_there_today =\
                f"SELECT * FROM users WHERE date = '{json_data['date']}' AND name = '{json_data['name']}'"

            cursor.execute(is_user_is_there_today)
            # Store the result
            result = cursor.fetchall()
            # Send the request
            connection.commit()

            # If use is already in the DB for today:
            if result:
                # Update user in the DB
                update_user_querry = f"UPDATE users SET departure_time = '{json_data['hour']}', departure_picture = '{json_data['picture_path']}' WHERE name = '{json_data['name']}' AND date = '{json_data['date']}'"
                cursor.execute(update_user_querry)

            else:
                # Create a new row for the user today:
                insert_user_querry = f"INSERT INTO users (name, date, arrival_time, arrival_picture) VALUES ('{json_data['name']}', '{json_data['date']}', '{json_data['hour']}', '{json_data['picture_path']}')"
                cursor.execute(insert_user_querry)

        except (Exception, psycopg2.DatabaseError) as error:
            print("ERROR DB: ", error)
        finally:
            # Execute query
            connection.commit()

            # closing database connection.
            if connection:
                cursor.close()
                connection.close()
                print("PostgreSQL connection is closed")

        # Return user's data to the front
        return jsonify(json_data)

Создайте маршрут, который получит данные сотрудника из базы данных с его именем

Мы получить Имя как строка из Получить запрос из Фронт , сделать запрос на базу данных и вернуть данные что мы получаем как json Анкет

# * ---------- Get all the data of an employee ---------- *
@app.route('/get_employee/', methods=['GET'])
def get_employee(name):
    answer_to_send = {}
    # Check if the user is already in the DB
    try:
        # Connect to DB
        connection = psycopg2.connect(user="USER",
                                      password="PASSWORD",
                                      host="DB_HOST",
                                      port="PORT",
                                      database="DATABASE_NAME")

        cursor = connection.cursor()
        # Query the DB to get all the data of a user:
        user_information = f"SELECT * FROM users WHERE name = '{name}'"

        cursor.execute(user_information)
        result = cursor.fetchall()
        connection.commit()

        # if the user exist in the db:
        if result:
            print('RESULT: ',result)
            # Structure the data and put the dates in string for the front
            for k,v in enumerate(result):
                answer_to_send[k] = {}
                for ko,vo in enumerate(result[k]):
                    answer_to_send[k][ko] = str(vo)
            print('answer_to_send: ', answer_to_send)
        else:
            answer_to_send = {'error': 'User not found...'}

    except (Exception, psycopg2.DatabaseError) as error:
        print("ERROR DB: ", error)
    finally:
        # closing database connection:
        if (connection):
            cursor.close()
            connection.close()

    # Return the user's data to the front
    return jsonify(answer_to_send)

Создайте маршрут, который получит данные 5 последних сотрудников, обнаруженных камерой

Мы получаем Получить запрос из Фронт , Запрос DB Чтобы получить 5 Последние записи и Отправить ответ к фронту как json Анкет

# * --------- Get the 5 last users seen by the camera --------- *
@app.route('/get_5_last_entries', methods=['GET'])
def get_5_last_entries():
    # Create a dict thet will contain the answer to give to the front
    answer_to_send = {}
    # Check if the user is already in the DB
    try:
        # Connect to DB
        connection = psycopg2.connect(user="USER_NAME",
                                      password="PASSWORD",
                                      host="HOST_NAME",
                                      port="PORT",
                                      database="DATABASE_NAME")

        cursor = connection.cursor()
        # Query the DB to get the 5 last entries ordered by ID:
        lasts_entries = f"SELECT * FROM users ORDER BY id DESC LIMIT 5;"
        cursor.execute(lasts_entries)
        # Store the result
        result = cursor.fetchall()
        # Send the request
        connection.commit()

        # if DB is not empty:
        if result:
            # Structure the data and put the dates in dict for the front
            for k, v in enumerate(result):
                answer_to_send[k] = {}
                for ko, vo in enumerate(result[k]):
                    answer_to_send[k][ko] = str(vo)
        else:
            answer_to_send = {'error': 'DB is not connected or empty'}

    except (Exception, psycopg2.DatabaseError) as error:
        print("ERROR DB: ", error)
    finally:
        # closing database connection:
        if (connection):
            cursor.close()
            connection.close()

    # Return the user's data to the front as a json
    return jsonify(answer_to_send)

Создайте маршрут, который добавит сотрудника в систему

Мы получаем Получить запрос с картина и имя Спереди мы будем Добавьте его в папку пользователя и Отправить сообщение об успехе спереди.

# * ---------- Add new employee ---------- *
@app.route('/add_employee', methods=['POST'])
@cross_origin(supports_credentials=True)
def add_employee():
    try:
        # Get the picture from the request
        image_file = request.files['image']

        # Store it in the folder of the know faces:
        file_path = os.path.join(f"assets/img/users/{request.form['nameOfEmployee']}.jpg")
        image_file.save(file_path)
        answer = 'new employee succesfully added'
    except:
        answer = 'Error while adding new employee. Please try later...'
    return jsonify(answer)

Создайте маршрут, который получит список имени всех сотрудников в системе

Мы получаем Получить запрос с фронта, Прогулка в папке пользователя, чтобы получить Имя всего сотрудника и отправьте этот список к Фронт как json Анкет

# * ---------- Get employee list ---------- *
@app.route('/get_employee_list', methods=['GET'])
def get_employee_list():
    # Create a dict that will store the list of employee's name
    employee_list = {}

    # Walk in the user's folder to get the user list
    walk_count = 0
    for file_name in os.listdir(f"{FILE_PATH}/assets/img/users/"):
        # Capture the employee's name with the file's name
        name = re.findall("(.*)\.jpg", file_name)
        if name:
            employee_list[walk_count] = name[0]
        walk_count += 1

    return jsonify(employee_list)

Создайте маршрут, который удалит пользователя с его именем

Мы получаем Получить запрос с фронта с Имя пользователя как строка, чтобы удалять Это. Тогда API доступ к папке пользователя и удалить картина с Соответствующее имя Анкет

# * ---------- Delete employee ---------- *
@app.route('/delete_employee/', methods=['GET'])
def delete_employee(name):
    try:
        # Select the path
        file_path = os.path.join(f'assets/img/users/{name}.jpg')
         # Remove the picture of the employee from the user's folder:
        os.remove(file_path)
        answer = 'Employee succesfully removed'
    except:
        answer = 'Error while deleting new employee. Please try later'

    return jsonify(answer)

Вот так! У нас есть полностью функциональный сценарий распознавания лица и API, который пинает немного задницы! Давайте сейчас создадим хороший пользовательский интерфейс.

3. Передняя часть

Для передней части я разделил каждую панель на компонент. Мы не вдаваемся в подробности в каждом компоненте, мы просто объясним, как отправить запрос и получить ответ в качестве JSON. Мы позволяем вам быть креативным, чтобы использовать данные. Если вам нужен пример, Вот ссылка на GitHub проекта Анкет

Запрос на получение данных сотрудника:

// Define a state the get the list of the employee's data
const [employeeList, setEmployeeList] = useState([]);
// Define a state to get the error if there is
const [errorMessage, setErrorMessage] = useState(null);


// Function to send the employee's name (value of an input fiel) and get back his data
const searchForEmployee = () => {
    // Value of the employee's name input
    const name = document.getElementById('searchForEmployee').value.toLowerCase()
    if(name){
        fetch(`http://127.0.0.1:5000/get_employee/${name}`)
        .then(response => response.json())
        .then(response => {
            if(response){
                // Set employeeList state with the response as a json
                setEmployeeList(response)
            } else {
               // Set errorMessage state with the response as a json 
              setErrorMessage(response.Error)
            }
        })
    }
    else{
       setEmployeeList(['No name find...'])
    }
}

Запрос получить 5 последних прибытий или вылетов:

// Define a state to store the 5 last entries
const [employeeList, setEmployeeList] = useState([]);

// Make the request to the API and get the 5 last entries as a json
const searchForLastEntries = () => {
    fetch('http://127.0.0.1:5000/get_5_last_entries')
    .then(response => response.json())
    .then(response => {
        if(response) {
            // Set the value of the employeeList state with the response
            setEmployeeList(response)
        }
    })
}

Запрос добавить сотрудника:

// Create a state to check if the user as been added
const [isUserWellAdded, setIsUserWellAdded] = useState(false);
// Create a state to check if the is error while the user's adding
const [errorWhileAddingUser, seterrorWhileAddingUser] = useState(false);

const addEmployeeToDb = e => {
        e.preventDefault()
        // Send it to backend -> add_employee as a POST request
        let name = document.getElementById("nameOfEmployee").value
        let picture = document.getElementById('employeePictureToSend')

        let formData  = new FormData();

        formData.append("nameOfEmployee", name)
        formData.append("image", picture.files[0])

        fetch('http://127.0.0.1:5000/add_employee',{
            method: 'POST',
            body:  formData,
        })
            .then(reposonse => reposonse.json())
            .then(response => {
                console.log(response)
                setIsUserWellAdded(true)
            })
            .catch(error => seterrorWhileAddingUser(true))
    }

Запросите список получения списка сотрудников и удалите их:

// Create a state to get the list of all the employee's list
const [nameList, setNameList] = useState({});

// Get the list of all the employee's in the folder
const getEmployeeList = () => {
    fetch('http://127.0.0.1:5000/get_employee_list')
        .then(response => response.json())
        .then (response => {
            if(!isEmployeeListLoaded){
                setNameList(response)
                setIsEmployeeListLoaded(true)
            }
        })
}

// A Component to have a button that delete the employye:
const EmployeeItem = props => {
    // Function that send the employee's name to delete
    const deleteEmployee = name => {
        fetch(`http://127.0.0.1:5000/delete_employee/${name}`)
            .then(response => response.json())
            .then(() => setIsEmployeeListLoaded(false))
    }
    return(
        
  • { props.name } deleteEmployee(props.name) }>DELETE
  • ) }

    Теперь вы можете положить камеру перед дверью и мирно выпить свой кофе!

    Отказ от ответственности

    Если вы хотите использовать его в производстве, обязательно уважайте закон вашей страны. И, пожалуйста, попросите людей их согласие перед использованием и храните их имидж.

    Погружение в проект

    Вы можете найти репо здесь.

    Команда, которая создала проект:

    Надеюсь, я был ясен.

    Если у вас есть любой вопрос или предложение об этом, не стесняйтесь вкладывать это в комментарии, или вы можете Прямо свяжитесь со мной по LinkedIn!

    Оригинал: “https://dev.to/graphtylove/how-to-automate-attendance-record-with-face-recognition-python-and-react-4413”