kevin před 2 roky
rodič
revize
bb3b40f722
4 změnil soubory, kde provedl 480 přidání a 112 odebrání
  1. 2 0
      .gitignore
  2. 82 71
      face_recognition_svm.py
  3. 226 41
      fr_flask.py
  4. 170 0
      fr_flask_0.py

+ 2 - 0
.gitignore

@@ -58,3 +58,5 @@ docs/_build/
 # PyBuilder
 target/
 
+/lfw.tgz
+/lfw/

+ 82 - 71
face_recognition_svm.py

@@ -14,45 +14,44 @@ encodings = []
 names = []
 tuples = []
 train_list = []
-lock = None
 model_name = 'saved_model_2.pkl'
-known_people_folder = os.path.join('application_data', 'verification_images')
+# known_people_folder = os.path.join('application_data', 'verification_images')
 face_model = "large"
 if face_model == "large":
     model_name = 'saved_model_2_large.pkl'
 
-dummy_data = [
-    {
-        "name": "Bayu",
-        "address": "299 St Louis Road Oak Forest, IL 60452",
-        "nik": "1000076456784631"
-    },
-    {
-        "name": "Dio",
-        "address": "22 Whitemarsh St. Mansfield, MA 02048",
-        "nik": "1000024792887549"
-    },
-    {
-        "name": "Hadi",
-        "address": "643 Honey Creek Dr. Milledgeville, GA 31061",
-        "nik": "1000038502830420"
-    },
-    {
-        "name": "Kevin",
-        "address": "881 Cooper Ave. Hummelstown, PA 17036",
-        "nik": "1000045356476664"
-    },
-    {
-        "name": "Matrix",
-        "address": "580 Glenwood Dr. Garner, NC 27529",
-        "nik": "1000023452134598"
-    },
-    {
-        "name": "Surya",
-        "address": "909 South St Paul Street Hopewell, VA 23860",
-        "nik": "1000075656784734"
-    },
-]
+# dummy_data = [
+#     {
+#         "name": "Bayu",
+#         "address": "299 St Louis Road Oak Forest, IL 60452",
+#         "nik": "1000076456784631"
+#     },
+#     {
+#         "name": "Dio",
+#         "address": "22 Whitemarsh St. Mansfield, MA 02048",
+#         "nik": "1000024792887549"
+#     },
+#     {
+#         "name": "Hadi",
+#         "address": "643 Honey Creek Dr. Milledgeville, GA 31061",
+#         "nik": "1000038502830420"
+#     },
+#     {
+#         "name": "Kevin",
+#         "address": "881 Cooper Ave. Hummelstown, PA 17036",
+#         "nik": "1000045356476664"
+#     },
+#     {
+#         "name": "Matrix",
+#         "address": "580 Glenwood Dr. Garner, NC 27529",
+#         "nik": "1000023452134598"
+#     },
+#     {
+#         "name": "Surya",
+#         "address": "909 South St Paul Street Hopewell, VA 23860",
+#         "nik": "1000075656784734"
+#     },
+# ]
 
 
 def scan_known_people(known_people_folder):
@@ -81,17 +80,17 @@ def image_files_in_folder(folder):
     return img_list
 
 
-known_faces = scan_known_people(known_people_folder)
+# known_faces = scan_known_people(known_people_folder)
 
-is_train = False
-
-if not is_train:
-    try:
-        clf = joblib.load(model_name)
-    except:
-        clf = None
-    if clf is None:
-        is_train = True
+# is_train = True
+#
+# if not is_train:
+#     try:
+#         clf = joblib.load(model_name)
+#     except:
+#         clf = None
+#     if clf is None:
+#         is_train = True
 
 
 def train_image(image, person):
@@ -106,13 +105,21 @@ def train_image(image, person):
     else:
         print(image + " was skipped and can't be used for training")
 
-
-if is_train:
-    # Training directory
+def train_svm(model_name):
     train_str = os.path.join('data', 'train')
     train_dir = os.listdir(os.path.join('data', 'train'))
     train_dir.sort()
 
+    # for person in train_dir:
+    #     pix_str = os.path.join(train_str, person)
+    #     pix = os.listdir(os.path.join(train_str, person))
+    #
+    #     # Loop through each training image for the current person
+    #     for person_img in pix:
+    #         # Get the face encodings for the face in each image file
+    #         image = os.path.join(pix_str, person_img)
+    #         train_image(image, person)
+
     # Loop through each person in the training directory
     with concurrent.futures.ThreadPoolExecutor() as executor:
         for person in train_dir:
@@ -133,33 +140,37 @@ if is_train:
     clf = svm.SVC(gamma='scale', probability=True)
     clf.fit(encodings, names)
     joblib.dump(clf, model_name)
+    return 0
+
+if __name__ == '__main__':
+    train_svm(model_name)
 
 # Load the test image with unknown faces into a numpy array
-test_image = face_recognition.load_image_file(os.path.join('application_data', 'input_image', 'input_image.jpg'))
+# test_image = face_recognition.load_image_file(os.path.join('application_data', 'input_image', 'input_image.jpg'))
 
 # Find all the faces in the test image using the default HOG-based model
-face_locations = face_recognition.face_locations(test_image)
-no = len(face_locations)
-print("Number of faces detected: ", no)
+# face_locations = face_recognition.face_locations(test_image)
+# no = len(face_locations)
+# print("Number of faces detected: ", no)
 
 # Predict all the faces in the test image using the trained classifier
-print("Found:")
-for i in range(no):
-    test_image_enc = face_recognition.face_encodings(test_image, model=face_model)[i]
-    start_time = time.perf_counter_ns()
-    proba_list = clf.predict_proba([test_image_enc])
-    dist = face_recognition.face_distance(known_faces, test_image_enc)
-    total = np.subtract(proba_list, dist)
-    end_time = time.perf_counter_ns()
-    process_time = end_time - start_time
-    classes = clf.classes_
-    print(classes)
-    print(total)
-    i = np.argmax(total)
-    proba = list(*proba_list)
-    name = dummy_data[i]["name"]
-    print(name, "{:.2f}".format(proba[i]))
-    print(proba)
-    print(list(dist))
-    print(list(*total))
-    print(process_time)
+# print("Found:")
+# for i in range(no):
+#     test_image_enc = face_recognition.face_encodings(test_image, model=face_model)[i]
+#     start_time = time.perf_counter_ns()
+#     proba_list = clf.predict_proba([test_image_enc])
+#     dist = face_recognition.face_distance(known_faces, test_image_enc)
+#     total = np.subtract(proba_list, dist)
+#     end_time = time.perf_counter_ns()
+#     process_time = end_time - start_time
+#     classes = clf.classes_
+#     print(classes)
+#     print(total)
+#     i = np.argmax(total)
+#     proba = list(*proba_list)
+#     name = dummy_data[i]["name"]
+#     print(name, "{:.2f}".format(proba[i]))
+#     print(proba)
+#     print(list(dist))
+#     print(list(*total))
+#     print(process_time)

+ 226 - 41
fr_flask.py

@@ -1,4 +1,4 @@
-from PIL import ImageFile
+from PIL import ImageFile, Image
 from flask import Flask, request, jsonify
 import face_recognition
 import base64
@@ -8,6 +8,10 @@ import numpy as np
 import re
 import os
 import time
+import mysql.connector
+import shlex
+import subprocess
+from face_recognition_svm import train_svm
 
 ImageFile.SAFEBLOCK = 2048 * 2048
 
@@ -15,46 +19,56 @@ app = Flask(__name__)
 model_file_name = "saved_model_2.pkl"
 clf = None
 classes = None
-dummy_data = [
-    {
-        "name": "Bayu",
-        "address": "299 St Louis Road Oak Forest, IL 60452",
-        "nik": "1000076456784631"
-    },
-    {
-        "name": "Dio",
-        "address": "22 Whitemarsh St. Mansfield, MA 02048",
-        "nik": "1000024792887549"
-    },
-    {
-        "name": "Hadi",
-        "address": "643 Honey Creek Dr. Milledgeville, GA 31061",
-        "nik": "1000038502830420"
-    },
-    {
-        "name": "Kevin",
-        "address": "881 Cooper Ave. Hummelstown, PA 17036",
-        "nik": "1000045356476664"
-    },
-    {
-        "name": "Matrix",
-        "address": "580 Glenwood Dr. Garner, NC 27529",
-        "nik": "1000023452134598"
-    },
-    {
-        "name": "Surya",
-        "address": "909 South St Paul Street Hopewell, VA 23860",
-        "nik": "1000075656784734"
-    },
-]
+ids = []
+# dummy_data = [
+#     {
+#         "name": "Bayu",
+#         "address": "299 St Louis Road Oak Forest, IL 60452",
+#         "nik": "1000076456784631"
+#     },
+#     {
+#         "name": "Dio",
+#         "address": "22 Whitemarsh St. Mansfield, MA 02048",
+#         "nik": "1000024792887549"
+#     },
+#     {
+#         "name": "Hadi",
+#         "address": "643 Honey Creek Dr. Milledgeville, GA 31061",
+#         "nik": "1000038502830420"
+#     },
+#     {
+#         "name": "Kevin",
+#         "address": "881 Cooper Ave. Hummelstown, PA 17036",
+#         "nik": "1000045356476664"
+#     },
+#     {
+#         "name": "Matrix",
+#         "address": "580 Glenwood Dr. Garner, NC 27529",
+#         "nik": "1000023452134598"
+#     },
+#     {
+#         "name": "Surya",
+#         "address": "909 South St Paul Street Hopewell, VA 23860",
+#         "nik": "1000075656784734"
+#     },
+# ]
 ssl = None
 known_people = "application_data/verification_images"
 known_faces = []
-total_threshold = 0.2
+total_threshold = 0.1
 face_model = "large"
 if face_model == "large":
     model_file_name = "saved_model_2_large.pkl"
 
+TRAINING_FOLDER = os.path.join("data","train")
+PROFILE_FOLDER = os.path.join("application_data", "verification_images")
+app.config["TRAINING_FOLDER"] = TRAINING_FOLDER
+app.config["PROFILE_FOLDER"] = PROFILE_FOLDER
+
+db_user = "facer"
+db_pass = "9Y6Bqg3JwQxXa"
+
+db = mysql.connector.connect(user=db_user, password=db_pass, unix_socket="/opt/lampp/var/mysql/mysql.sock", database='face_recognition')
 
 def scan_known_people(known_people_folder):
     known_face_encodings = []
@@ -62,10 +76,8 @@ def scan_known_people(known_people_folder):
     for file in image_files_in_folder(known_people_folder):
         img = face_recognition.load_image_file(file)
         encodings = face_recognition.face_encodings(img, model=face_model)
-
         if len(encodings) > 1:
             print("WARNING: More than one face found in {}. Only considering the first face.".format(file))
-
         if len(encodings) == 0:
             print("WARNING: No faces found in {}. Ignoring file.".format(file))
         else:
@@ -80,6 +92,149 @@ def image_files_in_folder(folder):
     img_list.sort()
     return img_list
 
+def load_db(id):
+    db = mysql.connector.connect(user=db_user, password=db_pass, unix_socket="/opt/lampp/var/mysql/mysql.sock",
+                                 database='face_recognition')
+    cursor = db.cursor()
+    result = {"name": "Unknown", "address": "", "nik": ""}
+    try:
+        query = "SELECT `NIK`, `NAME`, `ADDRESS` FROM `face_recognition` WHERE `ID` = {}".format(id)
+        cursor.execute(query)
+        for (nik, name, address) in cursor:
+            result['nik'] = nik
+            result['name'] = name
+            result['address'] = address
+    finally:
+        cursor.close()
+        db.close()
+    return result
+
+def save_db(nik, name, address):
+    db = mysql.connector.connect(user=db_user, password=db_pass, unix_socket="/opt/lampp/var/mysql/mysql.sock",
+                                 database='face_recognition')
+    id = None
+    cursor = db.cursor()
+    try:
+        query = 'INSERT INTO `face_recognition` (`NIK`, `NAME`, `ADDRESS`) VALUES ("{}", "{}", "{}")'.format(nik,name,address)
+        cursor.execute(query)
+        db.commit()
+        id = cursor.lastrowid
+    finally:
+        cursor.close()
+        db.close()
+    return id
+
+def get_face(image, crop=False):
+    max_height = image.height
+    max_width = image.width
+    profile_nparray = np.asarray(image)
+    profile_face_loc = face_recognition.face_locations(profile_nparray)
+    profile_len = len(profile_face_loc)
+    if profile_len >= 1:
+        if crop:
+            top = profile_face_loc[0][0]
+            right = profile_face_loc[0][1]
+            bottom = profile_face_loc[0][2]
+            left = profile_face_loc[0][3]
+            width = right - left
+            height = bottom - top
+            center_x = int(left + width / 2)
+            center_y = int(top + height / 2)
+            calc_new_width = min(int(width * 2), (max_width - center_x) * 2, abs((0 - center_x) * 2))
+            calc_new_height = min(int(height * 2), (max_height - center_y) * 2, abs((0 - center_y) * 2))
+            new_size = min(calc_new_height, calc_new_width)
+            new_top = int(center_y - new_size / 2)
+            new_right = int(center_x + new_size / 2)
+            new_bottom = int(center_y + new_size / 2)
+            new_left = int(center_x - new_size / 2)
+            cropped = image.crop((new_left, new_top, new_right, new_bottom))
+            resized = cropped.resize((250, 250))
+        else:
+            resized = image.resize((250,250))
+        return resized
+    return None
+
+@app.route('/',methods=['GET', 'POST'])
+def test():
+    return jsonify({"status" : "0"})
+
+@app.route('/upload', methods=['POST'])
+def upload():
+    try:
+        profile = request.files["profile"]
+        nik = request.form["nik"]
+        name = request.form["name"]
+        address = request.form["address"]
+        training = []
+        print(len(request.files))
+        if 'training' in request.files:
+            training = request.files.getlist("training")
+        elif 'training[]' in request.files:
+            training = request.files.getlist("training[]")
+        else:
+            files_length = len(request.files)
+            training_names = [f'training{x}' for x in range(files_length-1)]
+            for x in training_names:
+                training.append(request.files[x])
+        print(training)
+        print(len(training))
+        if not training:
+            return jsonify({"status": "2", "message": "Training files not exist"})
+        profile_image = Image.open(profile.stream)
+        profile_image.load()
+        new_profile_image = get_face(profile_image)
+        if not new_profile_image:
+            return jsonify({"status": "3", "message": "Profile face not found, please upload a different picture"})
+        detected_training = []
+        detected_training_fn = []
+        for file in training:
+            training_image = Image.open(file.stream)
+            new_training_image = get_face(training_image)
+            if new_training_image:
+                detected_training.append(new_training_image)
+                detected_training_fn.append(file.filename)
+        if not detected_training:
+            return jsonify({"status": "4", "message": "No face found on any training images, please upload a different picture"})
+        print(detected_training)
+        print(detected_training_fn)
+        # Save
+        id = save_db(nik, name, address)
+        print(id)
+        if not id:
+            return jsonify({"status": "1", "message": "Error uploading data, please try again"})
+        new_profile_image.save(os.path.join(app.config["PROFILE_FOLDER"], f'{id}.jpg'))
+        id_dir = os.path.join(app.config['TRAINING_FOLDER'], str(id))
+        if not os.path.exists(id_dir):
+            os.mkdir(id_dir)
+        for (image, filename) in zip(detected_training, detected_training_fn):
+            image.save(os.path.join(app.config['TRAINING_FOLDER'], str(id), filename))
+        return jsonify({"status": "0", "message": "Upload successful"})
+    except Exception as exc:
+        return jsonify({"status": "1", "message": f"Error uploading data, please try again | {exc}"})
+
+@app.route('/train', methods=['GET', 'POST'])
+def train():
+    try:
+        train_svm(model_file_name)
+        return jsonify({"status": "0", "message": "Train successful"})
+    except Exception as exc:
+        return jsonify({"status": "1", "message": f"Error training model: {exc}"})
+
+@app.route('/reload', methods=['GET', 'POST'])
+def face_reload():
+    pid = None
+    try:
+        with open("app.pid","r") as f:
+            pid = f.readline()
+        if pid:
+            cmd = f"kill -s HUP {pid}"
+            cmd_array = shlex.split(cmd)
+            print(cmd_array)
+            p = subprocess.Popen(cmd_array, start_new_session=True)
+        else:
+            return jsonify({"status": "1", "message": f"Reload unsucessful"})
+    except Exception as exc:
+        return jsonify({"status": "2", "message": f"Reload unsucessful: {exc}"})
 
 @app.route('/predict', methods=['POST'])
 def predict():
@@ -106,12 +261,24 @@ def predict():
             total = np.subtract(proba_list, dist)
             i = np.argmax(total)
             proba = list(*proba_list)[i]
-            name = dummy_data[i]["name"]
-            address = dummy_data[i]["address"]
-            nik = dummy_data[i]["nik"]
+            face_id = ids[i]
+            data = load_db(face_id)
+            name = data["name"]
+            address = data["address"]
+            nik = data["nik"]
+            print("total threshold: ", total_threshold)
+            print("total: ", total[0][i])
+            print({
+                "id": str(face_id),
+                "name": name,
+                "address": address,
+                "nik": nik,
+                "proba": proba,
+                "delta": total[0][i]
+            })
             if total[0][i] > total_threshold:
                 js = {
-                    "id": str(i),
+                    "id": str(face_id),
                     "name": name,
                     "address": address,
                     "nik": nik,
@@ -120,17 +287,22 @@ def predict():
                 }
             else:
                 js = {
-                    "id": -1,
+                    "id": "-1",
                     "name": "Unknown",
                     "address": "",
                     "nik": "",
                     "proba": 0.0,
                     "delta": 0.0
                 }
+            print(total[0][i] > total_threshold)
+            print(not result)
+            print(i == no - 1)
+            print((not result and i == no - 1))
             if total[0][i] > total_threshold or (not result and i == no - 1):
                 result.append(js)
             end_time = time.perf_counter()
             process_time = end_time - start_time
+            print(time.strftime("%c"))
             print(total[0])
             print("Process time:", process_time, "s")
     print(result)
@@ -142,6 +314,19 @@ try:
     print('model loaded')
     known_faces = scan_known_people(known_people)
     print('known faces scanned')
+    db = mysql.connector.connect(user=db_user, password=db_pass, unix_socket="/opt/lampp/var/mysql/mysql.sock",
+                                 database='face_recognition')
+    cursor = db.cursor()
+    result = {"name": "Unknown", "address": "", "nik": ""}
+    try:
+        query = "SELECT `ID` FROM `face_recognition` ORDER BY `ID`"
+        cursor.execute(query)
+        for id in cursor:
+            ids.append(id[0])
+    finally:
+        cursor.close()
+        db.close()
+    print("ids: ",ids)
 
 except FileNotFoundError as e:
     print('No model here')

+ 170 - 0
fr_flask_0.py

@@ -0,0 +1,170 @@
+from PIL import ImageFile
+from flask import Flask, request, jsonify
+import face_recognition
+import base64
+from io import BytesIO
+import joblib
+import numpy as np
+import re
+import os
+import time
+
+ImageFile.SAFEBLOCK = 2048 * 2048
+
+app = Flask(__name__)
+model_file_name = "saved_model_2.pkl"
+clf = None
+classes = None
+dummy_data = [
+    {
+        "name": "Bayu",
+        "address": "299 St Louis Road Oak Forest, IL 60452",
+        "nik": "1000076456784631"
+    },
+    {
+        "name": "Dio",
+        "address": "22 Whitemarsh St. Mansfield, MA 02048",
+        "nik": "1000024792887549"
+    },
+    {
+        "name": "Hadi",
+        "address": "643 Honey Creek Dr. Milledgeville, GA 31061",
+        "nik": "1000038502830420"
+    },
+    {
+        "name": "Kevin",
+        "address": "881 Cooper Ave. Hummelstown, PA 17036",
+        "nik": "1000045356476664"
+    },
+    {
+        "name": "Matrix",
+        "address": "580 Glenwood Dr. Garner, NC 27529",
+        "nik": "1000023452134598"
+    },
+    {
+        "name": "Surya",
+        "address": "909 South St Paul Street Hopewell, VA 23860",
+        "nik": "1000075656784734"
+    },
+]
+ssl = None
+known_people = "application_data/verification_images"
+known_faces = []
+total_threshold = 0.2
+face_model = "large"
+if face_model == "large":
+    model_file_name = "saved_model_2_large.pkl"
+
+UPLOAD_FOLDER = ""
+
+
+def scan_known_people(known_people_folder):
+    known_face_encodings = []
+
+    for file in image_files_in_folder(known_people_folder):
+        img = face_recognition.load_image_file(file)
+        encodings = face_recognition.face_encodings(img, model=face_model)
+
+        if len(encodings) > 1:
+            print("WARNING: More than one face found in {}. Only considering the first face.".format(file))
+
+        if len(encodings) == 0:
+            print("WARNING: No faces found in {}. Ignoring file.".format(file))
+        else:
+            known_face_encodings.append(encodings[0])
+
+    return known_face_encodings
+
+
+def image_files_in_folder(folder):
+    img_list = [os.path.join(folder, f) for f in os.listdir(folder) if
+                re.match(r'.*\.(jpg|jpeg|png|webp)', f, flags=re.I)]
+    img_list.sort()
+    return img_list
+
+def load_db():
+    pass
+
+def save_db(name, address, nik):
+    pass
+
+@app.route('/upload', methods=['POST'])
+def upload():
+    profile = request.files["profile"]
+    nik = request.form["nik"]
+    name = request.form["name"]
+    address = request.form["address"]
+
+
+
+
+@app.route('/predict', methods=['POST'])
+def predict():
+    result = []
+    if "image" in request.json:
+        im_b64 = request.json["image"]
+    elif "image" in request.files:
+        im_b64 = request.files["image"]
+    elif "image" in request.form:
+        im_b64 = request.form["image"]
+    else:
+        return {"error": "Error reading image"}
+    im_bytes = base64.b64decode(im_b64)
+    im_file = BytesIO(im_bytes)
+    test_image = face_recognition.load_image_file(im_file)
+    face_locations = face_recognition.face_locations(test_image)
+    no = len(face_locations)
+    if no > 0:
+        for i in range(no):
+            start_time = time.perf_counter()
+            test_image_enc = face_recognition.face_encodings(test_image, model=face_model)[i]
+            proba_list = clf.predict_proba([test_image_enc])
+            dist = face_recognition.face_distance(known_faces, test_image_enc)
+            total = np.subtract(proba_list, dist)
+            i = np.argmax(total)
+            proba = list(*proba_list)[i]
+            name = dummy_data[i]["name"]
+            address = dummy_data[i]["address"]
+            nik = dummy_data[i]["nik"]
+            if total[0][i] > total_threshold:
+                js = {
+                    "id": str(i),
+                    "name": name,
+                    "address": address,
+                    "nik": nik,
+                    "proba": proba,
+                    "delta": total[0][i]
+                }
+            else:
+                js = {
+                    "id": "-1",
+                    "name": "Unknown",
+                    "address": "",
+                    "nik": "",
+                    "proba": 0.0,
+                    "delta": 0.0
+                }
+            if total[0][i] > total_threshold or (not result and i == no - 1):
+                result.append(js)
+            end_time = time.perf_counter()
+            process_time = end_time - start_time
+            print(time.strftime("%c"))
+            print(total[0])
+            print("Process time:", process_time, "s")
+    print(result)
+    return jsonify(result)
+
+try:
+    clf = joblib.load(model_file_name)
+    classes = clf.classes_
+    print('model loaded')
+    known_faces = scan_known_people(known_people)
+    print('known faces scanned')
+
+except FileNotFoundError as e:
+    print('No model here')
+    exit(1)
+
+
+if __name__ == '__main__':
+    app.run(host='0.0.0.0', port=8349, debug=True, ssl_context=ssl)