Assalamualaikum, jumpa lagi di triyonos.com dengan tutorial-tutorial pemrogramannya yang menarik untuk dipelajari. Alhamdulillahi rabbil 'alamin, akhirnya saya bisa menyelesaikan tutorial pembuatan aplikasi face recognition sederhana ini. Aplikasi ini dibuat menggunakan OpenCV, Flask dan database MySQL di dalam Pycharm IDE.

Mirip-mirip dengan tutorial OpenCV yang sudah saya buat sebelum ini mengenai face detection, di sini saya tidak akan menerangkan detail tahapan pengkodingannya, melainkan hanya menerangkan cara instalasi packages yang diperlukan, download file-file yang dibutuhkan, pembuatan database dan copy paste program utamanya. Silahkan pelajari sendiri yaa kodingannya.

Aplikasi yang saya buat ini terdiri dari 4 halaman yaitu:

  1. Halaman Home (index).

    Merupakan halaman pertama yang akan tampil ketika aplikasi running. Halaman ini menampilkan daftar personil triyonos.com, serta tombol Add Personnel untuk melakukan input penambahan data personil dan tombol Face Recognition untuk menampilkan layar web cam face recognition.

    home page face recognition
  2. Halaman Add Personnel

    Halaman ini tampil setelah tombol Add Personnel diklik untuk melakukan penginputan data personil.

    add personnel page
  3. Halaman Generate Dataset

    Halaman ini tampil setelah tombol Next di halaman Add Personnel diklik. Aplikasi akan mengaktifkan web cam untuk mengambil foto wajah personil dan merekamnya sebagai dataset image. Aplikasi akan menggenerate 100 foto wajah, ditandai dengan counter yang dimulai dari angka 1 dan selesai di angka 100.

    generate dataset

    Setelah berhenti merekam (counter 100). User harus mengklik tombol Training untuk men-train dataset wajah dan menggenerate file classifier.xml.

  4. Halaman face recognition

    Halaman ini tampil jika tombol Face Recognition di halaman Home diklik.

    face recognition page

Adapun langkah-langkah pembuatan aplikasi ini saya bagi menjadi 4 bagian yaitu:

  1. Create database MySQL
  2. Create Pycharm Project and Install Packages
  3. Download file-file pendukung
  4. Copy paste script Python

Proses Pembuatan Aplikasi Web Face Recognition

1. Create database MySQL

Saya akan membuat database MySQL dengan nama flask_db melalui phpMyAdmin. PhpMyAdmin ini merupakan bagian dari XAMPP. Jika komputer teman-teman belum terinstall XAMPP, bisa ikuti panduan instalasinya di tutorial Cara Install XAMPP Versi 7 di Windows 10.

Buka phpMyAdmin melalui Mozilla Firefox lalu Create database flask_db.

create flask_db

Setelah berhasil membuat database flask_db, copy script SQL di bawah ini untuk membuat tabel master personil prs_mstr dan tabel image dataset img_dataset.

CREATE TABLE `img_dataset` (
  `img_id` int(11) NOT NULL,
  `img_person` varchar(3) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE `prs_mstr` (
  `prs_nbr` varchar(3) NOT NULL,
  `prs_name` varchar(50) NOT NULL,
  `prs_skill` varchar(30) NOT NULL,
  `prs_active` varchar(1) NOT NULL DEFAULT 'Y',
  `prs_added` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `img_dataset`
  ADD PRIMARY KEY (`img_id`);

ALTER TABLE `prs_mstr`
  ADD PRIMARY KEY (`prs_nbr`);

            

Kemudian ikuti langkah-langkah seperti pada gambar berikut:

flask_db create table

Tabel prs_mstr dan img_dataset berhasil dibuat.

table created

2. Create Pycharm Project and Install Packages

Create new project pada Pycharm IDE kemudian beri nama project FlaskOpencv_FaceRecognition. Setelah itu klik tombol Create

new pycharm project

Tampilkan menu Setting dengan cara klik File Settings... Kemudian arahkan ke sub menu Python Interpreter.

settings

Klik icon plus untuk menampilkan jendela Available Packages dan install package-package yang dibutuhkan dalam project ini.

packages installation

Package-package yang harus diinstall untuk project face recognition ini antara lain:

  1. Flask
  2. mysql-connector
  3. opencv-python
  4. opencv-contrib-python
  5. Pillow

NB : Harus sama persis yaa...

Jika tidak ada error untuk instalasi package-package di atas maka hasilnya akan seperti berikut ini:

packages installed

3. Download File-file Pendukung

Untuk mempersingkat pembahasan tutorial ini, saya sudah buatkan zip file untuk kemudian di-extract ke dalam folder root project Pycharm FlaskOpencv_FaceRecognition ini.

Silakan klik link faceRecognition_files.zip ini untuk mendownloadnya.

Setelah didownload, lakukan Extract Here... file zip nya.

download and extract zip

Dobel klik folder faceRecognition_files. Terdapat 4 folder untuk saya copy ke dalam folder root Pycharm project.

face recognition files

Drag and drop semua folder ke folder root.

drag and drop all folders

Akan muncul dialog konfirmasi Move folder. Jika To Directory nya sudah benar, langsung klik tombol Refactor.

move confirm

Maka hasilnya akan seperti ini:

folders structure

4. Koding Python

Buat file python baru di dalam folder root dengan nama app.py.

app.py

Copy script code python di bawah ini.

from flask import Flask, render_template, request, redirect, url_for, Response
import mysql.connector
import cv2
from PIL import Image
import numpy as np
import os

app = Flask(__name__)

mydb = mysql.connector.connect(
    host="localhost",
    user="root",
    passwd="",
    database="flask_db"
)
mycursor = mydb.cursor()


# <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Generate dataset >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def generate_dataset(nbr):
    face_classifier = cv2.CascadeClassifier("C:/Users/Erik/PycharmProjects/FlaskOpencv_FaceRecognition/resources/haarcascade_frontalface_default.xml")

    def face_cropped(img):
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        faces = face_classifier.detectMultiScale(gray, 1.3, 5)
        # scaling factor=1.3
        # Minimum neighbor = 5

        if faces is ():
            return None
        for (x, y, w, h) in faces:
            cropped_face = img[y:y + h, x:x + w]
        return cropped_face

    cap = cv2.VideoCapture(0)

    mycursor.execute("select ifnull(max(img_id), 0) from img_dataset")
    row = mycursor.fetchone()
    lastid = row[0]

    img_id = lastid
    max_imgid = img_id + 100
    count_img = 0

    while True:
        ret, img = cap.read()
        if face_cropped(img) is not None:
            count_img += 1
            img_id += 1
            face = cv2.resize(face_cropped(img), (200, 200))
            face = cv2.cvtColor(face, cv2.COLOR_BGR2GRAY)

            file_name_path = "dataset/"+nbr+"."+ str(img_id) + ".jpg"
            cv2.imwrite(file_name_path, face)
            cv2.putText(face, str(count_img), (50, 50), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 2)

            mycursor.execute("""INSERT INTO `img_dataset` (`img_id`, `img_person`) VALUES
                                ('{}', '{}')""".format(img_id, nbr))
            mydb.commit()

            frame = cv2.imencode('.jpg', face)[1].tobytes()
            yield (b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')

            if cv2.waitKey(1) == 13 or int(img_id) == int(max_imgid):
                break
                cap.release()
                cv2.destroyAllWindows()


# <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Train Classifier >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
@app.route('/train_classifier/<nbr>')
def train_classifier(nbr):
    dataset_dir = "C:/Users/Erik/PycharmProjects/FlaskOpencv_FaceRecognition/dataset"

    path = [os.path.join(dataset_dir, f) for f in os.listdir(dataset_dir)]
    faces = []
    ids = []

    for image in path:
        img = Image.open(image).convert('L');
        imageNp = np.array(img, 'uint8')
        id = int(os.path.split(image)[1].split(".")[1])

        faces.append(imageNp)
        ids.append(id)
    ids = np.array(ids)

    # Train the classifier and save
    clf = cv2.face.LBPHFaceRecognizer_create()
    clf.train(faces, ids)
    clf.write("classifier.xml")

    return redirect('/')


# <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Face Recognition >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def face_recognition():  # generate frame by frame from camera
    def draw_boundary(img, classifier, scaleFactor, minNeighbors, color, text, clf):
        gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        features = classifier.detectMultiScale(gray_image, scaleFactor, minNeighbors)

        coords = []

        for (x, y, w, h) in features:
            cv2.rectangle(img, (x, y), (x + w, y + h), color, 2)
            id, pred = clf.predict(gray_image[y:y + h, x:x + w])
            confidence = int(100 * (1 - pred / 300))

            mycursor.execute("select b.prs_name "
                             "  from img_dataset a "
                             "  left join prs_mstr b on a.img_person = b.prs_nbr "
                             " where img_id = " + str(id))
            s = mycursor.fetchone()
            s = '' + ''.join(s)

            if confidence > 70:
                cv2.putText(img, s, (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 1, cv2.LINE_AA)
            else:
                cv2.putText(img, "UNKNOWN", (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 1, cv2.LINE_AA)

            coords = [x, y, w, h]
        return coords

    def recognize(img, clf, faceCascade):
        coords = draw_boundary(img, faceCascade, 1.1, 10, (255, 255, 0), "Face", clf)
        return img

    faceCascade = cv2.CascadeClassifier("C:/Users/Erik/PycharmProjects/FlaskOpencv_FaceRecognition/resources/haarcascade_frontalface_default.xml")
    clf = cv2.face.LBPHFaceRecognizer_create()
    clf.read("classifier.xml")

    wCam, hCam = 500, 400

    cap = cv2.VideoCapture(0)
    cap.set(3, wCam)
    cap.set(4, hCam)

    while True:
        ret, img = cap.read()
        img = recognize(img, clf, faceCascade)

        frame = cv2.imencode('.jpg', img)[1].tobytes()
        yield (b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')

        key = cv2.waitKey(1)
        if key == 27:
            break


@app.route('/')
def home():
    mycursor.execute("select prs_nbr, prs_name, prs_skill, prs_active, prs_added from prs_mstr")
    data = mycursor.fetchall()

    return render_template('index.html', data=data)

@app.route('/addprsn')
def addprsn():
    mycursor.execute("select ifnull(max(prs_nbr) + 1, 101) from prs_mstr")
    row = mycursor.fetchone()
    nbr = row[0]
    # print(int(nbr))

    return render_template('addprsn.html', newnbr=int(nbr))

@app.route('/addprsn_submit', methods=['POST'])
def addprsn_submit():
    prsnbr = request.form.get('txtnbr')
    prsname = request.form.get('txtname')
    prsskill = request.form.get('optskill')

    mycursor.execute("""INSERT INTO `prs_mstr` (`prs_nbr`, `prs_name`, `prs_skill`) VALUES
                    ('{}', '{}', '{}')""".format(prsnbr, prsname, prsskill))
    mydb.commit()

    # return redirect(url_for('home'))
    return redirect(url_for('vfdataset_page', prs=prsnbr))

@app.route('/vfdataset_page/<prs>')
def vfdataset_page(prs):
    return render_template('gendataset.html', prs=prs)

@app.route('/vidfeed_dataset/<nbr>')
def vidfeed_dataset(nbr):
    #Video streaming route. Put this in the src attribute of an img tag
    return Response(generate_dataset(nbr), mimetype='multipart/x-mixed-replace; boundary=frame')

@app.route('/video_feed')
def video_feed():
    # Video streaming route. Put this in the src attribute of an img tag
    return Response(face_recognition(), mimetype='multipart/x-mixed-replace; boundary=frame')

@app.route('/fr_page')
def fr_page():
    return render_template('fr_page.html')

if __name__ == "__main__":
    app.run(host='127.0.0.1', port=5000, debug=True)

            

Struktur folder dan file akhir setelah ditambahkan file app.py.

app.py


Kalau ada pertanyaan silakan comment vidio ini di youtube ya, syaratnya harus subscribe terlebih dahulu 😃