fr_flask.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. from PIL import ImageFile, Image
  2. from flask import Flask, request, jsonify
  3. import face_recognition
  4. import base64
  5. from io import BytesIO
  6. import joblib
  7. import numpy as np
  8. import re
  9. import os
  10. import time
  11. import mysql.connector
  12. import shlex
  13. import subprocess
  14. from face_recognition_svm import train_svm
  15. ImageFile.SAFEBLOCK = 2048 * 2048
  16. app = Flask(__name__)
  17. model_file_name = "saved_model_2.pkl"
  18. clf = None
  19. classes = None
  20. ids = []
  21. # dummy_data = [
  22. # {
  23. # "name": "Bayu",
  24. # "address": "299 St Louis Road Oak Forest, IL 60452",
  25. # "nik": "1000076456784631"
  26. # },
  27. # {
  28. # "name": "Dio",
  29. # "address": "22 Whitemarsh St. Mansfield, MA 02048",
  30. # "nik": "1000024792887549"
  31. # },
  32. # {
  33. # "name": "Hadi",
  34. # "address": "643 Honey Creek Dr. Milledgeville, GA 31061",
  35. # "nik": "1000038502830420"
  36. # },
  37. # {
  38. # "name": "Kevin",
  39. # "address": "881 Cooper Ave. Hummelstown, PA 17036",
  40. # "nik": "1000045356476664"
  41. # },
  42. # {
  43. # "name": "Matrix",
  44. # "address": "580 Glenwood Dr. Garner, NC 27529",
  45. # "nik": "1000023452134598"
  46. # },
  47. # {
  48. # "name": "Surya",
  49. # "address": "909 South St Paul Street Hopewell, VA 23860",
  50. # "nik": "1000075656784734"
  51. # },
  52. # ]
  53. ssl = None
  54. known_people = "application_data/verification_images"
  55. known_faces = []
  56. total_threshold = 0.1
  57. face_model = "large"
  58. if face_model == "large":
  59. model_file_name = "saved_model_2_large.pkl"
  60. TRAINING_FOLDER = os.path.join("data", "train")
  61. PROFILE_FOLDER = os.path.join("application_data", "verification_images")
  62. app.config["TRAINING_FOLDER"] = TRAINING_FOLDER
  63. app.config["PROFILE_FOLDER"] = PROFILE_FOLDER
  64. db_user = "facer"
  65. db_pass = "9Y6Bqg3JwQxXa"
  66. db = mysql.connector.connect(user=db_user, password=db_pass, unix_socket="/opt/lampp/var/mysql/mysql.sock",
  67. database='face_recognition')
  68. def scan_known_people(known_people_folder):
  69. known_face_encodings = []
  70. for file in image_files_in_folder(known_people_folder):
  71. img = face_recognition.load_image_file(file)
  72. encodings = face_recognition.face_encodings(img, model=face_model)
  73. if len(encodings) > 1:
  74. print("WARNING: More than one face found in {}. Only considering the first face.".format(file))
  75. if len(encodings) == 0:
  76. print("WARNING: No faces found in {}. Ignoring file.".format(file))
  77. else:
  78. known_face_encodings.append(encodings[0])
  79. return known_face_encodings
  80. def image_files_in_folder(folder):
  81. img_list = [os.path.join(folder, f) for f in os.listdir(folder) if
  82. re.match(r'.*\.(jpg|jpeg|png|webp)', f, flags=re.I)]
  83. img_list.sort()
  84. return img_list
  85. def load_db(data_id):
  86. db_con = mysql.connector.connect(user=db_user, password=db_pass, unix_socket="/opt/lampp/var/mysql/mysql.sock",
  87. database='face_recognition')
  88. db_cursor = db_con.cursor()
  89. db_result = {"name": "Unknown", "address": "", "nik": ""}
  90. try:
  91. db_query = "SELECT `NIK`, `NAME`, `ADDRESS` FROM `face_recognition` WHERE `ID` = %s"
  92. db_cursor.execute(db_query, data_id)
  93. for (nik, name, address) in db_cursor:
  94. db_result['nik'] = nik
  95. db_result['name'] = name
  96. db_result['address'] = address
  97. finally:
  98. db_cursor.close()
  99. db_con.close()
  100. return db_result
  101. def save_db(nik, name, address):
  102. db_con = mysql.connector.connect(user=db_user, password=db_pass, unix_socket="/opt/lampp/var/mysql/mysql.sock",
  103. database='face_recognition')
  104. data_id = None
  105. db_cursor = db_con.cursor()
  106. try:
  107. db_query = 'INSERT INTO `face_recognition` (`NIK`, `NAME`, `ADDRESS`) VALUES (%s, %s, %s)'
  108. db_cursor.execute(db_query, (nik, name, address))
  109. db_con.commit()
  110. data_id = db_cursor.lastrowid
  111. finally:
  112. db_cursor.close()
  113. db_con.close()
  114. return data_id
  115. def get_face(image, crop=False):
  116. max_height = image.height
  117. max_width = image.width
  118. profile_nparray = np.asarray(image)
  119. profile_face_loc = face_recognition.face_locations(profile_nparray)
  120. profile_len = len(profile_face_loc)
  121. if profile_len >= 1:
  122. if crop:
  123. top = profile_face_loc[0][0]
  124. right = profile_face_loc[0][1]
  125. bottom = profile_face_loc[0][2]
  126. left = profile_face_loc[0][3]
  127. width = right - left
  128. height = bottom - top
  129. center_x = int(left + width / 2)
  130. center_y = int(top + height / 2)
  131. calc_new_width = min(int(width * 2), (max_width - center_x) * 2, abs((0 - center_x) * 2))
  132. calc_new_height = min(int(height * 2), (max_height - center_y) * 2, abs((0 - center_y) * 2))
  133. new_size = min(calc_new_height, calc_new_width)
  134. new_top = int(center_y - new_size / 2)
  135. new_right = int(center_x + new_size / 2)
  136. new_bottom = int(center_y + new_size / 2)
  137. new_left = int(center_x - new_size / 2)
  138. cropped = image.crop((new_left, new_top, new_right, new_bottom))
  139. resized = cropped.resize((250, 250))
  140. else:
  141. resized = image.resize((250, 250))
  142. return resized
  143. return None
  144. @app.route('/', methods=['GET', 'POST'])
  145. def test():
  146. return jsonify({"status": "0"})
  147. @app.route('/upload', methods=['POST'])
  148. def upload():
  149. try:
  150. profile = request.files["profile"]
  151. nik = request.form["nik"]
  152. name = request.form["name"]
  153. address = request.form["address"]
  154. training = []
  155. print(len(request.files))
  156. if 'training' in request.files:
  157. training = request.files.getlist("training")
  158. elif 'training[]' in request.files:
  159. training = request.files.getlist("training[]")
  160. else:
  161. files_length = len(request.files)
  162. training_names = [f'training{x}' for x in range(files_length - 1)]
  163. for x in training_names:
  164. training.append(request.files[x])
  165. print(training)
  166. print(len(training))
  167. if not training:
  168. return jsonify({"status": "2", "message": "Training files not exist"})
  169. profile_image = Image.open(profile.stream)
  170. profile_image.load()
  171. new_profile_image = get_face(profile_image)
  172. if not new_profile_image:
  173. return jsonify({"status": "3", "message": "Profile face not found, please upload a different picture"})
  174. detected_training = []
  175. detected_training_fn = []
  176. for file in training:
  177. training_image = Image.open(file.stream)
  178. new_training_image = get_face(training_image)
  179. if new_training_image:
  180. detected_training.append(new_training_image)
  181. detected_training_fn.append(file.filename)
  182. if not detected_training:
  183. return jsonify(
  184. {"status": "4", "message": "No face found on any training images, please upload a different picture"})
  185. print(detected_training)
  186. print(detected_training_fn)
  187. # Save
  188. user_id = save_db(nik, name, address)
  189. print(user_id)
  190. if not user_id:
  191. return jsonify({"status": "1", "message": "Error uploading data, please try again"})
  192. new_profile_image.save(os.path.join(app.config["PROFILE_FOLDER"], f'{user_id}.jpg'))
  193. id_dir = os.path.join(app.config['TRAINING_FOLDER'], str(user_id))
  194. if not os.path.exists(id_dir):
  195. os.mkdir(id_dir)
  196. for (image, filename) in zip(detected_training, detected_training_fn):
  197. image.save(os.path.join(app.config['TRAINING_FOLDER'], str(user_id), filename))
  198. return jsonify({"status": "0", "message": "Upload successful"})
  199. except Exception as exc:
  200. return jsonify({"status": "1", "message": f"Error uploading data, please try again | {exc}"})
  201. @app.route('/train', methods=['GET', 'POST'])
  202. def train():
  203. try:
  204. train_svm(model_file_name)
  205. return jsonify({"status": "0", "message": "Train successful"})
  206. except Exception as exc:
  207. return jsonify({"status": "1", "message": f"Error training model: {exc}"})
  208. @app.route('/reload', methods=['GET', 'POST'])
  209. def face_reload():
  210. pid = None
  211. try:
  212. with open("app.pid", "r") as f:
  213. pid = f.readline()
  214. if pid:
  215. cmd = f"kill -s HUP {pid}"
  216. cmd_array = shlex.split(cmd)
  217. print(cmd_array)
  218. subprocess.Popen(cmd_array, start_new_session=True)
  219. else:
  220. return jsonify({"status": "1", "message": f"Reload unsucessful"})
  221. except Exception as exc:
  222. return jsonify({"status": "2", "message": f"Reload unsucessful: {exc}"})
  223. @app.route('/predict', methods=['POST'])
  224. def predict():
  225. db_result = []
  226. if "image" in request.json:
  227. im_b64 = request.json["image"]
  228. elif "image" in request.files:
  229. im_b64 = request.files["image"]
  230. elif "image" in request.form:
  231. im_b64 = request.form["image"]
  232. else:
  233. return {"error": "Error reading image"}
  234. im_bytes = base64.b64decode(im_b64)
  235. im_file = BytesIO(im_bytes)
  236. test_image = face_recognition.load_image_file(im_file)
  237. face_locations = face_recognition.face_locations(test_image)
  238. no = len(face_locations)
  239. if no > 0:
  240. for i in range(no):
  241. start_time = time.perf_counter()
  242. test_image_enc = face_recognition.face_encodings(test_image, model=face_model)[i]
  243. proba_list = clf.predict_proba([test_image_enc])
  244. dist = face_recognition.face_distance(known_faces, test_image_enc)
  245. total = np.subtract(proba_list, dist)
  246. i = np.argmax(total)
  247. proba = list(*proba_list)[i]
  248. face_id = ids[i]
  249. data = load_db(face_id)
  250. name = data["name"]
  251. address = data["address"]
  252. nik = data["nik"]
  253. print("total threshold: ", total_threshold)
  254. print("total: ", total[0][i])
  255. print({
  256. "id": str(face_id),
  257. "name": name,
  258. "address": address,
  259. "nik": nik,
  260. "proba": proba,
  261. "delta": total[0][i]
  262. })
  263. if total[0][i] > total_threshold:
  264. js = {
  265. "id": str(face_id),
  266. "name": name,
  267. "address": address,
  268. "nik": nik,
  269. "proba": proba,
  270. "delta": total[0][i]
  271. }
  272. else:
  273. js = {
  274. "id": "-1",
  275. "name": "Unknown",
  276. "address": "",
  277. "nik": "",
  278. "proba": 0.0,
  279. "delta": 0.0
  280. }
  281. print(total[0][i] > total_threshold)
  282. print(not db_result)
  283. print(i == no - 1)
  284. print((not db_result and i == no - 1))
  285. if total[0][i] > total_threshold or (not db_result and i == no - 1):
  286. db_result.append(js)
  287. end_time = time.perf_counter()
  288. process_time = end_time - start_time
  289. print(time.strftime("%c"))
  290. print(total[0])
  291. print("Process time:", process_time, "s")
  292. print(db_result)
  293. return jsonify(db_result)
  294. try:
  295. clf = joblib.load(model_file_name)
  296. classes = clf.classes_
  297. print('model loaded')
  298. known_faces = scan_known_people(known_people)
  299. print('known faces scanned')
  300. db = mysql.connector.connect(user=db_user, password=db_pass, unix_socket="/opt/lampp/var/mysql/mysql.sock",
  301. database='face_recognition')
  302. cursor = db.cursor()
  303. result = {"name": "Unknown", "address": "", "nik": ""}
  304. try:
  305. query = "SELECT `ID` FROM `face_recognition` ORDER BY `ID`"
  306. cursor.execute(query)
  307. for data_id in cursor:
  308. ids.append(data_id[0])
  309. finally:
  310. cursor.close()
  311. db.close()
  312. print("ids: ", ids)
  313. except FileNotFoundError as e:
  314. print('No model here')
  315. exit(1)
  316. if __name__ == '__main__':
  317. app.run(host='0.0.0.0', port=8349, debug=True, ssl_context=ssl)