ระบบสแกนใบหน้าด้วย OpenCV และกล้องไอพี

นายณภัทร หอมสมบัตร 011

คณะวิศวกรรมศาสตร์ สาขาวิศวกรรมคอมพิวเตอร์

วิชา : 04-513-201 การโปรแกรมคอมพิวเตอร์ขั้นสูง

1.ความเป็นมา

ในยุคที่เทคโนโลยีและการประมวลผลข้อมูลก้าวหน้าอย่างรวดเร็ว พบว่าการใช้ระบบสแกนใบหน้าเพื่อเข้าระบบและควบคุมการเข้าถึงมีความสำคัญอย่างมากในการปรับปรุงความปลอดภัยและความสะดวกในหลายสถานการณ์ต่างๆ

การแผนและพัฒนาระบบเทคโนโลยีที่สามารถรวมกันเพื่อเพิ่มความสะดวกและความปลอดภัยในชีวิตประจำวันเป็นหนึ่งในทิศทางการพัฒนาเทคโนโลยีที่น่าสนใจที่สุดในปัจจุบัน แม้แต่โทรศัพท์มือถือก็สามารถเข้าถึงเทคโนโลยี Python เป็นภาษาคอมพิวเตอร์ที่มีประสิทธิภาพในการตรวจจับใบหน้าด้วยไลบรารี่ OpenCV และ face_recognition

ด้วยเหตุนี้ ระบบระบบสแกนใบหน้ามีความปลอดภัยและความสะดวกสบายในการใช้งาน

2.วัตถุประสงค์

  1. เพื่อสร้างระบบรักษาความปลอดภัยที่สะดวกสบายการใช้งาน
  2. เพื่อศึกษาการเขียนโปรแกรมภาษา c++ และ Python
  3. เพื่อทำให้ผู้ใช้ได้รับการแจ้งเตือนทันที

3.ขอบเขต

  1. มีการแจ้งเตือนด้วย Line notify
  2. มีการใช้ IP Camera ในการรับมูลภาพส่งไป Python
  3. มีการเชื่อมต่อระหว่าง Python และ ESP32
  4. มีการแสดงผลผ่านจอ LCD ,หลอดไฟ LED และServo Motor

4.ประโยชน์ที่คาดว่าจะได้รับ

  1. ทำให้เกิดความสะดวกในการใช้งานระบบหรือเข้าระบบต่างๆ
  2. ทำให้แจ้งเตือนทันทีแบบ Real Time

5.ความรู้ที่เกี่ยวข้อง

5.1 CV2

OpenCV (Open Source Computer Vision Library) เป็นชุดคลังรหัสซอฟต์แวร์โอเพนซอร์สที่พัฒนาขึ้นเพื่อการประมวลผลภาพและ OpenCV มีความหลากหลายของฟังก์ชันและอัลกอริทึมที่ใช้ในการประมวลผลภาพและวิดีโอ, เช่น การตรวจจับวัตถุ, การระบุใบหน้า, การติดตามวัตถุ, การประมวลผลภาพการยืนยันตัวตน, การประมวลผลวิดีโอ, และมากมายอื่น ๆ

5.3 Face_recognition 

face_recognition เป็นไลบรารีโปรแกรมเชิงซอฟต์แวร์ (software library) ที่ถูกพัฒนาขึ้นเพื่อการจดจำและระบุใบหน้าในรูปภาพโดยใช้การเรียนรู้ของเครื่อง (machine learning) ไลบรารีนี้เป็นไลบรารีโอเพนซอร์ส (open source) และถูกพัฒนาโดยชุมชนนักพัฒนาและนักสนับสนุนทั่วโลก

5.3 socket

Socket ใน Python คือไลบรารี (library) ที่ใช้ในการสร้างและจัดการการเชื่อมต่อเครือข่าย และการสื่อสารผ่านเครือข่ายในโปรแกรม Python ได้อย่างมีประสิทธิภาพ ไลบรารี socket ให้ควบคุมการสื่อสารระหว่างคอมพิวเตอร์หรืออุปกรณ์ในเครือข่าย TCP/IP ซึ่งเป็นโปรโตคอลเครือข่ายพื้นฐานที่ใช้ในการส่งข้อมูลผ่านเครือข่ายอินเทอร์เน็ต

5.4 requests

การใช้ไลบรารี requests ใน Python เพื่อส่งข้อความ Line Notify ทำได้โดยทำการทำร้องขอ HTTP POST ไปยัง API ของ Line Notify ด้วยข้อความที่ต้องการส่ง

5.5 <WiFi.h>

     ไลบรารีที่ใช้ในการเพิ่มและควบคุมการเชื่อมต่อไร้ ใน ESP32 เป็นตัวควบคุมที่สามารถเชื่อมต่อกับเครือข่าย Wi-Fi และใช้ในการสื่อสารแบบไร้สาย ซึ่งมีความหลากหลายในการใช้งาน เช่น การเชื่อมต่อกับเครือข่ายอินเทอร์เน็ต, การส่งข้อมูลผ่านไร้สาย,การควบคุมอุปกรณ์ไร้สายและอื่น ๆ การให้คอมพิวเตอรเป็น Client และ ESP32 เป็น Host ส่งรับเครือข่ายระหว่างกัน

#include <WiFi.h>
const char* ssid = "*********";
const char* pass = "********";
int port = 6969;
bool isConnected = false;
WiFiServer server(port);
WiFiClient client;

5.6 การแสดงผล

การแสดงผลมี 2 อย่างคือ LED จะบอกสถานะWiFi และ กล้อง มีส่วนสำคัญในการพัฒนาและทดสอบระบบการเชื่อมต่อและการทำงานของกล้องและWiFiในโครงงาน จอภาพผลึกเหลวจะใช้ ไลบรารีที่ใช้ในการควบคุมและแสดงข้อมูลบนจอ LCD (Liquid Crystal Display) ที่เชื่อมต่อผ่านสายสื่อสาร I2C

5.7 Servo motor

คืออุปกรณ์ที่ใช้ในการควบคุมการหมุนหรือการเคลื่อนที่ของอะไรบางอย่างในองค์ประกอบอิเล็กทรอนิกส์ จำลองการประตูหรือเข้าระบบของจริงได้

6.ผลการดำเนินการ

Diagramของระบบทั้งหมด

อย่างแรกคือ การเขียนโค้ด Python เขียนการเชื่อมต่อรับข้อมูลภาพจากกล้อง ส่งการแจ้งเตือนไปยัง Line notify และเป็น Client

#ขอบคุณ google และ gpt 3.5 ที่ช่วยผม
import socket
import cv2
import time
import face_recognition
import requests
import os

# Initialize known faces and their encodings
known_face_encodings = []
known_face_names = []

# Load known faces and their encodings from the "known_faces" folder
known_faces_folder = "krit/"

# Loop through the files in the folder
for filename in os.listdir(known_faces_folder):
    if filename.endswith(".jpg"):
        image_path = os.path.join(known_faces_folder, filename)
        image_of_person = face_recognition.load_image_file(image_path)
        face_encoding = face_recognition.face_encodings(image_of_person)[0]
        name = filename.split(".")[0]  # Extract the name from the filename
        known_face_encodings.append(face_encoding)
        known_face_names.append(name)

# Add a new person to the recognition system
new_person_folder = "napat/"

# Loop through the files in the folder
for filename in os.listdir(new_person_folder):
    if filename.endswith(".jpg"):
        image_path = os.path.join(new_person_folder, filename)
        image_of_person = face_recognition.load_image_file(image_path)
        face_encodings = face_recognition.face_encodings(image_of_person)

        if len(face_encodings) > 0:
            # Take the first face encoding (assuming there's only one face in each photo)
            face_encoding = face_encodings[0]

            # Extract the name from the filename (you can name the files as the person's name)
            #name = filename.split(".")[0]

            known_face_encodings.append(face_encoding)
            known_face_names.append("napat")

# Rest of your code remains the same


# Replace with your ESP32's IP address and port
esp32_ip = "xxx.xxx.xxx.xxx"
esp32_port = 6969

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((esp32_ip, esp32_port))
print(f"Connected to ESP32 at {esp32_ip}:{esp32_port}")

cap = cv2.VideoCapture(0)
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

# Line Notify Token - Replace with your actual Line Notify token
line_notify_token = 'kpYRmm3K3qrpd7hkbn7WPtj0Ac5PbgXURP3DTAlplmX'

def send_line_notification(message, image_path=None):
    url = 'https://notify-api.line.me/api/notify'
    headers = {
        'Authorization': f'Bearer {line_notify_token}'
    }
    data = {
        'message': message
    }

    files = None
    if image_path:
        files = {'imageFile': open(image_path, 'rb')}

    response = requests.post(url, headers=headers, data=data, files=files)

    if response.status_code == 200:
        print('Line notification sent successfully')
    else:
        print('Failed to send Line notification')

try:
    matches = []  # Initialize 'matches' outside the loop
    while True:
        ret, frame = cap.read()
        if not ret:
            print("Failed to capture a frame.")
            break

        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5, minSize=(30, 30))

        matches = []  # Reset 'matches' for each frame

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

        face_locations = face_recognition.face_locations(frame)
        face_encodings = face_recognition.face_encodings(frame, face_locations)

        for (x, y, w, h) in faces:
            if face_encodings:
                matches = face_recognition.compare_faces(known_face_encodings, face_encodings[0])
                name = "Unknown"

                if True in matches:
                    first_match_index = matches.index(True)
                    name = known_face_names[first_match_index]

                # Draw the name of the recognized face
                cv2.rectangle(frame, (x, y - 20), (x + w, y), (0, 255, 0), cv2.FILLED)
                font = cv2.FONT_HERSHEY_DUPLEX
                cv2.putText(frame, name, (x + 6, y - 6), font, 0.5, (0, 0, 0), 1)

        cv2.imshow("Face Recognition", frame)

        if True in matches:
            message = "on"
            # Capture a photo and save it
            photo_filename = 'captured_photo.jpg'
            cv2.imwrite(photo_filename, frame)
            # Send Line notification with the photo
            send_line_notification(f'มีคนเข้าระบบ ใบหน้าคือ: {name}', image_path=photo_filename)
        else:
            message = "off"

        s.send(message.encode('utf-8'))

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

        time.sleep(1)  # Add a 1-second delay

    cv2.destroyAllWindows()
    cap.release()
except Exception as e:
    print(f"Error: {e}")
finally:
    s.close()

อย่างต่อมา Ardunio ESP32

#include <WiFi.h>
#include <LiquidCrystal_I2C.h>
#include <ESP32Servo.h>

#define I2C_ADDR 0x27
#define LCD_COLUMNS 16
#define LCD_ROWS 2

LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_ROWS);

Servo myservo;

#define LED_ONE 12
#define LED_TWO 14

const char* ssid = "kranax1150";
const char* pass = "123456789";
int port = 6969;
bool isConnected = false;

WiFiServer server(port);
WiFiClient client;

bool servoIsOpen = false;

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, pass);

  pinMode(LED_ONE, OUTPUT);
  pinMode(LED_TWO, OUTPUT);

  lcd.init();
  lcd.backlight();

  myservo.attach(4);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.println("Connecting...");
    digitalWrite(LED_ONE, HIGH);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Connecting...");
    delay(1200);
    digitalWrite(LED_ONE, LOW);
    lcd.clear();
    lcd.setCursor(0, 1);
    lcd.print("Connecting...");
    delay(1200);
  }

  isConnected = true;
  digitalWrite(LED_TWO, HIGH);
  Serial.print("Server started on IP address: ");
  Serial.println(WiFi.localIP());
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Welcome to COE");
  Serial.print("Port: ");
  Serial.println(port);
  myservo.write(0); // Initialize servo to 0 degrees

  server.begin();
}

void loop() {
  if (WiFi.status() != WL_CONNECTED && isConnected) {
    // WiFi reconnection handling
    Serial.println("WiFi disconnected!");
    isConnected = false;
    digitalWrite(LED_TWO, LOW);

    while (WiFi.status() != WL_CONNECTED) {
      Serial.println("Reconnecting..");
      digitalWrite(LED_ONE, HIGH);
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Reconnecting...");
      delay(500);
      digitalWrite(LED_ONE, LOW);
      lcd.clear();
      lcd.setCursor(0, 1);
      lcd.print("Reconnecting...");
      delay(500);
    }

    isConnected = true;
    Serial.print("Reconnected to WiFi. IP address: ");
    digitalWrite(LED_TWO, HIGH);
    Serial.println(WiFi.localIP());
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Welcome to COE");
  }

  if (client) {
    if (!client.connected()) {
      // Client disconnection handling
      digitalWrite(LED_ONE, LOW);
      lcd.setCursor(0, 1);
      lcd.print("Client fail");
      client.stop(); // Close the disconnected client
      Serial.println("Client disconnected, LED_ONE turned off");

      // Add code to make LED_TWO blink for 0.5 seconds
      digitalWrite(LED_TWO, HIGH);
      delay(500);
      digitalWrite(LED_TWO, LOW);
      Serial.println("LED_TWO blinked for 0.5 seconds");
    } else {
      while (client.available()) {
        String message = client.readStringUntil('\n');
        Serial.print("Received: ");
        Serial.println(message);

        if (message.equals("on")) {
          digitalWrite(LED_ONE, HIGH);
          Serial.println("LED_ONE turned on");

          if (!servoIsOpen) {
            myservo.write(90); // Rotate servo to 90 degrees (open)
            delay(1000); // Wait for 1 second to see the servo position
            servoIsOpen = true;
          }

          lcd.clear();
          lcd.setCursor(0, 1);
          lcd.print("Welcome User");

          for (int i = 0; i <= 4; i++) {
            lcd.setCursor(0, 0);
            lcd.print("Countdown: " + String(i));
            delay(1000);
          }

          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Welcome to COE");
          digitalWrite(LED_ONE, LOW);
          Serial.println("LED_ONE turned off");

          if (servoIsOpen) {
            myservo.write(0); // Rotate servo to 0 degrees (close)
            delay(1000); // Wait for 1 second to see the servo position
            servoIsOpen = false;
          }
        } else if (message.equals("off")) {
          digitalWrite(LED_ONE, LOW);
          Serial.println("LED_ONE turned off");
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Welcome to COE");
        }
      }
    }
  }

  if (!client) {
    client = server.available();
  }
}

การทดลอง

6.1ทดลองความแม่นยำในการระบุใบหน้า

     การควบคุมแม่นยำในการระบุใบหน้าเป็นสิ่งสำคัญในระบบสแกนใบหน้า เพราะมันมีผลต่อความปลอดภัยและประสิทธิภาพของระบบนี้ โดยจะทดลอง 20 ครั้งต่อเนื่อง

6.2. TCP / IP

     TCP/IP (Transmission Control Protocol/Internet Protocol) เป็นชุดข้อกำหนด (protocol suite) ที่ใช้ในการสื่อสารข้อมูลระหว่างคอมพิวเตอร์บนเครือข่ายอินเทอร์เน็ตและเครือข่ายคอมพิวเตอร์อื่น ๆ โดย TCP/IP การที่ไม่ต้อง mqtt ทำให้ได้พบมีวิธีอื่นสื่อสารระหว่างอุปกรณ์ตัวอย่างการเชื่อมอยู่

6.3 การแจ้งเตือน Line notify API ฟรีจาก Line ทำเราสามารถทำระบบแจ้งเตือนได้สบาย

สรุปผลและข้อเสนอแนะ

โมเดลใหม่มีความแม่นยำปานกลางถึงค่อยข้างสูง 50-70% แต่แลกกับความต้องการของประสิทธิภาพคอมพิวเตอร์ที่สูง การเชื่อมต่อที่ไม่ค่อยเสถียร ESP32 มีวิธีคือต้องมีwifi ที่ความเร็วแรงสูง กล้องที่ Delay เพื่อรอEsp32 ประมวลผลทัน Python ส่วน Line notify ทำงานได้ดีที่สุด ไม่มีการผิดพลาด

    โมเดลเก่ามีความแม่นต่ำ 25-50% ทำให้ความต้องคอมพิวเตอร์ไม่สูง สาเหตุฐานข้อมูลที่น้อยทำให้มีความสูงประมวลผลสูง และ Line notify ทำงานได้ดีที่สุด เหมือนเดิม

เอกสารอ้างอิง

Chat Gpt 3.5 เว็บไซต์แชทบอทจาก OpenAI [สืบค้นวันที่ 1 พฤษจิกายน 2566] https://chat.openai.com

An approach for Face Detection and Face Recognition using OpenCV and Face Recognition Libraries in Python

Ainampudi Kumari Sirivarshitha; Kadavakollu Sravani; Kothamasu Santhi Priya; Vasantha Bhavani[สืบค้นวันที่ 25 ตุลาคม 2566] https://ieeexplore.ieee.org/document/10113066

OpenCV & Python | Computer Vision สำหรับผู้เริ่มต้น [FULL COURSE] [สืบค้นวันที่ 20 ตุลาคม 2566] https://www.youtube.com/watch?v=fLDJJXEykvo

face-recognition 1.3.0 License: MIT License (MIT license )Author Adam Geitgey] [สืบค้นวันที่ 20 ตุลาคม 2566]  https://pypi.org/project/face-recognition/

วิดีโอนำเสนอการทำงาน

You may also like...

ใส่ความเห็น

อีเมลของคุณจะไม่แสดงให้คนอื่นเห็น ช่องข้อมูลจำเป็นถูกทำเครื่องหมาย *