fr_flask.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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", database='face_recognition')
  67. def scan_known_people(known_people_folder):
  68. known_face_encodings = []
  69. for file in image_files_in_folder(known_people_folder):
  70. img = face_recognition.load_image_file(file)
  71. encodings = face_recognition.face_encodings(img, model=face_model)
  72. if len(encodings) > 1:
  73. print("WARNING: More than one face found in {}. Only considering the first face.".format(file))
  74. if len(encodings) == 0:
  75. print("WARNING: No faces found in {}. Ignoring file.".format(file))
  76. else:
  77. known_face_encodings.append(encodings[0])
  78. return known_face_encodings
  79. def image_files_in_folder(folder):
  80. img_list = [os.path.join(folder, f) for f in os.listdir(folder) if
  81. re.match(r'.*\.(jpg|jpeg|png|webp)', f, flags=re.I)]
  82. img_list.sort()
  83. return img_list
  84. def load_db(id):
  85. db = mysql.connector.connect(user=db_user, password=db_pass, unix_socket="/opt/lampp/var/mysql/mysql.sock",
  86. database='face_recognition')
  87. cursor = db.cursor()
  88. result = {"name": "Unknown", "address": "", "nik": ""}
  89. try:
  90. query = "SELECT `NIK`, `NAME`, `ADDRESS` FROM `face_recognition` WHERE `ID` = {}".format(id)
  91. cursor.execute(query)
  92. for (nik, name, address) in cursor:
  93. result['nik'] = nik
  94. result['name'] = name
  95. result['address'] = address
  96. finally:
  97. cursor.close()
  98. db.close()
  99. return result
  100. def save_db(nik, name, address):
  101. db = mysql.connector.connect(user=db_user, password=db_pass, unix_socket="/opt/lampp/var/mysql/mysql.sock",
  102. database='face_recognition')
  103. id = None
  104. cursor = db.cursor()
  105. try:
  106. query = 'INSERT INTO `face_recognition` (`NIK`, `NAME`, `ADDRESS`) VALUES ("{}", "{}", "{}")'.format(nik,name,address)
  107. cursor.execute(query)
  108. db.commit()
  109. id = cursor.lastrowid
  110. finally:
  111. cursor.close()
  112. db.close()
  113. return id
  114. def get_face(image, crop=False):
  115. max_height = image.height
  116. max_width = image.width
  117. profile_nparray = np.asarray(image)
  118. profile_face_loc = face_recognition.face_locations(profile_nparray)
  119. profile_len = len(profile_face_loc)
  120. if profile_len >= 1:
  121. if crop:
  122. top = profile_face_loc[0][0]
  123. right = profile_face_loc[0][1]
  124. bottom = profile_face_loc[0][2]
  125. left = profile_face_loc[0][3]
  126. width = right - left
  127. height = bottom - top
  128. center_x = int(left + width / 2)
  129. center_y = int(top + height / 2)
  130. calc_new_width = min(int(width * 2), (max_width - center_x) * 2, abs((0 - center_x) * 2))
  131. calc_new_height = min(int(height * 2), (max_height - center_y) * 2, abs((0 - center_y) * 2))
  132. new_size = min(calc_new_height, calc_new_width)
  133. new_top = int(center_y - new_size / 2)
  134. new_right = int(center_x + new_size / 2)
  135. new_bottom = int(center_y + new_size / 2)
  136. new_left = int(center_x - new_size / 2)
  137. cropped = image.crop((new_left, new_top, new_right, new_bottom))
  138. resized = cropped.resize((250, 250))
  139. else:
  140. resized = image.resize((250,250))
  141. return resized
  142. return None
  143. @app.route('/',methods=['GET', 'POST'])
  144. def test():
  145. return jsonify({"status" : "0"})
  146. @app.route('/upload', methods=['POST'])
  147. def upload():
  148. try:
  149. profile = request.files["profile"]
  150. nik = request.form["nik"]
  151. name = request.form["name"]
  152. address = request.form["address"]
  153. training = []
  154. print(len(request.files))
  155. if 'training' in request.files:
  156. training = request.files.getlist("training")
  157. elif 'training[]' in request.files:
  158. training = request.files.getlist("training[]")
  159. else:
  160. files_length = len(request.files)
  161. training_names = [f'training{x}' for x in range(files_length-1)]
  162. for x in training_names:
  163. training.append(request.files[x])
  164. print(training)
  165. print(len(training))
  166. if not training:
  167. return jsonify({"status": "2", "message": "Training files not exist"})
  168. profile_image = Image.open(profile.stream)
  169. profile_image.load()
  170. new_profile_image = get_face(profile_image)
  171. if not new_profile_image:
  172. return jsonify({"status": "3", "message": "Profile face not found, please upload a different picture"})
  173. detected_training = []
  174. detected_training_fn = []
  175. for file in training:
  176. training_image = Image.open(file.stream)
  177. new_training_image = get_face(training_image)
  178. if new_training_image:
  179. detected_training.append(new_training_image)
  180. detected_training_fn.append(file.filename)
  181. if not detected_training:
  182. return jsonify({"status": "4", "message": "No face found on any training images, please upload a different picture"})
  183. print(detected_training)
  184. print(detected_training_fn)
  185. # Save
  186. id = save_db(nik, name, address)
  187. print(id)
  188. if not id:
  189. return jsonify({"status": "1", "message": "Error uploading data, please try again"})
  190. new_profile_image.save(os.path.join(app.config["PROFILE_FOLDER"], f'{id}.jpg'))
  191. id_dir = os.path.join(app.config['TRAINING_FOLDER'], str(id))
  192. if not os.path.exists(id_dir):
  193. os.mkdir(id_dir)
  194. for (image, filename) in zip(detected_training, detected_training_fn):
  195. image.save(os.path.join(app.config['TRAINING_FOLDER'], str(id), filename))
  196. return jsonify({"status": "0", "message": "Upload successful"})
  197. except Exception as exc:
  198. return jsonify({"status": "1", "message": f"Error uploading data, please try again | {exc}"})
  199. @app.route('/train', methods=['GET', 'POST'])
  200. def train():
  201. try:
  202. train_svm(model_file_name)
  203. return jsonify({"status": "0", "message": "Train successful"})
  204. except Exception as exc:
  205. return jsonify({"status": "1", "message": f"Error training model: {exc}"})
  206. @app.route('/reload', methods=['GET', 'POST'])
  207. def face_reload():
  208. pid = None
  209. try:
  210. with open("app.pid","r") as f:
  211. pid = f.readline()
  212. if pid:
  213. cmd = f"kill -s HUP {pid}"
  214. cmd_array = shlex.split(cmd)
  215. print(cmd_array)
  216. p = subprocess.Popen(cmd_array, start_new_session=True)
  217. else:
  218. return jsonify({"status": "1", "message": f"Reload unsucessful"})
  219. except Exception as exc:
  220. return jsonify({"status": "2", "message": f"Reload unsucessful: {exc}"})
  221. @app.route('/predict', methods=['POST'])
  222. def predict():
  223. result = []
  224. if "image" in request.json:
  225. im_b64 = request.json["image"]
  226. elif "image" in request.files:
  227. im_b64 = request.files["image"]
  228. elif "image" in request.form:
  229. im_b64 = request.form["image"]
  230. else:
  231. return {"error": "Error reading image"}
  232. im_bytes = base64.b64decode(im_b64)
  233. im_file = BytesIO(im_bytes)
  234. test_image = face_recognition.load_image_file(im_file)
  235. face_locations = face_recognition.face_locations(test_image)
  236. no = len(face_locations)
  237. if no > 0:
  238. for i in range(no):
  239. start_time = time.perf_counter()
  240. test_image_enc = face_recognition.face_encodings(test_image, model=face_model)[i]
  241. proba_list = clf.predict_proba([test_image_enc])
  242. dist = face_recognition.face_distance(known_faces, test_image_enc)
  243. total = np.subtract(proba_list, dist)
  244. i = np.argmax(total)
  245. proba = list(*proba_list)[i]
  246. face_id = ids[i]
  247. data = load_db(face_id)
  248. name = data["name"]
  249. address = data["address"]
  250. nik = data["nik"]
  251. print("total threshold: ", total_threshold)
  252. print("total: ", total[0][i])
  253. print({
  254. "id": str(face_id),
  255. "name": name,
  256. "address": address,
  257. "nik": nik,
  258. "proba": proba,
  259. "delta": total[0][i]
  260. })
  261. if total[0][i] > total_threshold:
  262. js = {
  263. "id": str(face_id),
  264. "name": name,
  265. "address": address,
  266. "nik": nik,
  267. "proba": proba,
  268. "delta": total[0][i]
  269. }
  270. else:
  271. js = {
  272. "id": "-1",
  273. "name": "Unknown",
  274. "address": "",
  275. "nik": "",
  276. "proba": 0.0,
  277. "delta": 0.0
  278. }
  279. print(total[0][i] > total_threshold)
  280. print(not result)
  281. print(i == no - 1)
  282. print((not result and i == no - 1))
  283. if total[0][i] > total_threshold or (not result and i == no - 1):
  284. result.append(js)
  285. end_time = time.perf_counter()
  286. process_time = end_time - start_time
  287. print(time.strftime("%c"))
  288. print(total[0])
  289. print("Process time:", process_time, "s")
  290. print(result)
  291. return jsonify(result)
  292. try:
  293. clf = joblib.load(model_file_name)
  294. classes = clf.classes_
  295. print('model loaded')
  296. known_faces = scan_known_people(known_people)
  297. print('known faces scanned')
  298. db = mysql.connector.connect(user=db_user, password=db_pass, unix_socket="/opt/lampp/var/mysql/mysql.sock",
  299. database='face_recognition')
  300. cursor = db.cursor()
  301. result = {"name": "Unknown", "address": "", "nik": ""}
  302. try:
  303. query = "SELECT `ID` FROM `face_recognition` ORDER BY `ID`"
  304. cursor.execute(query)
  305. for id in cursor:
  306. ids.append(id[0])
  307. finally:
  308. cursor.close()
  309. db.close()
  310. print("ids: ",ids)
  311. except FileNotFoundError as e:
  312. print('No model here')
  313. exit(1)
  314. if __name__ == '__main__':
  315. app.run(host='0.0.0.0', port=8349, debug=True, ssl_context=ssl)