ankpan18 commited on
Commit
752c636
·
1 Parent(s): 700fede

face rec api with remote mysql 10mb server

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +3 -0
  2. Dockerfile +29 -0
  3. README.md +1 -0
  4. app/__init__.py +56 -0
  5. app/admin/__init__.py +6 -0
  6. app/admin/routes.py +136 -0
  7. app/api/__init__.py +5 -0
  8. app/api/routes.py +208 -0
  9. app/demo/__init__.py +6 -0
  10. app/demo/routes.py +207 -0
  11. app/face_detection/Models/v1/anchors.txt +4 -0
  12. app/face_detection/Models/v1/model.h5 +3 -0
  13. app/face_detection/config.py +15 -0
  14. app/face_detection/create_load_model.py +254 -0
  15. app/face_detection/decode_yolo_v2.py +108 -0
  16. app/face_detection/helper.py +24 -0
  17. app/face_detection/inference.py +281 -0
  18. app/face_recognition/Models/v1/config.py +3 -0
  19. app/face_recognition/Models/v1/model.h5 +3 -0
  20. app/face_recognition/aligner.py +80 -0
  21. app/face_recognition/config.py +4 -0
  22. app/face_recognition/helper.py +115 -0
  23. app/face_recognition/inference.py +211 -0
  24. app/face_recognition/setup_db_features.py +28 -0
  25. app/face_recognition/split_model.py +12 -0
  26. app/helper.py +140 -0
  27. app/main/__init__.py +5 -0
  28. app/main/routes.py +6 -0
  29. app/static/admin/dashboard.css +32 -0
  30. app/static/admin/dashboard.js +119 -0
  31. app/static/admin/login.css +49 -0
  32. app/static/admin/registeration.js +56 -0
  33. app/static/demo/index/dark.css +354 -0
  34. app/static/demo/index/icon.jpg +0 -0
  35. app/static/demo/index/script.js +498 -0
  36. app/static/demo/index/style.css +235 -0
  37. app/static/user/dashboard.css +305 -0
  38. app/static/user/dashboard.js +483 -0
  39. app/static/user/login.css +49 -0
  40. app/static/user/registeration.css +44 -0
  41. app/static/user/registeration.js +74 -0
  42. app/templates/admin/dashboard.html +28 -0
  43. app/templates/admin/login.html +25 -0
  44. app/templates/base.html +13 -0
  45. app/templates/demo.html +1 -0
  46. app/templates/demo/index.html +130 -0
  47. app/templates/user/dashboard.html +157 -0
  48. app/templates/user/login.html +25 -0
  49. app/templates/user/registeration.html +34 -0
  50. app/user/__init__.py +8 -0
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ # *.h5
2
+ myvenv/
3
+ __pycache__/
Dockerfile ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM ubuntu
2
+
3
+
4
+ RUN apt-get update && \
5
+ apt-get -y upgrade && \
6
+ apt-get install -y \
7
+ sudo
8
+
9
+
10
+ RUN DEBIAN_FRONTEND=noninteractive apt-get -y install python3 pip vim mc wget curl
11
+
12
+
13
+ COPY . /app
14
+ WORKDIR /app
15
+ RUN pip install -r requirements.txt
16
+
17
+
18
+
19
+ CMD python3 -c "print('Docker is more simple Deployment Tool')"
20
+
21
+ RUN pwd
22
+ RUN ls -l
23
+
24
+
25
+ EXPOSE 7860
26
+
27
+
28
+
29
+ CMD "flask run --host=0.0.0.0 --port=7860"
README.md CHANGED
@@ -5,6 +5,7 @@ colorFrom: blue
5
  colorTo: blue
6
  sdk: docker
7
  pinned: false
 
8
  ---
9
 
10
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
5
  colorTo: blue
6
  sdk: docker
7
  pinned: false
8
+ app_port: 7860
9
  ---
10
 
11
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app/__init__.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask,session
2
+ from datetime import timedelta
3
+
4
+ from app.face_detection import inference as fd
5
+ from app.face_detection.helper import get_crops as fd_get_crops
6
+ from app.face_recognition import inference as fr
7
+ from app.face_recognition.aligner import aligner
8
+ from app.face_recognition import helper as fr_helper
9
+
10
+
11
+
12
+ face_detector=fd.face_detection("app/face_detection/Models/v1")
13
+ face_detector.square_preprocessing=fd.square_pad()
14
+ # face_recognizer=fr.face_recognition("app/face_recognition/feature_extractor.h5")
15
+ face_recognizer=fr.face_recognition("app/face_recognition/Models/v1")
16
+ aligner_obj=aligner(min_aligner_confidence=0.6)
17
+
18
+ image_size=544
19
+ p_thres=0.7
20
+ nms_thres=0.3
21
+ batch_size=1
22
+ face_detector.set_mode(p_thres,nms_thres,mode="sized",image_size=image_size,batch_size=batch_size)
23
+
24
+
25
+ # def create_app(config_class=Config):
26
+ def create_app():
27
+ app=Flask(__name__)
28
+ # app.config.from_object(config_class)
29
+ # app.permanent_session_lifetime = timedelta(seconds=5)
30
+
31
+ @app.before_request
32
+ def make_session_permanent():
33
+ session.permanent = True
34
+
35
+ from app.main import bp as main_bp
36
+ app.register_blueprint(main_bp)
37
+
38
+ from app.demo import bp as demo_bp
39
+ app.register_blueprint(demo_bp,url_prefix="/demo")
40
+
41
+ from app.user import bp as user_bp
42
+ app.register_blueprint(user_bp,url_prefix='/user')
43
+
44
+ from app.admin import bp as admin_bp
45
+ app.register_blueprint(admin_bp,url_prefix='/admin')
46
+
47
+ from app.api import bp as api_bp
48
+ app.register_blueprint(api_bp,url_prefix='/api')
49
+
50
+ app.secret_key='asdasr34r'
51
+
52
+ @app.route("/test/")
53
+ def test_page():
54
+ return "<h1>This is a test page</h1>"
55
+
56
+ return app
app/admin/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ from flask import Blueprint
2
+
3
+ bp=Blueprint("admin",__name__)
4
+
5
+
6
+ from app.admin import routes
app/admin/routes.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import render_template,request,jsonify,redirect,url_for,session
2
+ import mysql.connector
3
+ from werkzeug.security import generate_password_hash,check_password_hash
4
+ from app.admin import bp
5
+ from app.helper import generate_random_id,access_database_as_admin,create_user_table,drop_user_table
6
+
7
+
8
+ @bp.route("/login/")
9
+ def login_page():
10
+ return render_template("admin/login.html")
11
+
12
+ @bp.route("/login/<message>")
13
+ def login_page_message(message):
14
+ return render_template("admin/login.html",message_class='active',message=message)
15
+
16
+ def get_random_unique_id():
17
+ dataBase = access_database_as_admin()
18
+ cursor=dataBase.cursor()
19
+
20
+ while(True):
21
+ random_id=generate_random_id()
22
+ cursor.execute("select username from admins where session_token=%s",[random_id])
23
+ if cursor.fetchone() is None: break
24
+ dataBase.close()
25
+ return random_id
26
+
27
+
28
+
29
+ @bp.route("/authenticate/",methods=["POST"])
30
+ def authenticate():
31
+ dataBase = access_database_as_admin()
32
+ cursor=dataBase.cursor()
33
+ cursor.execute("select password from admins where username=%s",[request.form['username']])
34
+ db_password_hash=cursor.fetchone()
35
+ dataBase.close()
36
+
37
+ # print(db_password_hash)
38
+ if None==db_password_hash:
39
+ # username doesn't exists
40
+ return redirect(url_for('admin.login_page_message', message = "username doesn't exists"))
41
+
42
+ elif(check_password_hash(db_password_hash[0],request.form['password'])):
43
+ # set session and login
44
+ session.permanent = True
45
+
46
+ session['admin_token']=get_random_unique_id()
47
+
48
+ dataBase = access_database_as_admin()
49
+ cursor=dataBase.cursor()
50
+ cursor.execute("update admins set session_token=%s where username=%s",(session['admin_token'],request.form['username']))
51
+ dataBase.commit()
52
+ dataBase.close()
53
+
54
+ return redirect("/admin/")
55
+ else:
56
+ # incorrect password
57
+ return redirect(url_for('admin.login_page_message', message = "Incorrect password"))
58
+
59
+
60
+
61
+
62
+ def is_auth(func):
63
+ def wrapper_func(*args,**kwargs):
64
+ if "admin_token" not in session:
65
+ return redirect(url_for('admin.login_page_message', message = "login in first"))
66
+ else:
67
+ dataBase = access_database_as_admin()
68
+ cursor=dataBase.cursor()
69
+ cursor.execute("select username from admins where session_token=%s",[session['admin_token']])
70
+ if cursor.fetchone() is None:
71
+ # no such session in db records
72
+ dataBase.close()
73
+ return redirect(url_for('admin.login_page_message', message = "no such session in db"))
74
+ else:
75
+ dataBase.close()
76
+ return func(*args,**kwargs)
77
+ # Renaming the function name:
78
+ wrapper_func.__name__ = func.__name__
79
+ return wrapper_func
80
+
81
+
82
+ @bp.route("/")
83
+ @is_auth
84
+ def user_dashboard():
85
+ return render_template("admin/dashboard.html")
86
+
87
+ @bp.route("/get_all_requests/", methods=["GET"])
88
+ @is_auth
89
+ def get_all_requests():
90
+ dataBase = access_database_as_admin()
91
+ cursor=dataBase.cursor()
92
+ cursor.execute("select username,request_message,access_key from users where access_key is null or access_key!='rejected';")
93
+ data=cursor.fetchall()
94
+ dataBase.close()
95
+ print(data)
96
+ data_dict=dict()
97
+ for one_row in data:
98
+ for i,column_name in enumerate(cursor.column_names):
99
+ data_dict[column_name]=[one_row[i]] if column_name not in data_dict else data_dict[column_name]+[one_row[i]]
100
+
101
+ print(data_dict)
102
+ return jsonify(data_dict)
103
+
104
+
105
+ def get_random_unique_access_key():
106
+ dataBase = access_database_as_admin()
107
+ cursor=dataBase.cursor()
108
+
109
+ while(True):
110
+ random_access_key=generate_random_id()
111
+ cursor.execute("select username from users where access_key=%s",[random_access_key])
112
+ if cursor.fetchone() is None: break
113
+ dataBase.close()
114
+ return random_access_key
115
+
116
+
117
+ @bp.route("/update_requests/",methods=["POST"])
118
+ @is_auth
119
+ def update_requests():
120
+ print(request.form)
121
+ dataBase = access_database_as_admin()
122
+ cursor=dataBase.cursor()
123
+ if request.form['mode']=="accept":
124
+ cursor.execute("update users set access_key=%s where username=%s",[get_random_unique_access_key(),request.form['username']])
125
+ create_user_table(request.form['username']) # also add a table for this user
126
+
127
+ elif request.form['mode']=="reject":
128
+ cursor.execute("update users set access_key=%s where username=%s",["rejected",request.form['username']])
129
+ drop_user_table(request.form['username']) # Drop table for this user
130
+
131
+ elif request.form['mode']=="revoke":
132
+ cursor.execute("update users set access_key=NULL where username=%s",[request.form['username']])
133
+
134
+ dataBase.commit()
135
+ dataBase.close()
136
+ return jsonify({"message":"success"})
app/api/__init__.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ from flask import Blueprint
2
+
3
+ bp=Blueprint("api",__name__)
4
+
5
+ from app.api import routes
app/api/routes.py ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import request,jsonify,g
2
+ from app.api import bp
3
+ from app.helper import generate_random_id,access_database_as_admin,image_to_base64,base64_to_image,add_row_user_table,read_row_user_table,read_user_table,remove_person_from_user_table
4
+ from PIL import ImageOps,Image
5
+ import numpy as np
6
+
7
+ from app import face_detector,face_recognizer,aligner_obj,fd_get_crops,fr_helper
8
+
9
+
10
+
11
+ #################################################################################################################################################
12
+
13
+ def set_image_size(settings,mode):
14
+ if mode=='small':
15
+ face_detector.image_size=[settings['small_size']]
16
+ elif mode=='large':
17
+ face_detector.image_size=[settings['large_size']]
18
+ elif mode=='both':
19
+ face_detector.image_size=[settings['small_size'],settings['large_size']]
20
+ else:
21
+ raise("Error")
22
+
23
+
24
+
25
+
26
+ def load_settings(username):
27
+
28
+ dataBase = access_database_as_admin()
29
+ cursor=dataBase.cursor()
30
+ cursor.execute("select * from user_settings where username=%s",[username])
31
+ settings=cursor.fetchone()
32
+ columns=cursor.column_names
33
+
34
+ if settings is None:
35
+ # get default settings and insert a row in user_settings
36
+ cursor.execute("select p_thres,nms_thres,small_size,large_size,d_thres,a_thres,db_mode,fr_mode from default_settings where page='user'")
37
+ settings=cursor.fetchone()
38
+ columns=cursor.column_names
39
+ cursor.execute(f"insert into user_settings(username,{','.join(columns)}) values(%s,{','.join(map(lambda x:'%s',columns))})",(session['user']['username'],)+settings)
40
+
41
+
42
+ settings= dict(zip(columns, settings))
43
+ # Disconnecting from the server
44
+ dataBase.commit()
45
+ dataBase.close()
46
+
47
+ # set face detector settings
48
+ face_detector.p_thres=settings['p_thres']
49
+ face_detector.nms_thres=settings['nms_thres']
50
+ # we will set image_size inside routes
51
+
52
+ # set face aligner settings
53
+ aligner_obj.face_mesh_images.min_detection_confidence=settings['a_thres']
54
+
55
+ # set face recognizer settings
56
+ face_recognizer.thres=settings['d_thres']
57
+
58
+ return settings
59
+
60
+ #################################################################################################################################################
61
+
62
+ def is_auth(func):
63
+ def wrapper_func(*args,**kwargs):
64
+ if "access_key" not in request.form: return jsonify({"message":"send access key too"})
65
+ else:
66
+ dataBase = access_database_as_admin()
67
+ cursor=dataBase.cursor()
68
+ cursor.execute("select username from users where access_key=%s",[request.form["access_key"]])
69
+ data=cursor.fetchone()
70
+ if data is None:
71
+ dataBase.close()
72
+ return jsonify({"message":"no such access key in database"})
73
+ else:
74
+ dataBase.close()
75
+ return func(data[0],*args,**kwargs)
76
+ # Renaming the function name:
77
+ wrapper_func.__name__ = func.__name__
78
+ return wrapper_func
79
+
80
+
81
+ @bp.route("/get_crops/",methods=["POST"])
82
+ @is_auth
83
+ def get_crops(username):
84
+
85
+ settings=load_settings(username)
86
+ set_image_size(settings,settings["db_mode"])
87
+ if "image_size" in request.form: face_detector.image_size=list(map(lambda x:int(x),request.form["image_size"].split(",")))
88
+ if "thres" in request.form: face_recognizer.thres=request.form["thres"]
89
+ print(face_detector.image_size)
90
+
91
+ file = request.files['image']
92
+
93
+ image=Image.open(file.stream).convert("RGB")
94
+ image = ImageOps.exif_transpose(image)
95
+ image=np.array(image)
96
+ print(image.shape)
97
+
98
+ image,objs_found=face_detector.predict(image)
99
+ print(objs_found)
100
+
101
+ all_aligned_crops=fd_get_crops(image,objs_found,aligner_obj,resize=(face_recognizer.model_config.input_size,face_recognizer.model_config.input_size))
102
+ all_aligned_crops_base64=[]
103
+
104
+ for i,aligned_crop in enumerate(all_aligned_crops):
105
+ all_aligned_crops_base64.append(image_to_base64(aligned_crop))
106
+
107
+ return jsonify({"message":"success","crops":all_aligned_crops_base64})
108
+
109
+
110
+
111
+
112
+ @bp.route("/add_person/",methods=["POST"])
113
+ @is_auth
114
+ def add_person(username):
115
+
116
+ # print(request.form)
117
+ json_data=request.get_json()
118
+ person_name=json_data['person_name']
119
+ remarks=json_data['remarks']
120
+ group_id=json_data["group_id"] if "group_id" in json_data else None
121
+ print(person_name)
122
+ all_remarks=[]
123
+ all_remarks_features=[]
124
+ for remark in remarks.keys():
125
+ all_img_features=[]
126
+ for img_base64 in remarks[remark]:
127
+ img=base64_to_image(img_base64)
128
+ # print(remark,img.shape)
129
+
130
+ all_img_features.append(face_recognizer.feature_extractor.predict(img[None,:,:,::-1],verbose=0)[0])
131
+ all_img_features=np.array(all_img_features)
132
+ all_remarks_features.append(all_img_features.mean(axis=0))
133
+ all_remarks.append(remark)
134
+
135
+ all_remarks_features=np.array(all_remarks_features)
136
+
137
+ print(all_remarks_features.shape)
138
+ print(all_remarks)
139
+ print(username)
140
+
141
+ add_row_user_table(username=username,person_id=person_name,face_vectors=all_remarks_features.astype("float64"),remarks=",".join(all_remarks),group_id=group_id)
142
+ read_row_user_table(username)
143
+
144
+
145
+
146
+ return jsonify({"message":"success"})
147
+
148
+
149
+ @bp.route("/remove_person/",methods=["POST"])
150
+ @is_auth
151
+ def remove_person(username):
152
+
153
+ print(username)
154
+ remove_person_from_user_table(username,request.get_json()["person_id"])
155
+
156
+ return jsonify({"message":"success"})
157
+ # return jsonify({"message":"success",'image':pred_img})
158
+
159
+
160
+ @bp.route("/face_recognize/",methods=["POST"])
161
+ @is_auth
162
+ def face_recognition(username):
163
+
164
+ settings=load_settings(username)
165
+ set_image_size(settings,settings["fr_mode"])
166
+ if "image_size" in request.form: face_detector.image_size=list(map(lambda x:int(x),request.form["image_size"].split(",")))
167
+ if "d_thres" in request.form: face_recognizer.thres=request.form["d_thres"]
168
+ print(face_detector.image_size)
169
+
170
+ # print(request.form)
171
+ file = request.files['image']
172
+
173
+ image=Image.open(file.stream).convert("RGB")
174
+ image = ImageOps.exif_transpose(image)
175
+ image=np.array(image)
176
+ print(image.shape)
177
+
178
+ print(username)
179
+ data=read_user_table(username) if "group_id" not in request.form else read_user_table(username,request.form["group_id"])
180
+ faces=data['person_id']
181
+ db_faces_features=data['face_vectors']
182
+
183
+ for i in range(len(faces)):
184
+ print(faces[i],":",db_faces_features[i].shape)
185
+
186
+ # face_recognizer.set_face_db_and_mode(faces=faces,db_faces_features=db_faces_features,distance_mode="avg",recognition_mode="repeat")
187
+ face_recognizer.set_face_db_and_mode(faces=faces,db_faces_features=db_faces_features,distance_mode="best",recognition_mode="repeat")
188
+ img,objs_found=face_detector.predict(image)
189
+ h,w=img.shape[:2]
190
+ tree=fr_helper.objs_found_to_xml("test.jpg",w,h,objs_found)
191
+ tree=face_recognizer.predict(img,tree)
192
+ pred_img=fr_helper.show_pred_image(tree,img)
193
+ pred_img=image_to_base64(pred_img)
194
+ objs_found=fr_helper.xml_to_objs_found(tree) # everything is okay till here
195
+ # print(objs_found[0])
196
+
197
+ objs_found=face_detector.square_preprocessing.rescale(objs_found) #rescale coordinates to original image's resolution
198
+ # print(objs_found[0])
199
+
200
+ all_crops=fd_get_crops(image,objs_found)
201
+ all_crops_base64=[]
202
+
203
+ for i,aligned_crop in enumerate(all_crops):
204
+ all_crops_base64.append(image_to_base64(aligned_crop))
205
+
206
+ person_ids=[obj_found['class'] for obj_found in objs_found]
207
+
208
+ return jsonify({"message":"success","pred_image":pred_img,"person_ids":person_ids,"crops":all_crops_base64,"objs_found":objs_found})
app/demo/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ from flask import Blueprint
2
+
3
+ bp=Blueprint("demo",__name__)
4
+
5
+
6
+ from app.demo import routes
app/demo/routes.py ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from werkzeug.utils import secure_filename
2
+ import cv2
3
+ import numpy as np
4
+ from PIL import Image
5
+ import os
6
+ from glob import glob
7
+ import shutil
8
+ import io
9
+ import base64
10
+ import uuid
11
+ from flask import render_template,request,send_from_directory,session,jsonify,json
12
+ from app import helper
13
+ from PIL import ImageOps
14
+ from app.helper import generate_random_id,access_database_as_admin,image_to_base64,base64_to_image,add_row_user_table,read_row_user_table,read_user_table,remove_person_from_user_table
15
+ from app.demo import bp
16
+ import copy
17
+
18
+
19
+
20
+
21
+
22
+ from app import face_detector,face_recognizer,aligner_obj,fd_get_crops,fr_helper,fd,fr
23
+
24
+ # @bp.before_app_first_request
25
+ # def create_temp_path():
26
+ # if not os.path.exists(temp_path):os.mkdir(temp_path)
27
+
28
+ # @bp.route(f"/{temp_path}/<subfolder>/<filename>")
29
+ # def upload(filename,subfolder):
30
+ # return send_from_directory(temp_path+f"/{subfolder}/", filename)
31
+
32
+ @bp.route("/")
33
+ def index():
34
+ return render_template('demo/index.html')
35
+
36
+ def load_settings(func):
37
+ def wrapper_func(*args,**kwargs):
38
+ # set face detector settings
39
+ face_detector.p_thres=session["demo"]['settings']['p_thres']
40
+ face_detector.nms_thres=session["demo"]['settings']['nms_thres']
41
+ # we will set image_size inside routes
42
+
43
+ # set face aligner settings
44
+ aligner_obj.face_mesh_images.min_detection_confidence=session["demo"]['settings']['a_thres']
45
+
46
+ # set face recognizer settings
47
+ face_recognizer.thres=session["demo"]['settings']['d_thres']
48
+
49
+ return func(*args,**kwargs)
50
+ # Renaming the function name:
51
+ wrapper_func.__name__ = func.__name__
52
+ return wrapper_func
53
+
54
+ def get_image_size(mode):
55
+ if mode=='small':
56
+ return [session["demo"]['settings']['small_size']]
57
+ elif mode=='large':
58
+ return [session["demo"]['settings']['large_size']]
59
+ elif mode=='both':
60
+ return [session["demo"]['settings']['small_size'],session["demo"]['settings']['large_size']]
61
+ else:
62
+ raise("Error")
63
+
64
+
65
+ @bp.route("/add_crops/",methods=["POST"])
66
+ @load_settings
67
+ def set_crops():
68
+ # set session
69
+ if not "demo_token" in session:
70
+ session["demo_token"]=helper.generate_random_id()
71
+
72
+
73
+ # exit();
74
+ # cursor.execute("insert into demo_sessions",[request.form['username']])
75
+
76
+ print(request.form)
77
+ file = request.files['image']
78
+ print(file)
79
+ fname = secure_filename(file.filename)
80
+
81
+ image=Image.open(file.stream).convert("RGB")
82
+ image = ImageOps.exif_transpose(image)
83
+ image=np.array(image)
84
+
85
+ # do your deep learning work
86
+ face_detector.image_size=get_image_size(session["demo"]['settings']['db_mode'])
87
+ print(face_detector.image_size)
88
+
89
+ image,objs_found=face_detector.predict(image)
90
+ print(face_detector.image_size)
91
+
92
+ all_aligned_crops=fd_get_crops(image,objs_found,aligner_obj,resize=(face_recognizer.model_config.input_size,face_recognizer.model_config.input_size))
93
+ all_aligned_crops_base64=[]
94
+ all_aligned_crops_names=[]
95
+
96
+ for i,aligned_crop in enumerate(all_aligned_crops):
97
+ all_aligned_crops_base64.append(helper.image_to_base64(aligned_crop))
98
+
99
+ if (len(all_aligned_crops_base64)!=0):
100
+ image=fd.pred_image(image,objs_found)
101
+
102
+ img_base64=helper.image_to_base64(image)
103
+ print(img_base64[:10])
104
+
105
+ return jsonify({"message":"successful","image":img_base64,"image_name":fname,"crops":all_aligned_crops_base64})
106
+
107
+
108
+ @bp.route("/update_crops_labels/",methods=["POST"])
109
+ @load_settings
110
+ def update_crops_labels():
111
+ print(request.form.keys())
112
+
113
+ imgs_base64=request.form['faces'].split(",")
114
+ print(len(imgs_base64))
115
+ all_img_features=[]
116
+ for img_base64 in imgs_base64:
117
+ img=cv2.resize(base64_to_image(img_base64),[face_recognizer.model_config.input_size,face_recognizer.model_config.input_size])
118
+ all_img_features.append(face_recognizer.feature_extractor.predict(img[None,...],verbose=0)[0])
119
+ all_img_features[-1]=all_img_features[-1].astype("float32").tobytes().decode("latin-1")
120
+
121
+ print(all_img_features.__len__())
122
+ # for decoding numpy array
123
+ # print(all_img_features[0])
124
+ # print(np.frombuffer(all_img_features[0].encode("latin-1"),dtype="float32"))
125
+
126
+ return jsonify({"message":"success","features":all_img_features})
127
+
128
+ @bp.route("/face_recognition/",methods=["POST"])
129
+ @load_settings
130
+ def face_recognition():
131
+
132
+ file = request.files['image']
133
+ # print(file)
134
+
135
+ image=Image.open(file.stream).convert("RGB")
136
+ image = ImageOps.exif_transpose(image)
137
+ image=np.array(image)
138
+ db_images=json.loads(request.form['db_images'])
139
+
140
+ db_faces_features=[]
141
+ names=[]
142
+ for name in db_images:
143
+ names.append(name)
144
+ person_features=[]
145
+ for decoded_features in db_images[name]:
146
+ person_features.append(np.frombuffer(decoded_features.encode("latin-1"),dtype="float32"))
147
+ person_features=np.array(person_features)
148
+ db_faces_features.append(person_features)
149
+
150
+ for i in range(len(names)):
151
+ print(names[i],":",db_faces_features[i].shape)
152
+
153
+ # face_recognizer.set_face_db_and_mode(faces=faces,db_faces_features=db_faces_features,distance_mode="avg",recognition_mode="repeat")
154
+ face_recognizer.set_face_db_and_mode(faces=names,db_faces_features=db_faces_features,distance_mode="best",recognition_mode="repeat")
155
+
156
+ face_detector.image_size=get_image_size(session["demo"]['settings']['fr_mode'])
157
+
158
+ img,objs_found=face_detector.predict(image)
159
+ h,w=img.shape[:2]
160
+ tree=fr_helper.objs_found_to_xml("test.jpg",w,h,objs_found)
161
+ tree=face_recognizer.predict(img,tree)
162
+ pred_img=fr_helper.show_pred_image(tree,img)
163
+
164
+ pred_img=helper.image_to_base64(pred_img)
165
+
166
+ return jsonify({"message":"success",'image':pred_img})
167
+
168
+
169
+ @bp.route("/get_settings/",methods=['GET'])
170
+ def get_settings():
171
+ session.permanent=True
172
+ if "demo" not in session:
173
+ dataBase = access_database_as_admin()
174
+ cursor=dataBase.cursor()
175
+ cursor.execute("select * from default_settings where page='demo'")
176
+
177
+ session["demo"]={'settings':dict()}
178
+ session["demo"]['settings']= dict(zip(cursor.column_names, cursor.fetchone()))
179
+ # Disconnecting from the server
180
+ dataBase.commit()
181
+ dataBase.close()
182
+
183
+ return session["demo"]['settings']
184
+
185
+ @bp.route("/reset_settings/",methods=['GET'])
186
+ def reset_settings():
187
+ del session["demo"]
188
+
189
+ return {"message":"success"}
190
+
191
+ @bp.route("/update_settings/",methods=['POST'])
192
+ def update_settings():
193
+ json_data=request.get_json()
194
+
195
+ if "demo" not in session:
196
+ session["demo"]={'settings':dict()}
197
+ # print(json_data)
198
+ session["demo"]['settings']['p_thres']=float(json_data['p_thres'])
199
+ session["demo"]['settings']['nms_thres']=float(json_data['nms_thres'])
200
+ session["demo"]['settings']['large_size']=int(json_data['large_size'])
201
+ session["demo"]['settings']['small_size']=int(json_data['small_size'])
202
+ session["demo"]['settings']['d_thres']=float(json_data['d_thres'])
203
+ session["demo"]['settings']['a_thres']=float(json_data['a_thres'])
204
+ session["demo"]['settings']['db_mode']=json_data['db_mode']
205
+ session["demo"]['settings']['fr_mode']=json_data['fr_mode']
206
+
207
+ return {"message":"success"}
app/face_detection/Models/v1/anchors.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ 1.577280900000000097e+00 1.936586900000000000e+00
2
+ 8.381339999999999790e+00 1.007399999999999984e+01
3
+ 4.881808999999999621e+00 5.764687000000000339e+00
4
+ 2.773467000000000127e+00 3.284511999999999876e+00
app/face_detection/Models/v1/model.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:90dd2a59c7acc25d967c9914a7a53362ed2229c56e3105f538e04388fce70390
3
+ size 607092424
app/face_detection/config.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import tensorflow.keras.backend as K
3
+
4
+
5
+
6
+ cell_size=32
7
+ class_names=['face']
8
+ class_colors={class_name:np.random.rand(3) for class_name in class_names}
9
+
10
+
11
+
12
+ class_to_idx={class_name:i for i,class_name in enumerate(class_names)}
13
+ idx_to_class={i:class_name for i,class_name in enumerate(class_names)}
14
+
15
+
app/face_detection/create_load_model.py ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import tensorflow as tf
3
+ from tensorflow.keras import Model,layers
4
+ from app.face_detection.config import class_names
5
+
6
+ os.environ['CUDA_VISIBLE_DEVICES'] = '-1'
7
+ # custom layer for reshaping last layer
8
+
9
+ # custom layer for reshaping last layer
10
+
11
+ class yolo_reshape(tf.keras.layers.Layer):
12
+ global num_anchors
13
+ def __init__(self, **kwargs):
14
+ super(yolo_reshape,self).__init__()
15
+ self.last_item=(5+len(class_names))
16
+ def call(self,output_layer):
17
+ shape = [tf.shape(output_layer)[k] for k in range(4)]
18
+ # print(shape)
19
+ # tf.print(shape)
20
+ return tf.reshape(output_layer,[shape[0],shape[1],shape[2],num_anchors,self.last_item])
21
+
22
+ def create_model():
23
+ global num_anchors
24
+ def space_to_depth_x2(x):
25
+ return tf.nn.space_to_depth(x,block_size=2)
26
+
27
+ x_input=layers.Input(shape=(None,None,3))
28
+ x=layers.Lambda(lambda x:x/255.)(x_input)
29
+ x=layers.Conv2D(32,(3,3),strides=(1,1),padding='same',name='conv_1',use_bias=False)(x)
30
+ x=layers.BatchNormalization(name='norm_1')(x)
31
+ x=layers.LeakyReLU(alpha=0.1)(x)
32
+ x=layers.MaxPooling2D(pool_size=(2,2))(x)
33
+
34
+ x=layers.Conv2D(64,(3,3),strides=(1,1),padding='same',name='conv_2',use_bias=False)(x)
35
+ x=layers.BatchNormalization(name='norm_2')(x)
36
+ x=layers.LeakyReLU(alpha=0.1)(x)
37
+ x=layers.MaxPooling2D(pool_size=(2,2))(x)
38
+
39
+ x=layers.Conv2D(128,(3,3),strides=(1,1),padding='same',name='conv_3',use_bias=False)(x)
40
+ x=layers.BatchNormalization(name='norm_3')(x)
41
+ x=layers.LeakyReLU(alpha=0.1)(x)
42
+
43
+ x=layers.Conv2D(64,(1,1),strides=(1,1),padding='same',name='conv_4',use_bias=False)(x)
44
+ x=layers.BatchNormalization(name='norm_4')(x)
45
+ x=layers.LeakyReLU(alpha=0.1)(x)
46
+
47
+ x=layers.Conv2D(128,(3,3),strides=(1,1),padding='same',name='conv_5',use_bias=False)(x)
48
+ x=layers.BatchNormalization(name='norm_5')(x)
49
+ x=layers.LeakyReLU(alpha=0.1)(x)
50
+ x=layers.MaxPooling2D(pool_size=(2,2))(x)
51
+
52
+ x=layers.Conv2D(256,(3,3),strides=(1,1),padding='same',name='conv_6',use_bias=False)(x)
53
+ x=layers.BatchNormalization(name='norm_6')(x)
54
+ x=layers.LeakyReLU(alpha=0.1)(x)
55
+
56
+ x=layers.Conv2D(128,(1,1),strides=(1,1),padding='same',name='conv_7',use_bias=False)(x)
57
+ x=layers.BatchNormalization(name='norm_7')(x)
58
+ x=layers.LeakyReLU(alpha=0.1)(x)
59
+
60
+ x=layers.Conv2D(256,(3,3),strides=(1,1),padding='same',name='conv_8',use_bias=False)(x)
61
+ x=layers.BatchNormalization(name='norm_8')(x)
62
+ x=layers.LeakyReLU(alpha=0.1)(x)
63
+ x=layers.MaxPooling2D(pool_size=(2,2))(x)
64
+
65
+ x=layers.Conv2D(512,(3,3),strides=(1,1),padding='same',name='conv_9',use_bias=False)(x)
66
+ x=layers.BatchNormalization(name='norm_9')(x)
67
+ x=layers.LeakyReLU(alpha=0.1)(x)
68
+
69
+ x=layers.Conv2D(256,(1,1),strides=(1,1),padding='same',name='conv_10',use_bias=False)(x)
70
+ x=layers.BatchNormalization(name='norm_10')(x)
71
+ x=layers.LeakyReLU(alpha=0.1)(x)
72
+
73
+ x=layers.Conv2D(512,(3,3),strides=(1,1),padding='same',name='conv_11',use_bias=False)(x)
74
+ x=layers.BatchNormalization(name='norm_11')(x)
75
+ x=layers.LeakyReLU(alpha=0.1)(x)
76
+
77
+ x=layers.Conv2D(256,(1,1),strides=(1,1),padding='same',name='conv_12',use_bias=False)(x)
78
+ x=layers.BatchNormalization(name='norm_12')(x)
79
+ x=layers.LeakyReLU(alpha=0.1)(x)
80
+
81
+ x=layers.Conv2D(512,(3,3),strides=(1,1),padding='same',name='conv_13',use_bias=False)(x)
82
+ x=layers.BatchNormalization(name='norm_13')(x)
83
+ x=layers.LeakyReLU(alpha=0.1)(x)
84
+
85
+ skip_connection = x
86
+
87
+ x=layers.MaxPooling2D(pool_size=(2,2))(x)
88
+
89
+ x=layers.Conv2D(1024,(3,3),strides=(1,1),padding='same',name='conv_14',use_bias=False)(x)
90
+ x=layers.BatchNormalization(name='norm_14')(x)
91
+ x=layers.LeakyReLU(alpha=0.1)(x)
92
+
93
+ x=layers.Conv2D(512,(1,1),strides=(1,1),padding='same',name='conv_15',use_bias=False)(x)
94
+ x=layers.BatchNormalization(name='norm_15')(x)
95
+ x=layers.LeakyReLU(alpha=0.1)(x)
96
+
97
+ x=layers.Conv2D(1024,(3,3),strides=(1,1),padding='same',name='conv_16',use_bias=False)(x)
98
+ x=layers.BatchNormalization(name='norm_16')(x)
99
+ x=layers.LeakyReLU(alpha=0.1)(x)
100
+
101
+ x=layers.Conv2D(512,(1,1),strides=(1,1),padding='same',name='conv_17',use_bias=False)(x)
102
+ x=layers.BatchNormalization(name='norm_17')(x)
103
+ x=layers.LeakyReLU(alpha=0.1)(x)
104
+
105
+ x=layers.Conv2D(1024,(3,3),strides=(1,1),padding='same',name='conv_18',use_bias=False)(x)
106
+ x=layers.BatchNormalization(name='norm_18')(x)
107
+ x=layers.LeakyReLU(alpha=0.1)(x)
108
+
109
+ x=layers.Conv2D(1024,(3,3),strides=(1,1),padding='same',name='conv_19',use_bias=False)(x)
110
+ x=layers.BatchNormalization(name='norm_19')(x)
111
+ x=layers.LeakyReLU(alpha=0.1)(x)
112
+
113
+ x=layers.Conv2D(1024,(3,3),strides=(1,1),padding='same',name='conv_20',use_bias=False)(x)
114
+ x=layers.BatchNormalization(name='norm_20')(x)
115
+ x=layers.LeakyReLU(alpha=0.1)(x)
116
+
117
+ skip_connection=layers.Conv2D(64,(1,1),strides=(1,1),padding='same',name='conv_21',use_bias=False)(skip_connection)
118
+ skip_connection=layers.BatchNormalization(name='norm_21')(skip_connection)
119
+ skip_connection=layers.LeakyReLU(alpha=0.1)(skip_connection)
120
+ skip_connection=layers.Lambda(space_to_depth_x2)(skip_connection) # halfs the resolution and add more depth
121
+
122
+ x=layers.concatenate([skip_connection,x])
123
+ x=layers.Conv2D(1024,(3,3),strides=(1,1),padding='same',name='conv_22',use_bias=False)(x)
124
+ x=layers.BatchNormalization(name='norm_22')(x)
125
+ x=layers.LeakyReLU(alpha=0.1)(x)
126
+
127
+ x=layers.Conv2D((num_anchors*(5+len(class_names))),(1,1),strides=(1,1),padding='same',name='conv_23')(x)
128
+ out=yolo_reshape()(x)
129
+
130
+ model=Model(x_input,out,name='yolo_v2_model')
131
+ # model.summary()
132
+ return model
133
+
134
+ def create_tiny_model():
135
+ global num_anchors
136
+
137
+ x_input=layers.Input(shape=(416,416,3))
138
+ x=layers.Lambda(lambda x:x/255.)(x_input)
139
+ x=layers.Conv2D(16,(3,3),strides=(1,1),padding='same',name='conv_1',use_bias=False)(x)
140
+ x=layers.BatchNormalization(name='norm_1')(x)
141
+ x=layers.LeakyReLU(alpha=0.1)(x)
142
+ x=layers.MaxPooling2D(pool_size=(2,2),strides=(2,2))(x)
143
+
144
+ x=layers.Conv2D(32,(3,3),strides=(1,1),padding='same',name='conv_2',use_bias=False)(x)
145
+ x=layers.BatchNormalization(name='norm_2')(x)
146
+ x=layers.LeakyReLU(alpha=0.1)(x)
147
+ x=layers.MaxPooling2D(pool_size=(2,2),strides=(2,2))(x)
148
+
149
+ x=layers.Conv2D(64,(3,3),strides=(1,1),padding='same',name='conv_3',use_bias=False)(x)
150
+ x=layers.BatchNormalization(name='norm_3')(x)
151
+ x=layers.LeakyReLU(alpha=0.1)(x)
152
+ x=layers.MaxPooling2D(pool_size=(2,2),strides=(2,2))(x)
153
+
154
+ x=layers.Conv2D(128,(3,3),strides=(1,1),padding='same',name='conv_4',use_bias=False)(x)
155
+ x=layers.BatchNormalization(name='norm_4')(x)
156
+ x=layers.LeakyReLU(alpha=0.1)(x)
157
+ x=layers.MaxPooling2D(pool_size=(2,2),strides=(2,2))(x)
158
+
159
+ x=layers.Conv2D(256,(3,3),strides=(1,1),padding='same',name='conv_5',use_bias=False)(x)
160
+ x=layers.BatchNormalization(name='norm_5')(x)
161
+ x=layers.LeakyReLU(alpha=0.1)(x)
162
+ x=layers.MaxPooling2D(pool_size=(2,2),strides=(2,2))(x)
163
+
164
+ x=layers.Conv2D(512,(3,3),strides=(1,1),padding='same',name='conv_6',use_bias=False)(x)
165
+ x=layers.BatchNormalization(name='norm_6')(x)
166
+ x=layers.LeakyReLU(alpha=0.1)(x)
167
+ # x=layers.MaxPooling2D(pool_size=(2,2),strides=(1,1))(x)
168
+
169
+ x=layers.Conv2D(1024,(3,3),strides=(1,1),padding='same',name='conv_7',use_bias=False)(x)
170
+ x=layers.BatchNormalization(name='norm_7')(x)
171
+ x=layers.LeakyReLU(alpha=0.1)(x)
172
+
173
+
174
+ x=layers.Conv2D(1024,(3,3),strides=(1,1),padding='same',name='conv_8',use_bias=False)(x)
175
+ x=layers.BatchNormalization(name='norm_8')(x)
176
+ x=layers.LeakyReLU(alpha=0.1)(x)
177
+
178
+ x=layers.Conv2D((num_anchors*(5+len(class_names))),(1,1),strides=(1,1),padding='same',name='conv_9')(x)
179
+ out=yolo_reshape()(x)
180
+
181
+ model=Model(x_input,out,name='yolo_v2_tiny_model')
182
+ # model.summary()
183
+ return model
184
+
185
+ def load_model(path):
186
+ # model=tf.keras.models.load_model(path,custom_objects={'yolo_dynamic_reshape':yolo_dynamic_reshape},compile=False)
187
+ model=create_model()
188
+ model.load_weights(path)
189
+ # model=tf.keras.models.load_model(path)
190
+ return model
191
+
192
+
193
+ import struct
194
+
195
+ def get_original_weights(model,path_to_weight = "./yolov2-voc.weights"):
196
+ global num_anchors
197
+ # path_to_weight = "./yolov2.weights"(trained on coco dataset (80 classes))
198
+ if "yolov2-voc.weights" in path_to_weight: offset=5;nb_conv = 23;
199
+ if "darknet19_448.conv.23" in path_to_weight: offset=4;nb_conv = 18;
200
+ if "yolov2-tiny-voc.weights" in path_to_weight: offset=4;nb_conv = 9;
201
+ print(offset,nb_conv)
202
+
203
+ class WeightReader:
204
+ def __init__(self, weight_file):
205
+ self.offset = offset # an offset of 5 as first 5 values are non weight values(they are weight header)(for yolov2-voc.weights)
206
+ # self.all_weights = np.fromfile(weight_file, dtype='float32')
207
+ self.all_weights = open(weight_file,'rb')
208
+ weight_header=struct.unpack(f'{offset}i', self.all_weights.read(offset*4))
209
+ # print("weight Header(major, minor, revision, seen):",weight_header)
210
+
211
+ def read_bytes(self, size):
212
+ weights = struct.unpack('%df' % size, self.all_weights.read(size*4))
213
+ # print(weights)
214
+ # input("wait now forever")
215
+ return np.array(weights)
216
+
217
+ weight_reader = WeightReader(path_to_weight)
218
+ # print("all_weights = {}".format(np.fromfile(path_to_weight, dtype='float32').shape[0]-weight_reader.offset))
219
+
220
+ for i in range(1, nb_conv+1):
221
+ conv_layer = model.get_layer('conv_' + str(i))
222
+
223
+ if i < nb_conv:
224
+ norm_layer = model.get_layer('norm_' + str(i))
225
+
226
+ size = np.prod(norm_layer.get_weights()[0].shape)
227
+
228
+ beta = weight_reader.read_bytes(size)
229
+ gamma = weight_reader.read_bytes(size)
230
+ mean = weight_reader.read_bytes(size)
231
+ var = weight_reader.read_bytes(size)
232
+
233
+ weights = norm_layer.set_weights([gamma, beta, mean, var])
234
+
235
+ if len(conv_layer.get_weights()) > 1:
236
+ bias = weight_reader.read_bytes(np.prod(conv_layer.get_weights()[1].shape))
237
+ kernel = weight_reader.read_bytes(np.prod(conv_layer.get_weights()[0].shape))
238
+ kernel = kernel.reshape(list(reversed(conv_layer.get_weights()[0].shape)))
239
+ kernel = kernel.transpose([2,3,1,0])
240
+ # print(kernel.shape)
241
+ kernel=kernel.reshape([*kernel.shape[:-1],num_anchors,-1]) # reshape to this format so we change change position of p idx
242
+ idx=4 # in darknet each object was encoded as [x,y,w,h,p,c] but we use [p,x,y,w,h,c]
243
+ kernel=np.concatenate([kernel[...,idx:idx+1],kernel[...,:idx],kernel[...,idx+1:]],axis=-1) # setting p to idx 0
244
+ # print(kernel.shape)
245
+ kernel=kernel.reshape([*kernel.shape[:-2],-1])
246
+ # print(kernel.shape)
247
+ conv_layer.set_weights([kernel, bias])
248
+ else:
249
+ kernel = weight_reader.read_bytes(np.prod(conv_layer.get_weights()[0].shape))
250
+ kernel = kernel.reshape(list(reversed(conv_layer.get_weights()[0].shape)))
251
+ kernel = kernel.transpose([2,3,1,0])
252
+ conv_layer.set_weights([kernel])
253
+
254
+ return model
app/face_detection/decode_yolo_v2.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import matplotlib.pyplot as plt
3
+ from matplotlib.patches import Rectangle
4
+ import copy
5
+ import tensorflow.keras.backend as K
6
+ import cv2
7
+ from app.face_detection.config import cell_size,idx_to_class,class_to_idx,class_colors
8
+
9
+
10
+
11
+ def get_objects(y_pred,p=0.5,decode_preds=True,idx=None):
12
+ global tf_anchors
13
+ output_size=y_pred.shape[1]
14
+ image_size=cell_size*output_size
15
+
16
+ y_pred=copy.deepcopy(y_pred)
17
+ if decode_preds:
18
+ y_pred[...,0]=K.sigmoid(y_pred[...,0])
19
+ y_pred[...,3:5]=np.clip((K.exp(y_pred[...,3:5])*tf_anchors).numpy(),0,output_size)
20
+ # y_pred[...,3:5]=np.clip(y_pred[...,3:5],0,output_size)
21
+ objs_found=[]
22
+ idxs=np.where(y_pred[...,0]>=p)
23
+ if np.size(idxs):
24
+ for i,obj in enumerate(y_pred[idxs[0],idxs[1],idxs[2],:]):
25
+ # obj (p,x,y,w,h,c_1,c_2,c_3,c_4,c_5.......c_n)
26
+ if decode_preds:
27
+ obj[1:3]=K.sigmoid(obj[1:3]) # x,y
28
+
29
+ prob=obj[0]
30
+ obj=obj[1:]
31
+
32
+ obj[4]=np.argmax(obj[4:])
33
+ obj=obj[:5]
34
+
35
+ obj[0]=idxs[1][i]+obj[0] # center x
36
+ obj[1]=idxs[0][i]+obj[1] # center y
37
+
38
+ obj[0]=np.clip(obj[0]-(obj[2]/2),0,output_size) # xmin
39
+ obj[1]=np.clip(obj[1]-(obj[3]/2),0,output_size) # ymin
40
+
41
+
42
+ obj_name=idx_to_class[obj[4]]
43
+
44
+
45
+ obj_details={'p':prob,'xywh':list(obj[:-1]/output_size),'class_idx':int(obj[4]),'class':obj_name} # xywh are scaled 0 to 1
46
+ if idx is not None:obj_details['idx']=idx
47
+ objs_found.append(obj_details)
48
+ objs_found=sorted(objs_found,key=lambda x:x['p'],reverse=True)
49
+ return objs_found
50
+
51
+ def list_get_iou(bboxes1, bboxes2):
52
+
53
+ bboxes1 = [bboxes1[0],bboxes1[1],bboxes1[0]+bboxes1[2],bboxes1[1]+bboxes1[3]]
54
+ bboxes2 = [bboxes2[0],bboxes2[1],bboxes2[0]+bboxes2[2],bboxes2[1]+bboxes2[3]]
55
+
56
+ xA = max(bboxes1[0], bboxes2[0])
57
+ yA = max(bboxes1[1], bboxes2[1])
58
+ xB = min(bboxes1[2], bboxes2[2])
59
+ yB = min(bboxes1[3], bboxes2[3])
60
+
61
+ intersection_area = max(0, xB - xA ) * max(0, yB - yA )
62
+
63
+ box1_area = (bboxes1[2] - bboxes1[0] ) * (bboxes1[3] - bboxes1[1] )
64
+ box2_area = (bboxes2[2] - bboxes2[0] ) * (bboxes2[3] - bboxes2[1] )
65
+
66
+ iou = intersection_area / float(box1_area + box2_area - intersection_area+1e-6)
67
+
68
+ return iou
69
+
70
+ def nms(objs_found,iou_threshold=0.2):
71
+ objs_found=np.array(copy.deepcopy(objs_found))
72
+ best_boxes=[]
73
+ while len(objs_found)>0:
74
+ obj=objs_found[0]
75
+ objs_found=objs_found[1:]
76
+
77
+ delete_idx=[]
78
+ for b_idx,b in enumerate(objs_found):
79
+
80
+ if obj['class_idx']==b['class_idx']:
81
+ iou=list_get_iou(obj['xywh'],b['xywh'])
82
+ if iou>= iou_threshold:
83
+ delete_idx.append(b_idx)
84
+ objs_found=np.delete(objs_found,delete_idx)
85
+ best_boxes.append(obj)
86
+ return best_boxes
87
+
88
+ def show_objects(img,objs_found,return_img=False):
89
+ plt.imshow(img)
90
+ for i in range(len(objs_found)):
91
+ p=objs_found[i]['p']
92
+ obj=objs_found[i]['xywh']
93
+ obj_name=objs_found[i]['class']
94
+ plt.gca().add_patch(Rectangle((obj[0],obj[1]),(obj[2]),(obj[3]),linewidth=4,edgecolor=class_colors[obj_name],facecolor='none'))
95
+ plt.text(obj[0],obj[1],obj_name)
96
+
97
+
98
+
99
+ def pred_image(img,objs_found,font_scale=2,thickness=4):
100
+ for i in range(len(objs_found)):
101
+ p=objs_found[i]['p']
102
+ obj=np.array(objs_found[i]['xywh'])*img.shape[0]
103
+ obj_name=objs_found[i]['class']
104
+
105
+ img=cv2.rectangle(img,(int(obj[0]),int(obj[1])),(int(obj[0]+obj[2]),int(obj[1]+obj[3])),(class_colors[obj_name]*255),thickness)
106
+ img=cv2.putText(img,obj_name,(int(obj[0]),int(obj[1])),cv2.FONT_HERSHEY_SIMPLEX,font_scale, (0,0,0), thickness, lineType=cv2.LINE_AA)
107
+ # draw_text(img, "world", font_scale=4, pos=(10, 20 + h), text_color_bg=(255, 0, 0))
108
+ return img
app/face_detection/helper.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import numpy as np
3
+
4
+
5
+ def get_crops(img,objs_found,aligner=None,resize:tuple=None):
6
+ img_h,img_w,_=img.shape
7
+ all_crops=[]
8
+ for obj_found in objs_found:
9
+ xmin,ymin=obj_found['xywh'][0],obj_found['xywh'][1]
10
+ xmax,ymax=xmin+obj_found['xywh'][2],ymin+obj_found['xywh'][3]
11
+ # rescale them
12
+ xmin,ymin=int(xmin*img_w),int(ymin*img_h)
13
+ xmax,ymax=int(xmax*img_w),int(ymax*img_h)
14
+
15
+ crop=img[ymin:ymax,xmin:xmax]
16
+ if aligner is not None:
17
+ crop=aligner.align_image(crop)
18
+ if crop is None: continue
19
+ if resize is not None:
20
+ crop=cv2.resize(crop,resize)
21
+ all_crops.append(crop)
22
+
23
+ return all_crops
24
+
app/face_detection/inference.py ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import numpy as np
3
+ import matplotlib.pyplot as plt
4
+ import math
5
+ import copy
6
+
7
+
8
+
9
+
10
+ def tiler(img,image_size,tiles=2,pad=0,):
11
+ # pad is 0 to 0.9%
12
+ h,w=img.shape[:2]
13
+
14
+ tile_h=(h//tiles)
15
+ tile_w=(w//tiles)
16
+
17
+ pad=int(tile_h*pad)
18
+
19
+ crops=[]
20
+ coordinates=[]
21
+ for i in range(tiles):
22
+ for j in range(tiles):
23
+ ymin=tile_h*i
24
+ xmin=tile_w*j
25
+
26
+ if i!=0:ymin=ymin-pad
27
+ if j!=0:xmin=xmin-pad
28
+
29
+ ymax=min(ymin+tile_h+pad,h)
30
+ xmax=min(xmin+tile_w+pad,w)
31
+
32
+ # crops.append(img[ymin:ymax,xmin:xmax])
33
+ crops.append(cv2.resize(img[ymin:ymax,xmin:xmax],[image_size,image_size]))
34
+ coordinates.append((xmin,ymin,xmax,ymax))
35
+ # print(crops[-1].shape)
36
+ return coordinates,np.array(crops)
37
+
38
+ class square_crop:
39
+ def __call__(self,img):
40
+ h,w=img.shape[:2]
41
+ self.w_removed,self.h_removed=0,0
42
+ if w>h:
43
+ self.w_removed=(w-h)//2
44
+ img=img[:,self.w_removed:w-self.w_removed]
45
+ elif h>w:
46
+ self.h_removed=(h-w)//2
47
+ img=img[self.h_removed:h-self.h_removed,:]
48
+
49
+ h,w=img.shape[:2]
50
+ self.w_removed,self.h_removed=self.w_removed/w,self.h_removed/h
51
+ return img
52
+ def rescale(self,objs_found):
53
+ raise NotImplementedError
54
+
55
+ class square_pad:
56
+ def __call__(self,img,color=(0,0,0)):
57
+ h,w=img.shape[:2]
58
+ self.w_added,self.h_added=0,0
59
+ if h>w:
60
+ self.w_added=int((h-w)/2)
61
+ padding=(np.ones([h,self.w_added,3])*np.array(color)[None,None,:]).astype("uint8")
62
+ img=np.concatenate([padding,img,padding],axis=1)
63
+ elif w>h:
64
+ self.h_added=int((w-h)/2)
65
+ padding=(np.ones([self.h_added,w,3])*np.array(color)[None,None,:]).astype("uint8")
66
+ img=np.concatenate([padding,img,padding],axis=0)
67
+ h,w=img.shape[:2]
68
+
69
+ self.w_added,self.h_added=self.w_added/w,self.h_added/h
70
+
71
+ return img
72
+ def rescale(self,objs_found):
73
+
74
+ for i in range(len(objs_found)):
75
+ objs_found[i]['xywh'][0]=(objs_found[i]['xywh'][0]-self.w_added)/(1-2*self.w_added)
76
+ objs_found[i]['xywh'][1]=(objs_found[i]['xywh'][1]-self.h_added)/(1-2*self.h_added)
77
+ objs_found[i]['xywh'][2]=(objs_found[i]['xywh'][2])/(1-2*self.w_added)
78
+ objs_found[i]['xywh'][3]=(objs_found[i]['xywh'][3])/(1-2*self.h_added)
79
+ return objs_found
80
+
81
+
82
+ class face_detection:
83
+ def __init__(self,model_path):
84
+ ################### set num_anchors & tf_anchors ###################
85
+ anchor_boxes=np.loadtxt(model_path+"/anchors.txt")
86
+ num_anchors=anchor_boxes.shape[0]
87
+ tf_anchors=K.reshape(K.variable(anchor_boxes),[1, 1, 1, num_anchors, 2])
88
+ load_model_lib.num_anchors=num_anchors
89
+ decode_model_lib.tf_anchors=tf_anchors
90
+ ####################################################################
91
+
92
+ self.model=load_model(model_path+"/model.h5")
93
+
94
+ self.modes_available=["tiled","sized"]
95
+ self.square_preprocessing=square_crop
96
+
97
+ def invoke_model(self,img,p=0.2,iou_threshold=0.3,batch_size=4):
98
+ all_objs_found=[]
99
+
100
+ for i in range(math.ceil(img.shape[0]/batch_size)):
101
+
102
+ y_pred=self.model.predict(img[int(i*batch_size):int((i+1)*batch_size)].astype('float32'),verbose=0)
103
+ # print(y_pred.shape)
104
+
105
+ for i in range(y_pred.shape[0]):
106
+ objs_found=get_objects(y_pred[i],p=p)
107
+ objs_found=nms(objs_found,iou_threshold=iou_threshold)
108
+ all_objs_found.append(objs_found)
109
+
110
+ return all_objs_found
111
+ def get_tiled_output(self,img,p_thres,nms_thres,tiles,pad,image_size,save_tiles=None,batch_size=4):
112
+ # pad is 0 to 0.5%
113
+ # pad=0.05
114
+ img=cv2.resize(img,[image_size*tiles,image_size*tiles])
115
+
116
+ coordinates,crops=tiler(img,tiles=tiles,pad=pad,image_size=image_size)
117
+
118
+ all_objs_found=self.invoke_model(crops,p_thres,nms_thres,batch_size)
119
+
120
+ if save_tiles:
121
+ fig=plt.figure(figsize=(3*tiles,3*tiles))
122
+ plt.axis("off")
123
+ plt.title(f"pad:{pad}")
124
+
125
+ for i in range(int(tiles*tiles)):
126
+ fig.add_subplot(tiles,tiles,i+1)
127
+ plt.axis("off")
128
+ plt.imshow(pred_image(crops[i],all_objs_found[i]))
129
+ # plt.show(block=False)
130
+ plt.savefig(save_tiles+f"_{tiles}.jpg")
131
+ plt.close()
132
+
133
+ all_objs_found_joined=[]
134
+ for i in range(int(tiles*tiles)):
135
+ xmin,ymin,xmax,ymax=coordinates[i]
136
+ w,h=xmax-xmin,ymax-ymin
137
+ for j in range(all_objs_found[i].__len__()):
138
+ # all_objs_found[i][j]['xywh']=np.array(all_objs_found[i][j]['xywh'])/image_size
139
+ all_objs_found[i][j]['xywh']=np.array(all_objs_found[i][j]['xywh'])*w
140
+ all_objs_found[i][j]['xywh'][0]+=xmin
141
+ all_objs_found[i][j]['xywh'][1]+=ymin
142
+ all_objs_found[i][j]['xywh']=(all_objs_found[i][j]['xywh']/(image_size*tiles)).tolist()
143
+ all_objs_found_joined.extend(all_objs_found[i])
144
+
145
+ all_objs_found_joined=sorted(all_objs_found_joined,reverse=True,key=lambda x:x["p"]) # This was very important
146
+ all_objs_found_joined=nms(all_objs_found_joined,nms_thres)
147
+
148
+
149
+ return all_objs_found_joined
150
+
151
+
152
+ def set_mode(self,p_thres,nms_thres,batch_size=4,mode="tiled",**kwargs):
153
+ # mode : tiled or sized
154
+
155
+ self.p_thres=p_thres
156
+ self.nms_thres=nms_thres
157
+ self.batch_size=batch_size
158
+
159
+ if mode=="tiled":
160
+ try:
161
+ self.image_size=kwargs['image_size']
162
+ if "tiles" not in kwargs:
163
+ self.tiles=[1]
164
+ self.pad=0
165
+ else:
166
+ self.tiles=kwargs['tiles'] if(type(kwargs['tiles'])==type(list([1])) or type(kwargs['tiles'])==type(np.zeros([]))) else [kwargs['tiles']]
167
+ self.pad=kwargs['pad']
168
+ except:
169
+
170
+ raise ValueError(f"Not all tiled mode parameters passed.")
171
+
172
+ self.save_tiles=kwargs["save_tiles"] if ("save_tiles" in kwargs) else None
173
+
174
+ elif mode=="sized":
175
+ try:
176
+ # self.image_size=kwargs['image_size']
177
+ self.image_size=kwargs['image_size'] if(type(kwargs['image_size'])==type(list([1])) or type(kwargs['image_size'])==type(np.zeros([]))) else [kwargs['image_size']]
178
+ self.batch_size=1
179
+ except:
180
+ raise ValueError(f"Not all Sized mode parameters passed.")
181
+ else:
182
+ raise ValueError(f"Unavailable mode={mode} \nmode can only be one of:{self.modes_available}")
183
+
184
+ self.mode=mode
185
+
186
+
187
+ def predict_once(self,img):
188
+
189
+ if (type(img)==str):
190
+ img=cv2.cvtColor(cv2.imread(img),cv2.COLOR_BGR2RGB)
191
+ elif (type(img)!=type(np.zeros([]))):
192
+ raise TypeError(f"Inappropriate type of image={type(img)}")
193
+
194
+ # if img.shape[0]!=img.shape[1]: raise ValueError(f"The image should be squared")
195
+
196
+
197
+ if not hasattr(self,'mode'): raise ValueError(f"First call set_mode function to set mode using one of the following mode :{self.modes_available}")
198
+
199
+ if self.mode=='tiled':
200
+ if type(self.tiles)==type(list([1])) or type(self.tiles)==type(np.zeros([])): raise TypeError("use advanced_predict function for inference on multiple tiles")
201
+ objs_found=self.get_tiled_output(img,p_thres=self.p_thres,nms_thres=self.nms_thres,tiles=self.tiles,pad=self.pad,image_size=self.image_size,save_tiles=self.save_tiles)
202
+ elif self.mode=='sized':
203
+ if type(self.image_size)==type(list([1])) or type(self.image_size)==type(np.zeros([])): raise TypeError("use advanced_predict function for inference on multiple sizes")
204
+ resized_img=cv2.resize(img,[self.image_size,self.image_size])
205
+ objs_found=self.invoke_model(resized_img[None,:,:,:],self.p_thres,self.nms_thres,batch_size=1)[0]
206
+
207
+ return img,objs_found
208
+
209
+ def predict(self,img):
210
+
211
+ if (type(img)==str):
212
+ img=cv2.cvtColor(cv2.imread(img),cv2.COLOR_BGR2RGB)
213
+ elif (type(img)!=type(np.zeros([]))):
214
+ raise TypeError(f"Inappropriate type of image={type(img)}")
215
+
216
+ if img.shape[0]!=img.shape[1]: img=self.square_preprocessing(img)
217
+
218
+ if not hasattr(self,'mode'): raise ValueError(f"First call set_mode function to set mode using one of the following mode :{self.modes_available}")
219
+
220
+ if self.mode=="tiled":
221
+ all_objs_found=[]
222
+ all_tiles=copy.deepcopy(self.tiles)
223
+ for tiles in all_tiles:
224
+ self.tiles=tiles
225
+ _,objs_found=self.predict_once(img)
226
+ all_objs_found.extend(objs_found)
227
+ self.tiles=all_tiles
228
+
229
+ elif self.mode=="sized":
230
+ all_objs_found=[]
231
+ all_image_size=copy.deepcopy(self.image_size)
232
+ for image_size in all_image_size:
233
+ self.image_size=image_size
234
+ _,objs_found=self.predict_once(img)
235
+ all_objs_found.extend(objs_found)
236
+ self.image_size=all_image_size
237
+ all_objs_found=sorted(all_objs_found,reverse=True,key=lambda x:x["p"]) # This was very important
238
+ all_objs_found=nms(all_objs_found,self.nms_thres)
239
+
240
+ return img,all_objs_found
241
+
242
+
243
+
244
+
245
+
246
+ if __name__=="__main__":
247
+ import create_load_model as load_model_lib
248
+ import decode_yolo_v2 as decode_model_lib
249
+ from create_load_model import *
250
+ from decode_yolo_v2 import *
251
+
252
+
253
+ face_detector=face_detection("face_detection/Models/v1/")
254
+
255
+ # test_img="C:\\Users\\Home\\Downloads\\WhatsApp Image 2023-01-04 at 6.58.40 PM.jpeg"
256
+ test_img="C:\\Users\\Home\\Downloads\\family-52.jpg"
257
+
258
+ p_thres=0.5
259
+ nms_thres=0.3
260
+ tiles=3
261
+ pad=0
262
+
263
+ # face_detector.set_mode(p_thres,nms_thres,mode="tiled",tiles=[1,2],pad=pad,image_size=416,save_tiles="tile")
264
+ # face_detector.set_mode(p_thres=p_thres,nms_thres=nms_thres,image_size=608)
265
+ # face_detector.set_mode(p_thres,nms_thres,mode="sized",image_size=256)
266
+ # face_detector.set_mode(p_thres,nms_thres,mode="sized",image_size=352)
267
+ # face_detector.set_mode(p_thres,nms_thres,mode="sized",image_size=608)
268
+ face_detector.set_mode(p_thres,nms_thres,mode="sized",image_size=1024)
269
+ # face_detector.set_mode(p_thres,nms_thres,mode="sized",image_size=[608,1024])
270
+ img,objs_found=face_detector.predict(test_img)
271
+ # img,objs_found=face_detector.advanced_predict(test_img)
272
+ pred_img=pred_image(img,objs_found)
273
+ plt.figure()
274
+ plt.imshow(pred_img)
275
+ plt.show()
276
+ # cv2.imwrite("test_output.jpg",pred_img[:,:,::-1])
277
+ else:
278
+ import app.face_detection.create_load_model as load_model_lib
279
+ import app.face_detection.decode_yolo_v2 as decode_model_lib
280
+ from app.face_detection.create_load_model import *
281
+ from app.face_detection.decode_yolo_v2 import *
app/face_recognition/Models/v1/config.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ input_size=224
2
+ thres=0.5
3
+ large_distance=10
app/face_recognition/Models/v1/model.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ab0f8c73a7493b4125b24055aaee62bbc3ab99e43c8fdb1c31fef473469270a8
3
+ size 539190512
app/face_recognition/aligner.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import itertools
3
+ import numpy as np
4
+ import mediapipe as mp
5
+ import matplotlib.pyplot as plt
6
+ import PIL
7
+ import os
8
+ import shutil
9
+
10
+
11
+
12
+ class aligner:
13
+ def __init__(self,min_aligner_confidence):
14
+ mp_face_mesh = mp.solutions.face_mesh
15
+
16
+ self.face_mesh_images = mp_face_mesh.FaceMesh(static_image_mode=True, max_num_faces=1,
17
+ min_detection_confidence=min_aligner_confidence)
18
+
19
+ mp_drawing = mp.solutions.drawing_utils
20
+ mp_drawing_styles = mp.solutions.drawing_styles
21
+ LEFT_EYE_INDEXES = list(set(itertools.chain(*mp_face_mesh.FACEMESH_LEFT_EYE)))
22
+ RIGHT_EYE_INDEXES = list(set(itertools.chain(*mp_face_mesh.FACEMESH_RIGHT_EYE)))
23
+
24
+ self.LEFT_EYE_INDEX=LEFT_EYE_INDEXES[7] # eye point index
25
+ self.RIGHT_EYE_INDEX=RIGHT_EYE_INDEXES[4] # eye point index
26
+
27
+ def align_image(self,img):
28
+
29
+ # start work
30
+ face_mesh_results = self.face_mesh_images.process(img)
31
+ if face_mesh_results.multi_face_landmarks!=None:
32
+ face_landmarks=face_mesh_results.multi_face_landmarks[0]
33
+
34
+ h,w,_=img.shape
35
+
36
+ points=[]
37
+
38
+
39
+ x_coord=int(np.clip(face_landmarks.landmark[self.LEFT_EYE_INDEX].x*w,0,w))
40
+ y_coord=int(np.clip(face_landmarks.landmark[self.LEFT_EYE_INDEX].y*h,0,h))
41
+ points.append((x_coord,y_coord))
42
+
43
+
44
+ x_coord=int(np.clip(face_landmarks.landmark[self.RIGHT_EYE_INDEX].x*w,0,w))
45
+ y_coord=int(np.clip(face_landmarks.landmark[self.RIGHT_EYE_INDEX].y*h,0,h))
46
+ points.append((x_coord,y_coord))
47
+
48
+ p0=np.array(points[0],dtype='float64')
49
+ p1=np.array(points[1],dtype='float64')
50
+
51
+
52
+ h=abs(p0[1]-p1[1])
53
+ w=abs(p0[0]-p1[0])
54
+
55
+ theta=np.arctan(h/w)
56
+
57
+ angle=(theta * 180) / np.pi
58
+
59
+ def get_direction(p0,p1):
60
+ if p0[0]<p1[0]:
61
+ if p0[1]<p1[1]:
62
+ direction=1
63
+ else:
64
+ direction=-1
65
+ else:
66
+ if p1[1]<p0[1]:
67
+ direction=1
68
+ else:
69
+ direction=-1
70
+ return direction
71
+
72
+ direction=get_direction(p0,p1)
73
+ angle=direction*angle
74
+ # print("rotated anticlockwise by :",angle,"angle")
75
+ new_img = PIL.Image.fromarray(img)
76
+ new_img = new_img.rotate(angle)
77
+
78
+ return np.array(new_img)
79
+ else:
80
+ return None
app/face_recognition/config.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ min_aligner_confidence=0.6
2
+ db_dir="aligned_crops"
3
+ img_dir="images"
4
+ save_dir="results"
app/face_recognition/helper.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import xml.etree.ElementTree as ET
2
+ import numpy as np
3
+ import cv2
4
+
5
+ def show_pred_image(tree,img):
6
+ root=tree.getroot()
7
+
8
+ size=root.find('size')
9
+ w,h=int(size.find("width").text),int(size.find("height").text)
10
+ default_color=[220,255,0]
11
+ random_color=np.random.randn(3)*255
12
+
13
+ for obj in root.findall("object"):
14
+ bndbox=obj.find("bndbox")
15
+ classname=obj.find('name').text
16
+
17
+ xmin,ymin , xmax,ymax=int(bndbox.find('xmin').text),int(bndbox.find('ymin').text),int(bndbox.find('xmax').text),int(bndbox.find('ymax').text)
18
+
19
+ if classname=="face":
20
+ color=default_color
21
+ else:
22
+ color=random_color
23
+ distance=obj.find("distance").text
24
+ classname+=f"({distance})"
25
+
26
+ img=cv2.rectangle(img,(xmin,ymin),(xmax,ymax),color,7)
27
+ img=cv2.putText(img,classname,(xmin,ymin),cv2.FONT_HERSHEY_SIMPLEX,2,color,thickness=5)
28
+ return img
29
+
30
+
31
+ def xml_to_objs_found(tree):
32
+ root=tree.getroot()
33
+
34
+ size=root.find('size')
35
+ image_w,image_h=int(size.find("width").text),int(size.find("height").text)
36
+
37
+ objs_found=[]
38
+ for obj in root.findall("object"):
39
+ obj_found=dict()
40
+ bndbox=obj.find("bndbox")
41
+ classname=obj.find('name').text
42
+ distance=float(obj.find('distance').text) if classname!="face" else None
43
+
44
+ xmin,ymin , xmax,ymax=int(bndbox.find('xmin').text),int(bndbox.find('ymin').text),int(bndbox.find('xmax').text),int(bndbox.find('ymax').text)
45
+
46
+ x,y = xmin/image_w , ymin/image_h
47
+ w,h = (xmax-xmin)/image_w , (ymax-ymin)/image_h
48
+
49
+ obj_details={'xywh':[x,y,w,h],'class':classname,'distance':distance}
50
+ objs_found.append(obj_details)
51
+
52
+ return objs_found
53
+
54
+
55
+ def objs_found_to_xml(test_img,w,h,objs_found):
56
+ root=ET.Element("annotation")
57
+
58
+ filename_tag=ET.Element("filename")
59
+ filename_tag.text=test_img
60
+ root.append(filename_tag)
61
+ path_tag=ET.Element("path")
62
+ path_tag.text="./"+test_img
63
+ root.append(path_tag)
64
+
65
+
66
+ size_tag=ET.Element("size")
67
+ # w,h defined above
68
+ # print(w,h)
69
+ width_tag=ET.Element("width")
70
+ width_tag.text=str(w)
71
+ height_tag=ET.Element("height")
72
+ height_tag.text=str(h)
73
+ depth_tag=ET.Element("depth")
74
+ depth_tag.text="3"
75
+
76
+ size_tag.append(width_tag)
77
+ size_tag.append(height_tag)
78
+ size_tag.append(depth_tag)
79
+ root.append(size_tag)
80
+
81
+ # add all objects
82
+ for obj_found in objs_found:
83
+ obj_found['xywh']=np.array(obj_found['xywh'])*w
84
+
85
+ obj_tag=ET.Element("object")
86
+ name_tag=ET.Element("name")
87
+ name_tag.text=obj_found['class']
88
+ obj_tag.append(name_tag)
89
+
90
+ bndbox_tag=ET.Element("bndbox")
91
+ xmin_tag=ET.Element("xmin")
92
+ xmin_tag.text=str(int(obj_found['xywh'][0]))
93
+ ymin_tag=ET.Element("ymin")
94
+ ymin_tag.text=str(int(obj_found['xywh'][1]))
95
+ xmax_tag=ET.Element("xmax")
96
+ xmax_tag.text=str(int(obj_found['xywh'][0]+obj_found['xywh'][2]))
97
+ ymax_tag=ET.Element("ymax")
98
+ ymax_tag.text=str(int(obj_found['xywh'][1]+obj_found['xywh'][3]))
99
+
100
+ obj_found['xywh']=np.array(obj_found['xywh'])/w
101
+
102
+ bndbox_tag.append(xmin_tag)
103
+ bndbox_tag.append(ymin_tag)
104
+ bndbox_tag.append(xmax_tag)
105
+ bndbox_tag.append(ymax_tag)
106
+
107
+ obj_tag.append(bndbox_tag)
108
+ root.append(obj_tag)
109
+
110
+ xml=ET.ElementTree(root)
111
+
112
+ # with open(xml_file_path,"wb") as f:
113
+ # xml.write(f)
114
+
115
+ return xml
app/face_recognition/inference.py ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import PIL
2
+ from PIL import ImageOps
3
+ import xml.etree.ElementTree as ET
4
+ import shutil
5
+ import os
6
+ import numpy as np
7
+ from glob import glob
8
+ import tensorflow as tf
9
+ from tensorflow.keras import backend as K
10
+ import cv2
11
+ import matplotlib.pyplot as plt
12
+ import importlib
13
+
14
+
15
+
16
+ from app.face_recognition import config
17
+ from app.face_recognition.aligner import aligner
18
+
19
+
20
+
21
+ class face_recognition:
22
+ def __init__(self,model_path,thres=None,min_aligner_confidence=None):
23
+ config_file_path='.'.join(model_path.split("/"))+".config"
24
+ # print(config_file_path)
25
+ self.model_config= importlib.import_module(config_file_path)
26
+ # print(self.model_config)
27
+ self.thres=thres if thres is not None else self.model_config.thres
28
+ self.aligner=aligner(min_aligner_confidence) if min_aligner_confidence is not None else aligner(config.min_aligner_confidence)
29
+ self.feature_extractor=tf.keras.models.load_model(model_path+"/model.h5",compile=False)
30
+
31
+
32
+
33
+ def euclidean_distance(self,vectors):
34
+ squared_sum=np.sum(np.square(vectors[0]-vectors[1]),axis=-1,keepdims=True)
35
+ return np.sqrt(np.maximum(squared_sum,1e-7))
36
+
37
+
38
+
39
+ def calculate_distance(self,crop_img,db_faces_features,mode='avg'):
40
+ """
41
+ mode= 'avg' or 'best'
42
+ """
43
+ if mode not in ['avg','best']: raise ValueError(f"Unknown mode:{mode} \nMode should be one of these:{['avg','best']}")
44
+ crop_img_features=self.feature_extractor.predict(crop_img[None,:,:,:],verbose=0)
45
+ all_distances=[] # distance of this particular crop with all faces in database
46
+ for face_idx in range(len(self.faces)):
47
+ if mode=='avg':
48
+ db_face_features=db_faces_features[face_idx].mean(axis=0,keepdims=True) # avg method
49
+ new_crop_img_features=crop_img_features.copy()
50
+ else:
51
+ db_face_features=db_faces_features[face_idx] # best method
52
+ new_crop_img_features=np.tile(crop_img_features,[db_face_features.shape[0],1])
53
+ try:
54
+ assert(db_face_features.shape==new_crop_img_features.shape)
55
+ except:
56
+ raise AssertionError(f"db_face_features shape{db_face_features.shape} does not match crop_img_features shape{new_crop_img_features.shape}")
57
+
58
+ distance=np.min(self.euclidean_distance([db_face_features,new_crop_img_features]),axis=0)[0]
59
+
60
+ if distance<=self.thres:
61
+ all_distances.append(distance) # obj distance wrt to all faces in database
62
+ else:
63
+ all_distances.append(self.model_config.large_distance) # not the person garruntied
64
+ return all_distances
65
+
66
+
67
+
68
+ def repeat_allowed_face_recognition(self,distance_dict):
69
+ faceidx_to_obj_dict=dict()
70
+ for obj in distance_dict.keys():
71
+ distances=np.array(distance_dict[obj])
72
+ min_distance,min_distance_idx = distances.min(),distances.argmin()
73
+ if min_distance<=self.thres:
74
+ obj.find('name').text = self.faces[min_distance_idx]
75
+ distance_tag=ET.Element("distance")
76
+ distance_tag.text="{:.2f}".format(min_distance)
77
+ obj.append(distance_tag)
78
+ return faceidx_to_obj_dict
79
+
80
+
81
+ def assign_face_label(self,obj):
82
+
83
+ # find min and argmin
84
+ min_distance,min_distance_idx = self.distance_dict[obj].min(),self.distance_dict[obj].argmin()
85
+ # base condition
86
+ if min_distance>=self.thres:
87
+ # print("end");
88
+ return;
89
+ if min_distance_idx not in self.faceidx_to_obj_dict:
90
+ self.faceidx_to_obj_dict[min_distance_idx]=(obj,min_distance) # stores obj and distance
91
+ else:
92
+
93
+ if(min_distance>self.faceidx_to_obj_dict[min_distance_idx][1]):
94
+ self.distance_dict[obj][min_distance_idx]=self.model_config.large_distance
95
+ self.assign_face_label(obj)
96
+ else:
97
+ temp_obj,temp_min_distance=self.faceidx_to_obj_dict[min_distance_idx]
98
+ self.faceidx_to_obj_dict[min_distance_idx]=(obj,min_distance) # stores obj and distance
99
+ self.distance_dict[temp_obj][min_distance_idx]=self.model_config.large_distance
100
+ self.assign_face_label(temp_obj)
101
+
102
+
103
+ def no_repeat_allowed_face_recognition(self,distance_dict):
104
+
105
+ self.faceidx_to_obj_dict=dict()
106
+ for obj in distance_dict.keys():
107
+ self.assign_face_label(obj)
108
+
109
+ for idx,(obj,distance) in self.faceidx_to_obj_dict.items():
110
+ obj.find('name').text = self.faces[idx]
111
+ distance_tag=ET.Element("distance")
112
+ distance_tag.text="{:.2f}".format(distance)
113
+ obj.append(distance_tag)
114
+ # print(obj.find("distance").text)
115
+
116
+ return self.faceidx_to_obj_dict
117
+
118
+
119
+ def forward_pass(self,img,tree,mode="repeat"):
120
+ '''mode : "repeat" or "no-repeat" '''
121
+ root=tree.getroot()
122
+ self.distance_dict=dict()
123
+
124
+ size=root.find('size')
125
+ w,h=int(size.find("width").text),int(size.find("height").text)
126
+
127
+ for i,obj in enumerate(root.findall("object")):
128
+ bndbox=obj.find("bndbox")
129
+
130
+ xmin,ymin , xmax,ymax=int(bndbox.find('xmin').text),int(bndbox.find('ymin').text),int(bndbox.find('xmax').text),int(bndbox.find('ymax').text)
131
+
132
+ crop_img=img[ymin:ymax,xmin:xmax]
133
+ crop_img=cv2.resize(crop_img,[self.model_config.input_size,self.model_config.input_size])
134
+ crop_img=self.aligner.align_image(crop_img)
135
+
136
+
137
+ if crop_img is not None:
138
+ self.distance_dict[obj]=np.array(self.calculate_distance(crop_img,self.db_faces_features,mode=self.distance_mode))
139
+
140
+ # print(distance_dict)
141
+
142
+ if mode=="repeat":
143
+ faceidx_to_obj_dict=self.repeat_allowed_face_recognition(self.distance_dict)
144
+ elif mode=="no-repeat":
145
+ faceidx_to_obj_dict=self.no_repeat_allowed_face_recognition(self.distance_dict)
146
+ return tree
147
+
148
+ def predict(self,img,tree):
149
+ if (not hasattr(self,"distance_mode")) or (not hasattr(self,"recognition_mode")): raise ValueError(f"Call set_face_db_and_mode method first!")
150
+ tree=self.forward_pass(img,tree,mode=self.recognition_mode)
151
+ return tree
152
+
153
+ def set_face_db_and_mode(self,faces,db_faces_features,distance_mode="avg",recognition_mode="repeat"):
154
+
155
+ if distance_mode not in ['avg','best']: raise ValueError(f"Unknown mode:{distance_mode} \nMode should be one of these:{['avg','best']}")
156
+ if recognition_mode not in ['repeat','no-repeat']: raise ValueError(f"Unknown mode:{recognition_mode} \nMode should be one of these:{['repeat','no-repeat']}")
157
+ self.distance_mode=distance_mode
158
+ self.recognition_mode=recognition_mode
159
+
160
+ self.faces=faces
161
+ self.db_faces_features=db_faces_features
162
+
163
+ # print(face_features)
164
+ # for xml_file in ["/content/images - Copy/IMG20221124131734.xml"]:
165
+
166
+ if __name__=="__main__":
167
+
168
+ from helper import *
169
+
170
+ img_dir=config.img_dir
171
+ save_dir=config.save_dir
172
+
173
+
174
+
175
+ _,faces,_=next(os.walk(config.db_dir))
176
+ db_faces_features=[np.loadtxt(f"{config.db_dir}/{face_dir}/features.npy",ndmin=2) for face_dir in faces]
177
+
178
+ for i in range(len(faces)):
179
+ print(faces[i],":",db_faces_features[i].shape)
180
+
181
+
182
+ if os.path.exists(save_dir):shutil.rmtree(save_dir)
183
+ os.mkdir(save_dir)
184
+
185
+
186
+ fr=face_recognition("face_recognition/Models/v1")
187
+ # fr=face_recognition(thres=0.3)
188
+ # fr.set_face_db_and_mode(faces,db_faces_features,distance_mode="best",recognition_mode="repeat")
189
+ fr.set_face_db_and_mode(faces,db_faces_features,distance_mode="best",recognition_mode="no-repeat")
190
+
191
+ for xml_file in glob(f"{img_dir}/*.xml"):
192
+ tree=ET.parse(xml_file)
193
+ root=tree.getroot()
194
+ img_name=img_dir+'/'+root.find("filename").text
195
+ img=PIL.Image.open(img_name).convert("RGB")
196
+ img = ImageOps.exif_transpose(img)
197
+ img=np.array(img)
198
+
199
+ tree=fr.predict(img,tree)
200
+
201
+ img=show_pred_image(tree,img)
202
+ # plot examples
203
+ # plt.figure(figsize=(10,10))
204
+ # plt.axis("off")
205
+ # plt.title("Labeled images")
206
+ # plt.imshow(img)
207
+ # plt.show()
208
+ print(xml_to_objs_found(tree))
209
+
210
+ cv2.imwrite(save_dir+"/"+root.find("filename").text,cv2.cvtColor(img,cv2.COLOR_RGB2BGR))
211
+
app/face_recognition/setup_db_features.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import tensorflow as tf
2
+ from face_recognition import config
3
+ import cv2
4
+ from glob import glob
5
+ import os
6
+ import numpy as np
7
+
8
+ feature_extractor=tf.keras.models.load_model("face_recognition/feature_extractor.h5",compile=False)
9
+ # feature_extractor.summary()
10
+
11
+ extensions=['.jpg','.jpeg','.png','.svg','.webp']
12
+
13
+ db_dir=config.db_dir
14
+ _,sub_folders,_=next(os.walk(db_dir))
15
+ print(sub_folders)
16
+ for sub_folder in sub_folders:
17
+ image_paths=[]
18
+ [image_paths.extend(glob(db_dir+"\\"+sub_folder+"\\*"+extension)) for extension in extensions]
19
+
20
+ all_img_features=[]
21
+ for image_path in image_paths:
22
+ print(image_path)
23
+ img=cv2.resize(cv2.imread(image_path),[config.input_size,config.input_size])
24
+ all_img_features.append(feature_extractor.predict(img[None,:,:,::-1],verbose=0)[0])
25
+
26
+ np.savetxt(db_dir+"\\"+sub_folder+"\\features.npy",all_img_features)
27
+
28
+ # "aligned_all"
app/face_recognition/split_model.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import tensorflow as tf
2
+ from tensorflow.keras import backend as K
3
+ from tensorflow.keras import Model,layers
4
+
5
+
6
+ model=tf.keras.models.load_model("face_recognization_model.h5",compile=False)
7
+ # model.summary()
8
+
9
+
10
+ feature_extractor=Model(model.layers[0].input,model.layers[2](model.layers[0].input),name='feature_extractor')
11
+ feature_extractor.summary()
12
+ feature_extractor.save("feature_extractor.h5")
app/helper.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+ import base64
3
+ import uuid
4
+ from PIL import Image
5
+ import mysql.connector
6
+
7
+ def generate_random_id():
8
+ return str(uuid.uuid1())
9
+
10
+ def image_to_base64(img):
11
+ img=Image.fromarray(img[:,:,:3])
12
+ rawBytes=io.BytesIO()
13
+ img.save(rawBytes,"JPEG")
14
+ rawBytes.seek(0)
15
+ img_base64=str(base64.b64encode(rawBytes.read()))
16
+ return img_base64
17
+
18
+ def base64_to_image(img_base64):
19
+ # Assuming base64_str is the string value without 'data:image/jpeg;base64,'
20
+ img = Image.open(io.BytesIO(base64.decodebytes(bytes(img_base64, "utf-8"))))
21
+ return np.array(img)
22
+
23
+ def access_database_as_admin():
24
+
25
+ return mysql.connector.connect(host="bnadwttldj2i5cq9aymp-mysql.services.clever-cloud.com",
26
+ user="uvfqvcypihhznd2u",
27
+ port=3306,
28
+ password="CX6TBadRQYFqprozqDTo",
29
+ database="bnadwttldj2i5cq9aymp")
30
+
31
+
32
+ def create_user_table(username):
33
+ dataBase=access_database_as_admin()
34
+ cursor=dataBase.cursor()
35
+ query=f"""create table if not exists user_{username}(
36
+ person_id varchar(30) unique not null,
37
+ face_vectors blob not null,
38
+ remarks text not null,
39
+ group_id char(30)
40
+ );"""
41
+ cursor.execute(query)
42
+ dataBase.commit()
43
+ dataBase.close()
44
+
45
+ def drop_user_table(username):
46
+ dataBase=access_database_as_admin()
47
+ cursor=dataBase.cursor()
48
+ query=f"drop table if exists user_{username};"
49
+ cursor.execute(query)
50
+ dataBase.commit()
51
+ dataBase.close()
52
+
53
+ def add_row_user_table(username,person_id,face_vectors,remarks,group_id=None):
54
+ """
55
+ person_id:str
56
+ face_vectors:np.array shape:(n,128)
57
+ remarks:np.array shape:(n,)
58
+ group_id:str
59
+
60
+ """
61
+
62
+ # print(face_vectors.tobytes())
63
+ # print(remarks.tobytes())
64
+ # print(np.frombuffer(remarks.tobytes(), dtype="float64"))
65
+ # pass
66
+ dataBase=access_database_as_admin()
67
+ cursor=dataBase.cursor()
68
+ cursor.execute(f"select person_id from user_{username} where person_id=%s;",[person_id])
69
+ if cursor.fetchone() is None:
70
+ if group_id is not None:
71
+ query=f"insert into user_{username}(person_id,face_vectors,remarks,group_id) values(%s,%s,%s,%s);"
72
+ cursor.execute(query,[person_id,face_vectors.tobytes(),remarks,group_id])
73
+ else:
74
+ query=f"insert into user_{username}(person_id,face_vectors,remarks) values(%s,%s,%s);"
75
+ cursor.execute(query,[person_id,face_vectors.tobytes(),remarks])
76
+ else:
77
+ if group_id is not None:
78
+ query=f"update user_{username} SET face_vectors=%s,remarks=%s,group_id=%s where person_id=%s;"
79
+ cursor.execute(query,[face_vectors.tobytes(),remarks,group_id,person_id])
80
+ else:
81
+ query=f"update user_{username} SET face_vectors=%s,remarks=%s where person_id=%s;"
82
+ cursor.execute(query,[face_vectors.tobytes(),remarks,person_id])
83
+ dataBase.commit()
84
+ dataBase.close()
85
+
86
+ def read_row_user_table(username):
87
+ dataBase=access_database_as_admin()
88
+ cursor=dataBase.cursor()
89
+ query=f"select person_id,face_vectors,remarks,group_id from user_{username};"
90
+ cursor.execute(query)
91
+ data=list(cursor.fetchone())
92
+ data[1]=np.frombuffer(data[1],dtype="float64")
93
+
94
+ data[2]=data[2].split(",")
95
+ data[1]=data[1].reshape(len(data[2]),-1)
96
+ print(data)
97
+ # dataBase.commit()
98
+ dataBase.close()
99
+
100
+ def read_user_table(username,split_remarks=True,group_id=None):
101
+ dataBase=access_database_as_admin()
102
+ cursor=dataBase.cursor()
103
+ if group_id is None:
104
+ cursor.execute(f"select person_id,face_vectors,remarks,group_id from user_{username};")
105
+ else:
106
+ cursor.execute(f"select person_id,face_vectors,remarks,group_id from user_{username} where group_id=%s;",[group_id])
107
+ data={column_name:[] for column_name in cursor.column_names}
108
+ for row in cursor.fetchall():
109
+ row=list(row)
110
+ row[1]=np.frombuffer(row[1],dtype="float64")
111
+ row[2]=row[2].split(",")
112
+
113
+ data['person_id'].append(row[0])
114
+ data['face_vectors'].append(row[1].reshape(len(row[2]),-1))
115
+ if not split_remarks:
116
+ row[2]=",".join(row[2])
117
+ data['remarks'].append(row[2])
118
+ data['group_id'].append(row[3])
119
+
120
+ dataBase.close()
121
+ # print(data['person_id'])
122
+ # print(data['face_vectors'])
123
+ return data
124
+
125
+ def remove_person_from_user_table(username,person_id):
126
+ dataBase=access_database_as_admin()
127
+ cursor=dataBase.cursor()
128
+ query=f"delete from user_{username} where person_id=%s;"
129
+ cursor.execute(query,[person_id])
130
+ dataBase.commit()
131
+ dataBase.close()
132
+
133
+ import numpy as np
134
+
135
+ # add_row_user_table("abc","1",np.array([[2,3],[1,4]],dtype="float64"),"front face,left face,right face",group_id="1")
136
+ # read_user_table("abc")
137
+ # print(np.fromstring("a,b,c",dtype='S3'))
138
+
139
+ # drop_user_table("abc")
140
+ # create_user_table("abc")
app/main/__init__.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ from flask import Blueprint
2
+
3
+ bp=Blueprint("main",__name__)
4
+
5
+ from app.main import routes
app/main/routes.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ from flask import redirect
2
+ from app.main import bp
3
+
4
+ @bp.route("/")
5
+ def index():
6
+ return redirect("/demo/")
app/static/admin/dashboard.css ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *{
2
+ padding: 3px 9px;
3
+ }
4
+ #access_requests_table{
5
+ /* border:2px dashed black; */
6
+
7
+ /* position: absolute;
8
+ top:50%;
9
+ left:50%;
10
+ transform: translate(-50%,-50%); */
11
+ width:fit-content;
12
+
13
+ }
14
+
15
+ table, th, td {
16
+ border:2px solid black;
17
+ border-collapse: collapse;
18
+ }
19
+
20
+ button{
21
+ cursor: pointer;
22
+ }
23
+
24
+ .accept{
25
+ background-color: greenyellow;
26
+ }
27
+ .reject{
28
+ background-color: red;
29
+ }
30
+ .revoke{
31
+ background-color: blueviolet;
32
+ }
app/static/admin/dashboard.js ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function add_request_row(username,request_message)
2
+ {
3
+ //#access_requests_table
4
+ // <tr>
5
+ // <td>abc</td>
6
+ // <td>Please give access :(</td>
7
+ //
8
+ // <td>
9
+ // <button class="accept"><i class="fa-solid fa-check"></i></button>
10
+ // <button class="reject"><i class="fa-solid fa-close"></i></button>
11
+ // </td>
12
+ // </tr>
13
+ var table_row=document.createElement("tr");
14
+ var username_tag=document.createElement("td");
15
+ username_tag.innerText=username;
16
+ var request_message_tag=document.createElement("td");
17
+ request_message_tag.innerText=request_message;
18
+
19
+ var review_tag=document.createElement("td");
20
+ review_tag.innerHTML='<button class="accept" onclick="perform_action(this);"><i class="fa-solid fa-check"></i></button>\
21
+ <button class="reject" onclick="perform_action(this);"><i class="fa-solid fa-close"></i></button>';
22
+ table_row.appendChild(username_tag);
23
+ table_row.appendChild(request_message_tag);
24
+ table_row.appendChild(review_tag);
25
+ document.querySelector("#access_requests_table").appendChild(table_row);
26
+ }
27
+
28
+
29
+
30
+
31
+
32
+ fetch("get_all_requests/").then(function(response){
33
+ return response.json();
34
+ }).then(function(response){
35
+ console.log(response);
36
+ if ('username' in response)
37
+ {
38
+ for(var i=0;i<response['username'].length;i++)
39
+ {
40
+ if (response['access_key'][i]==null)
41
+ add_request_row(response['username'][i],response['request_message'][i])
42
+ else
43
+ add_access_row(response['username'][i],response['request_message'][i])
44
+ }
45
+
46
+ }
47
+
48
+ })
49
+
50
+
51
+
52
+ function perform_action(elem){
53
+ // console.log(elem);
54
+ console.log(elem.getAttribute("class"));
55
+ var row=elem.parentNode.parentNode;
56
+ // username:row.firstChild.innerText
57
+
58
+ if (elem.getAttribute("class")=="reject")
59
+ {
60
+ const response = confirm("Are you sure you want to do that?");
61
+ if (!response)
62
+ {
63
+ return;
64
+ }
65
+ }
66
+
67
+ var formdata=new FormData();
68
+ formdata.append("username",row.firstChild.innerText);
69
+ formdata.append("mode",elem.getAttribute("class"));
70
+ fetch("update_requests/",{
71
+ method:"POST",
72
+ body:formdata
73
+ }).then(function(response){
74
+ return response.json();
75
+ }).then(function(response){
76
+ console.log("response:",response);
77
+ if (elem.getAttribute("class")=="accept")
78
+ {
79
+ add_access_row(row.firstChild.innerText,row.querySelector("td:nth-child(2)").innerText);
80
+ }
81
+ else if (elem.getAttribute("class")=="revoke")
82
+ {
83
+ add_request_row(row.firstChild.innerText,row.firstChild.dataset.request_message);
84
+ }
85
+ row.remove();
86
+ })
87
+
88
+
89
+
90
+ }
91
+
92
+
93
+
94
+
95
+
96
+ function add_access_row(username,request_message)
97
+ {
98
+ //#access_requests_table
99
+ // <tr>
100
+ // <td>username</td>
101
+ // <td>
102
+ // <button class="reject"><i class="fa-solid fa-close"></i></button>
103
+ // </td>
104
+ // </tr>
105
+ var table_row=document.createElement("tr");
106
+ var username_tag=document.createElement("td");
107
+ username_tag.innerText=username;
108
+ username_tag.dataset.request_message=request_message;
109
+ var remove_access_tag=document.createElement("td");
110
+ remove_access_tag.innerHTML='<button class="revoke" onclick="perform_action(this);"><i class="fa-solid fa-close"></i></button>';
111
+ table_row.appendChild(username_tag);
112
+ table_row.appendChild(remove_access_tag);
113
+ document.querySelector("#access_granted_table").appendChild(table_row);
114
+ }
115
+
116
+
117
+ // add_access_row('username')
118
+ // add_access_row('anuj')
119
+ // add_access_row('abc')
app/static/admin/login.css ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #container{
2
+ position: absolute;
3
+ top:50%;
4
+ left:50%;
5
+ transform:translate(-50%,-50%);
6
+ display: flex;
7
+ row-gap: 20px;
8
+ flex-direction: column;
9
+ align-items: center;
10
+ border:2px solid black;
11
+ /* box-sizing: border-box; */
12
+
13
+ padding: 20px;
14
+ }
15
+ #container>h1{
16
+ text-align: center;
17
+ margin: 0px;
18
+ }
19
+ #container>p{
20
+ text-align: center;
21
+ margin: 0px;
22
+ margin-bottom: 5px;
23
+ visibility: hidden;
24
+ color:red;
25
+ }
26
+ .active{
27
+ visibility: visible !important;
28
+ }
29
+
30
+ #container>div{
31
+ display: flex;
32
+ width:314px;
33
+ justify-content: space-between;
34
+ }
35
+ #container>div>p{
36
+ margin: 0;
37
+ }
38
+
39
+ #container>div>input{
40
+ border:none;
41
+ outline:none;
42
+ border-bottom:1px solid black;
43
+ }
44
+
45
+ #container>input{
46
+ width:30%;
47
+ margin: 10px;
48
+ }
49
+
app/static/admin/registeration.js ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function check_username(elem){
2
+ if(elem.value!=''){
3
+ fetch(`/user/is_username_available/?username=${elem.value}`,{
4
+ method:"GET",
5
+
6
+ }).then(function(response){
7
+ return response.json();
8
+ }).then(function(response){
9
+ // show a indicator that this username is available
10
+ if(response['available'])
11
+ {
12
+ // show green indicator
13
+ console.log("Username available");
14
+ elem.dataset.valid=true;
15
+ elem.style.borderColor='green';
16
+ elem.style.borderWidth=4;
17
+ }
18
+ else
19
+ {
20
+ // show red indicator
21
+ console.log("Username unavailable");
22
+ elem.dataset.valid=false;
23
+ elem.style.borderColor='red';
24
+ elem.style.borderWidth=4;
25
+ }
26
+ });
27
+ }
28
+ }
29
+
30
+ function check_password_is_matching(confirm_password){
31
+ var password=document.querySelector("#password");
32
+ if(confirm_password.value!=password.value){
33
+ confirm_password.style.borderColor='red';
34
+ confirm_password.style.borderWidth=4;
35
+ }
36
+ else{
37
+ confirm_password.style.borderColor='green';
38
+ confirm_password.style.borderWidth=4;
39
+ }
40
+ }
41
+
42
+ function validate_form(form){
43
+ if(form.username.dataset.valid=="false"){
44
+ document.querySelector("#container>p").style.visibility='visible';
45
+ document.querySelector("#container>p").innerText="username not available";
46
+ return false;
47
+ }
48
+ else if(form.password.value!=form.confirm_password.value){
49
+ document.querySelector("#container>p").style.visibility='visible';
50
+ document.querySelector("#container>p").innerText="password not matching";
51
+ return false;
52
+ }
53
+ else{
54
+ return true;
55
+ }
56
+ }
app/static/demo/index/dark.css ADDED
@@ -0,0 +1,354 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ :root{
2
+ /* --color-primary:#7380ec; */
3
+ /* --color-primary:rgb(205, 18, 234); */
4
+ --color-primary:rgb(163 18 234);
5
+ --color-secondary:rgb(173, 54, 232);
6
+
7
+ --color-name-border:white;
8
+ }
9
+
10
+ *{
11
+ box-sizing: border-box;
12
+ /* background-color: rgb(22, 22, 22); */
13
+ background-color: rgb(12, 12, 12);
14
+ color:white;
15
+ font-weight: bold;
16
+ font-family: 'Poppins';
17
+ /* pointer-events: none; */
18
+ }
19
+
20
+
21
+
22
+ /* width */
23
+ ::-webkit-scrollbar {
24
+ width: 10px;
25
+ height:10px;
26
+ }
27
+
28
+ /* Track */
29
+ /* ::-webkit-scrollbar-track {
30
+ background: #B2EBF2;
31
+ } */
32
+
33
+ /* Handle */
34
+ ::-webkit-scrollbar-thumb {
35
+ /* background: #5E35B1; */
36
+ background: var(--color-primary);
37
+ border-radius: 10px;
38
+ }
39
+
40
+ /* Handle on hover */
41
+ ::-webkit-scrollbar-thumb:hover {
42
+ background: var(--color-secondary);
43
+ }
44
+
45
+
46
+ #db_images_bar
47
+ {
48
+ display: flex;
49
+ height:100px;
50
+ /* border:2px solid rgb(39, 86, 255); */
51
+ width: 100%;
52
+ padding-bottom: 10px;
53
+ }
54
+
55
+ #db_images_bar>.add_button{
56
+ height: 60px;
57
+ width: 20%;
58
+ padding: 2px;
59
+ margin: auto 0;
60
+ margin-right: 5px;
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: center;
64
+ flex-direction: column;
65
+ z-index: 2;
66
+ }
67
+
68
+
69
+ #db_images_bar>.add_button>i{
70
+ color:white;
71
+ background-color: inherit;
72
+ font-size: 3em;
73
+ }
74
+
75
+
76
+
77
+ #db_images
78
+ {
79
+ display: flex;
80
+ height: 100%;
81
+ width: 80%;
82
+ overflow: scroll hidden;
83
+ grid-row-start: 1;
84
+ margin: 0px 10px;
85
+ }
86
+ .db_image{
87
+ height:inherit;
88
+ filter: blur(0);
89
+ transition: 0.3s;
90
+ border-radius: inherit;
91
+ }
92
+ .db_image_container{
93
+ height: inherit;
94
+ background: black;
95
+ margin-right:10px ;
96
+ position: relative;
97
+ display: inline-block;
98
+
99
+ border-radius: 20%;
100
+ }
101
+
102
+ .db_image_container:hover{
103
+ cursor: pointer;
104
+ }
105
+ .db_image_container:hover .db_image{
106
+ opacity: 0.5;
107
+ filter: blur(3px);
108
+ }
109
+
110
+ .db_image_container>.close_text{
111
+ opacity: 0;
112
+ font-size: xxx-large;
113
+ color:white;
114
+ position: absolute;
115
+ top:50%;
116
+ left:50%;
117
+ transform: translate(-50%,-50%);
118
+ padding: 0px;
119
+ margin: 0px;
120
+ transition: 0.3s;
121
+ background-color: transparent;
122
+ }
123
+ .db_image_container:hover .close_text{
124
+ opacity: 1;
125
+ }
126
+
127
+
128
+
129
+
130
+
131
+
132
+
133
+ /*new main container*/
134
+ #container{
135
+ height:452px;
136
+ width:1000px;
137
+ /* border:2px dotted black; */
138
+ margin: 0 auto;
139
+ display: flex;
140
+ position: absolute;
141
+ top:50%;
142
+ left:50%;
143
+ transform: translate(-50%,-50%);
144
+ }
145
+
146
+ #container>.left-section{
147
+ height: inherit;
148
+ width:50%;
149
+ border-right:4px solid rgb(123, 123, 123);
150
+ display: flex;
151
+ align-items: center;
152
+ flex-direction: column;
153
+ padding: 10px;
154
+ }
155
+
156
+ #face_rec_image{
157
+ height: 65%;
158
+ /* border: 1px solid turquoise; */
159
+ border:0;
160
+ }
161
+
162
+
163
+
164
+ img[src=""],img:not([src]) {
165
+ opacity: 0;
166
+ }
167
+
168
+ img[src="*"]{
169
+ opacity: 1;
170
+ }
171
+
172
+
173
+ .buttons{
174
+ display: flex;
175
+ align-items: center;
176
+ justify-content: center;
177
+ /* border:2px solid red; */
178
+ height:50px;
179
+ width:100%;
180
+ }
181
+ .buttons>div>input{
182
+ padding:2px 5px;
183
+ margin:0px 5px;
184
+ }
185
+
186
+ #container>.right-section{
187
+ height: inherit;
188
+ width:50%;
189
+ display: flex;
190
+ align-items: center;
191
+ flex-direction: column;
192
+ /* justify-content: center; */
193
+ padding: 10px;
194
+ }
195
+
196
+ #unassigned_faces{
197
+ width:100%;
198
+ height:100px;
199
+ /* border:1px solid rgb(255, 66, 255); */
200
+ padding:10px;
201
+ display: flex;
202
+ flex-direction: row;
203
+ align-items: center;
204
+ overflow: scroll hidden;
205
+ }
206
+
207
+ .crop_img{
208
+ height: 50px;
209
+ margin: 2px;
210
+ }
211
+
212
+ #name_list{
213
+ width:100%;
214
+ height:55%;
215
+ /* border:2px solid rgb(66, 113, 255); */
216
+ overflow: hidden scroll;
217
+ padding:15px;
218
+ }
219
+
220
+ #name_list>.person{
221
+ width:100%;
222
+ height: 80px;
223
+ border-bottom:2px solid var(--color-name-border);
224
+ position: relative;
225
+ padding: 4px 1px;
226
+ display: flex;
227
+ align-items: end;
228
+ }
229
+ #name_list>.person>input{
230
+ position: absolute;
231
+ left:5px;
232
+ top:5px;
233
+ /* padding: inherit; */
234
+ background-color: transparent;
235
+ border:none;
236
+ outline: none;
237
+ }
238
+ #name_list>.person>input:focus{
239
+ border-bottom: 1px solid var(--color-name-border);
240
+ }
241
+
242
+ #name_list>.person>i{
243
+ color:red;
244
+ position: absolute;
245
+ top:50%;
246
+ transform: translate(0,-50%);
247
+ right:20px;
248
+
249
+ }
250
+ #name_list>.person>i:hover{
251
+ cursor:pointer;
252
+ }
253
+
254
+ #name_list>.person>.faces{
255
+ height:fit-content;
256
+ width: 100%;
257
+
258
+ }
259
+
260
+
261
+ #add_name_btn{
262
+ margin: 40px;
263
+ width:inherit;
264
+ height:inherit;
265
+ }
266
+
267
+ .btn{
268
+ background-color: var(--color-primary);
269
+ box-shadow: 0px 0px 43px -4px var(--color-primary);
270
+ border-radius: 5px;
271
+ border:none;
272
+ }
273
+ .btn:hover{
274
+ cursor: pointer;
275
+ background-color: var(--color-secondary);
276
+ /* box-shadow: 0px 0px 43px -4px var(--color-secondary); */
277
+
278
+ }
279
+
280
+ .settings_btn{
281
+ position: absolute;
282
+ top:40px;
283
+ right:40px;
284
+ font-size: larger;
285
+ }
286
+
287
+ #settings_menu{
288
+ background-color: black;
289
+ height: fit-content;
290
+ width:40%;
291
+ z-index: 10000;
292
+ position: absolute;
293
+ top:50%;
294
+ left:50%;
295
+ transform: translate(-50%,-50%);
296
+ border-radius: 10px;
297
+ box-shadow: 0px 0px 43px -4px var(--color-primary);
298
+ padding: 2px 20px;
299
+ display: none;
300
+ }
301
+ #settings_menu>h1{
302
+ background-color: inherit;
303
+ }
304
+ #settings_menu>.settings{
305
+ background-color: inherit;
306
+ height: 280px;
307
+ overflow: hidden scroll;
308
+ position: relative;
309
+ }
310
+
311
+ #settings_menu>.close_btn{
312
+ color:red;
313
+ position: absolute;
314
+ top: 20px;
315
+ right: 20px;
316
+ font-size: larger;
317
+ background-color: transparent;
318
+ }
319
+ #settings_menu>.close_btn:hover{
320
+ cursor: pointer;
321
+ }
322
+
323
+ .reset_btn_container{
324
+ position: absolute;
325
+ top: 20px;
326
+ right: 30px;
327
+ }
328
+ .reset_btn_container>.reset_btn{
329
+ color:white;
330
+ position: fixed;
331
+ font-size: larger;
332
+ background-color: transparent;
333
+ }
334
+ .reset_btn_container>.reset_btn:hover{
335
+ cursor: pointer;
336
+ }
337
+
338
+ #container.blur{
339
+ filter: blur(5px);
340
+ pointer-events: none;
341
+ }
342
+
343
+ #save_btn_container{
344
+ display: flex;
345
+ justify-content: center;
346
+ margin: 10px 0px;
347
+ font-size: large;
348
+ }
349
+ #save_settings_btn{
350
+ background-color: rgb(76, 76, 232);
351
+ outline: none;
352
+ border: none;
353
+ border-radius: 6px;
354
+ }
app/static/demo/index/icon.jpg ADDED
app/static/demo/index/script.js ADDED
@@ -0,0 +1,498 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var dragged_elem;
2
+ var touch_start_time=null;
3
+ var elapsedTime=null;
4
+ var maxAllowedTime=500;
5
+
6
+ function drag(ev){
7
+ // ev.preventDefault();
8
+ console.log(ev.target.id);
9
+ dragged_elem=ev.target;
10
+ // ev.dataTransfer.setData("text",ev.target.id);
11
+ }
12
+ function dragTouchstart(e,elem) {
13
+ elapsedTime=null;
14
+ touch_start_time = new Date().getTime();
15
+ }
16
+ function dragTouchmove(e,elem) {
17
+
18
+ let touchX = e.touches[0].pageX;
19
+ let touchY = e.touches[0].pageY;
20
+
21
+ if(elapsedTime==null)
22
+ {
23
+ elapsedTime = new Date().getTime() - touch_start_time;
24
+ }
25
+
26
+ // console.log(elapsedTime);
27
+
28
+ if (elapsedTime<maxAllowedTime) return;
29
+
30
+ // console.log("no-scroll")
31
+ e.preventDefault()
32
+
33
+ if (dragged_elem==null)
34
+ {
35
+ dragged_elem=elem;
36
+ console.log(dragged_elem);
37
+ }
38
+
39
+ }
40
+
41
+ function allowDrop(ev){
42
+ ev.preventDefault();
43
+ console.log("ready to be dropped");
44
+ }
45
+
46
+ function drop(ev,element){
47
+ ev.preventDefault();
48
+ console.log("dropped!");
49
+ element.appendChild(dragged_elem);
50
+ dragged_elem=null;
51
+
52
+ }
53
+
54
+ function dragTouchend(e,elem) {
55
+
56
+ if(dragged_elem==null) return;
57
+
58
+ var droppable_element=document.elementFromPoint(e.changedTouches[0].clientX, e.changedTouches[0].clientY).closest(".droppable");
59
+ if(droppable_element==null) return;
60
+
61
+ if(droppable_element.hasAttribute("data-dropto")) droppable_element=droppable_element.querySelector(droppable_element.dataset.dropto)
62
+
63
+ droppable_element.appendChild(dragged_elem);
64
+
65
+ console.log(droppable_element)
66
+ dragged_elem=null;
67
+ // e.target.style.transform="scale(0.8)";
68
+ }
69
+
70
+ // function click_based_drop(elem)
71
+ // {
72
+ // if(dragged_elem!=null){
73
+
74
+ // console.log("asd");
75
+ // if(elem.getAttribute("class")=="person")
76
+ // {
77
+ // console.log();
78
+ // elem.querySelector(".faces").appendChild(dragged_elem);
79
+ // dragged_elem=null;
80
+ // features_updated=false;
81
+ // }
82
+ // else if (elem.getAttribute("id")=="unassigned_faces")
83
+ // {
84
+ // document.querySelector("#unassigned_faces").appendChild(dragged_elem);
85
+ // dragged_elem=null;
86
+ // features_updated=false;
87
+ // }
88
+ // }
89
+
90
+ // }
91
+
92
+
93
+ var database_input=document.querySelector("#db_images_bar>.add_button>input")
94
+ database_input.addEventListener("change", function(e){
95
+ if(e.target.files[0]){
96
+ console.log(e.target.files[0].name);
97
+
98
+ const formdata = new FormData();
99
+ formdata.append("a",23);
100
+ formdata.append("image",e.target.files[0]);
101
+
102
+ fetch("/demo/add_crops/",
103
+ {
104
+ method:'POST',
105
+ body:formdata,
106
+ }).then(
107
+ function(response)
108
+ {
109
+ return response.json();
110
+ }
111
+ ).then(
112
+ function(response)
113
+ {
114
+ console.log(response);
115
+ if (response['message']=='successful')
116
+ {
117
+
118
+ var images_div=document.querySelector("#db_images_bar>#db_images");
119
+ var img_container_tag=document.createElement("div");
120
+ var img_remove_tag=document.createElement("p");
121
+ var img_tag=document.createElement("img");
122
+ img_tag.src="data:image/jpeg;base64,"+response['image'].split('\'')[1];
123
+ img_tag.setAttribute("class","db_image");
124
+ img_remove_tag.setAttribute("class","close_text");
125
+ img_remove_tag.innerHTML="✖";
126
+ img_container_tag.setAttribute("class","db_image_container");
127
+ img_container_tag.setAttribute("onclick","remove_image(this);");
128
+ img_container_tag.dataset.image_name=response['image_name'];
129
+ img_container_tag.appendChild(img_tag);
130
+ img_container_tag.appendChild(img_remove_tag);
131
+
132
+ img_container_tag.addEventListener("mouseenter",function(e){
133
+
134
+ var image=document.querySelector("#face_rec_image");
135
+ if (image.hasAttribute('src'))
136
+ {
137
+ image.dataset.old_src=image.src;
138
+ }
139
+ image.src=e.target.querySelector("img").src;
140
+
141
+
142
+ })
143
+ img_container_tag.addEventListener("mouseleave",function(){
144
+
145
+ var image=document.querySelector("#face_rec_image");
146
+ if (image.hasAttribute("data-old_src")){
147
+ console.log("has_old_src")
148
+ image.src=image.dataset.old_src;
149
+ delete image.dataset.old_src;
150
+ }
151
+ else{
152
+ image.removeAttribute('src');
153
+ }
154
+
155
+
156
+ })
157
+
158
+ images_div.appendChild(img_container_tag);
159
+
160
+
161
+
162
+
163
+ // add crops to the #unassigned_faces
164
+ for(var i=0;i<response["crops"].length;i++)
165
+ {
166
+ var crop_container=document.querySelector("#unassigned_faces");
167
+ var crop_img=document.createElement("img");
168
+ crop_img.src="data:image/jpeg;base64,"+response["crops"][i].split('\'')[1];
169
+ crop_img.dataset.image_name=response['image_name'];
170
+
171
+ crop_img.setAttribute("class","crop_img");
172
+
173
+ crop_img.setAttribute("draggable","true");
174
+ crop_img.setAttribute("ondragstart","drag(event)");
175
+ crop_container.appendChild(crop_img)
176
+
177
+ // disable right click
178
+ crop_img.addEventListener("contextmenu",function(ev){
179
+ ev.preventDefault();
180
+ // console.log("right click");
181
+ // ev.target.style.transform="scale(1.2)";
182
+ // ev.target.focus();
183
+ // dragged_elem=e.target;
184
+ });
185
+
186
+ // crop_img.addEventListener("blur",function(ev){
187
+ // console.log("blur");
188
+ // ev.target.style.transform="scale(1)";
189
+ // });
190
+
191
+
192
+ // add touch events
193
+ // crop_img.addEventListener("touchstart",function(e){
194
+ // console.log("touch-started");
195
+ // });
196
+ crop_img.setAttribute("ontouchstart","dragTouchstart(event,this);");
197
+ crop_img.setAttribute("ontouchmove","dragTouchmove(event,this);");
198
+ crop_img.setAttribute("ontouchend","dragTouchend(event,this);");
199
+ // crop_img.addEventListener("touchmove",function(e){
200
+
201
+ // dragTouchmove(e);
202
+ // });
203
+ // crop_img.addEventListener("touchend",function(e){
204
+ // console.log("touch-end");
205
+ // dragTouchend(e);
206
+ // });
207
+ }
208
+
209
+ // response['images'].forEach(img_name => {
210
+ // img_tag=document.createElement("img");
211
+ // img_tag.src=Flask.url_for('upload',{subfolder:'images',filename:img_name} );
212
+ // images_div.appendChild(img_tag);
213
+ // });
214
+ }
215
+
216
+
217
+ }
218
+ );
219
+ }
220
+ });
221
+
222
+
223
+
224
+
225
+ function remove_image(e)
226
+ {
227
+ // reset old image in image-viewer start ----------------------------------------
228
+ var image=document.querySelector("#face_rec_image");
229
+ if (image.hasAttribute("data-old_src")){
230
+ console.log("has_old_src")
231
+ image.src=image.dataset.old_src;
232
+ delete image.dataset.old_src;
233
+ }
234
+ else{
235
+ image.removeAttribute('src');
236
+ }
237
+ // reset old image in image-viewer end ------------------------------------------
238
+
239
+ // console.log(e)
240
+
241
+ crops=document.querySelectorAll(`.crop_img[data-image_name='${e.dataset.image_name}']`)
242
+ // console.log(crops)
243
+ for(var i=0;i<crops.length;i++)
244
+ crops[i].remove();
245
+
246
+ e.remove();
247
+ }
248
+
249
+
250
+
251
+
252
+ function add_person(){
253
+ // make such a structure:
254
+ // <div class="person" ontouchend="dragTouchend(event)" ondragover="allowDrop(event)" ondrop="drop(event,this)">
255
+ // <input type="text" value="Anuj" ondrop="return false;" onkeypress="deselect(event,this);">
256
+ // <div class="faces"></div>
257
+ // <i class="fa-solid fa-xmark" onclick="this.parentElement.remove();"></i>
258
+ // </div>
259
+ var person=document.createElement("div");
260
+ person.setAttribute("class","person droppable");
261
+ person.dataset.dropto=".faces";
262
+ person.setAttribute("ondragover","allowDrop(event)");
263
+ person.setAttribute("ondrop","drop(event,this.querySelector('.faces'))");
264
+ // person.setAttribute("ontouchend","dragTouchend(event)");
265
+ var name=document.createElement("input");
266
+ name.setAttribute("type","text");
267
+ name.setAttribute("ondrop","return false;");
268
+ name.setAttribute("onkeyup","deselect(event,this);");
269
+ var faces=document.createElement("div");
270
+ faces.setAttribute("class","faces");
271
+ var close_icon=document.createElement("i");
272
+ close_icon.setAttribute("class","fa-solid fa-xmark");
273
+ close_icon.setAttribute("onclick","remove_person(this.parentElement);");
274
+ person.appendChild(name);
275
+ person.appendChild(faces);
276
+ person.appendChild(close_icon);
277
+ document.querySelector("#name_list").appendChild(person);
278
+ name.focus();
279
+ // name.select();
280
+
281
+ }
282
+
283
+ function load_image_preview(elem){
284
+ if(elem.files[0])
285
+ {
286
+ console.log(elem.files[0]);
287
+ if (FileReader && elem.files[0]) {
288
+ var fr = new FileReader();
289
+ fr.onload = function () {
290
+ document.querySelector("#face_rec_image").src = fr.result;
291
+ document.querySelector("#face_rec_image").style.width="unset";
292
+ }
293
+ fr.readAsDataURL(elem.files[0]);
294
+ }
295
+ }
296
+ }
297
+
298
+ function deselect(e,elem){
299
+ // document.body.focus();
300
+
301
+ if(e.key=="Enter")
302
+ elem.blur();
303
+ }
304
+
305
+ function update_crops_labels(elem)
306
+ {
307
+ console.log("update face labels");
308
+ var formdata=new FormData();
309
+
310
+ var faces=document.querySelectorAll(".person>.faces>img");
311
+ var faces_base64=[]
312
+ var selected_faces=[]
313
+
314
+ for (var i=0;i<faces.length;i++)
315
+ {
316
+
317
+ if(!faces[i].hasAttribute("data-features"))
318
+ {
319
+ selected_faces.push(faces[i]);
320
+ faces_base64.push(faces[i].src.split(',')[1]); // also removed datajpeg part
321
+ }
322
+
323
+ }
324
+
325
+ if (selected_faces.length>0)
326
+ {
327
+ formdata.append("faces",faces_base64);
328
+ // to see the the json
329
+ // var object = {};
330
+ // formdata.forEach(function(value, key){
331
+ // object[key] = value;
332
+ // });
333
+ // var json = JSON.stringify(object);
334
+ // console.log(json);
335
+
336
+ fetch("/demo/update_crops_labels/",{
337
+ method:"POST",
338
+ body:formdata
339
+ }).then(function(response){
340
+ console.log(response)
341
+ return response.json();
342
+ }).then(function(response){
343
+ console.log(response);
344
+ if (response.message!='success') return;
345
+
346
+ for(var i=0;i<response['features'].length;i++)
347
+ selected_faces[i].dataset.features=response['features'][i];
348
+ face_recognition(elem);
349
+ });
350
+
351
+ }
352
+ else{
353
+ console.log("already up to date !");
354
+ face_recognition(elem);
355
+ }
356
+
357
+
358
+ }
359
+
360
+
361
+
362
+ function face_recognition(elem)
363
+ {
364
+
365
+ if(elem.files[0])
366
+ {
367
+ // update_crops_labels(elem); // get features of all db images from backend
368
+
369
+ var formdata=new FormData();
370
+ var faces=document.querySelectorAll(".person>.faces>img");
371
+ var faces_features={};
372
+
373
+
374
+ var face_labels=document.querySelectorAll(".person");
375
+
376
+ for (var i=0;i<face_labels.length;i++)
377
+ {
378
+ var faces=face_labels[i].querySelectorAll(".faces>img");
379
+ var face_features=[]
380
+ if (faces.length>0)
381
+ {
382
+ for(var j=0;j<faces.length;j++)
383
+ {
384
+ face_features.push(faces[j].dataset.features)
385
+ }
386
+ // name:[features_array]
387
+ faces_features[face_labels[i].querySelector("input").value]=face_features;
388
+
389
+ }
390
+ }
391
+ formdata.append("db_images",JSON.stringify(faces_features));
392
+ formdata.append("image",elem.files[0]);
393
+
394
+ console.log(formdata.get("db_images"));
395
+ if(formdata.get("db_images")=="{}"){
396
+ console.log("Add db_images_first")
397
+ return ;
398
+ }
399
+ // console.log(elem.files[0]);
400
+ fetch("/demo/face_recognition/",{
401
+ method:"POST",
402
+ body:formdata
403
+ }).then(function(response){
404
+ return response.json();
405
+ }).then(function(response){
406
+ console.log(response);
407
+ document.querySelector("#face_rec_image").src="data:image/jpeg;base64,"+response['image'].split('\'')[1];
408
+ })
409
+
410
+
411
+ }
412
+ }
413
+
414
+
415
+ function remove_person(person){
416
+ var unassigned_faces=document.querySelector("#unassigned_faces");
417
+ var all_crops=person.querySelectorAll(".faces>img");
418
+ all_crops.forEach(function(crop){
419
+ unassigned_faces.appendChild(crop);
420
+ })
421
+ person.remove();
422
+ }
423
+
424
+
425
+ function show_settings(){
426
+ document.querySelector('#settings_menu').style.display='block';
427
+ document.querySelector('#container').classList.add("blur");
428
+ }
429
+ function hide_settings(){
430
+ document.querySelector('#settings_menu').style.display='none';
431
+ document.querySelector('#container').classList.remove("blur");
432
+ }
433
+
434
+
435
+
436
+ function get_settings(){
437
+ fetch("get_settings/",{
438
+ method:"GET"
439
+ }).then(function(response){
440
+ return response.json();
441
+ }).then(function(res){
442
+ console.log(res);
443
+
444
+ p_thres.value=p_thresValue.innerText=res['p_thres'];
445
+ nms_thres.value=nms_thresValue.innerText=res['nms_thres'];
446
+
447
+ small_size.value=small_sizeValue.innerText=res['small_size'];
448
+ large_size.value=large_sizeValue.innerText=res['large_size'];
449
+
450
+ d_thres.value=d_thresValue.innerText=res['d_thres'];
451
+ a_thres.value=a_thresValue.innerText=res['a_thres'];
452
+
453
+ db_mode.value=res['db_mode'];
454
+ fr_mode.value=res['fr_mode'];
455
+ console.log(res['db_mode'],res['fr_mode']);
456
+ })
457
+ }
458
+ get_settings();
459
+ // document.querySelector('#p_thres')
460
+ // document.querySelector('#p_thres').value
461
+
462
+ function update_settings(){
463
+ var new_settings=new Object();
464
+ new_settings['p_thres']=p_thres.value;
465
+ new_settings['nms_thres']=nms_thres.value;
466
+ new_settings['small_size']=small_size.value;
467
+ new_settings['large_size']=large_size.value;
468
+ new_settings['d_thres']=d_thres.value;
469
+ new_settings['a_thres']=a_thres.value;
470
+ new_settings['db_mode']=db_mode.value;
471
+ new_settings['fr_mode']=fr_mode.value;
472
+
473
+ fetch("update_settings/",{
474
+ method:"POST",
475
+ headers:{'content-type': 'application/json'},
476
+ body:JSON.stringify(new_settings)
477
+ }).then(function(response){
478
+ return response.json();
479
+ }).then(function(res){
480
+ console.log(res);
481
+ if(res['message']=='success')
482
+ hide_settings();
483
+ }
484
+ );
485
+ }
486
+
487
+ function reset_settings(){
488
+ fetch("reset_settings/",{
489
+ method:"GET"
490
+ }).then(function(response){
491
+ return response.json();
492
+ }).then(function(res){
493
+ console.log(res);
494
+ if(res['message']=='success')
495
+ get_settings();
496
+ }
497
+ );
498
+ }
app/static/demo/index/style.css ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *{
2
+ box-sizing: border-box;
3
+ }
4
+
5
+ /* width */
6
+ ::-webkit-scrollbar {
7
+ width: 10px;
8
+ height:10px;
9
+ }
10
+
11
+ /* Track */
12
+ ::-webkit-scrollbar-track {
13
+ background: #B2EBF2;
14
+ }
15
+
16
+ /* Handle */
17
+ ::-webkit-scrollbar-thumb {
18
+ background: #5E35B1;
19
+ }
20
+
21
+ /* Handle on hover */
22
+ ::-webkit-scrollbar-thumb:hover {
23
+ background: #673AB7;
24
+ }
25
+
26
+
27
+ #db_images_bar
28
+ {
29
+ display: flex;
30
+ height:100px;
31
+ /* border:2px solid rgb(39, 86, 255); */
32
+ width: 100%;
33
+ padding-bottom: 10px;
34
+ }
35
+
36
+ #db_images_bar>.add_button{
37
+ background-color:rgb(205, 18, 234) ;
38
+ height: 60px;
39
+ width: 20%;
40
+ padding: 2px;
41
+ border-radius: 5px;
42
+ margin: auto 0;
43
+ margin-right: 5px;
44
+ display: flex;
45
+ align-items: center;
46
+ justify-content: center;
47
+ flex-direction: column;
48
+ }
49
+
50
+ #db_images_bar>.add_button:hover{
51
+ cursor: pointer;
52
+ }
53
+
54
+ #db_images_bar>.add_button>i{
55
+ color:white;
56
+ font-size: 3em;
57
+ }
58
+
59
+
60
+
61
+ #db_images
62
+ {
63
+ display: flex;
64
+ height: 100%;
65
+ width: 80%;
66
+ overflow: scroll hidden;
67
+ grid-row-start: 1;
68
+ }
69
+ .db_image{
70
+ height:inherit;
71
+ filter: blur(0);
72
+ transition: 0.3s;
73
+ border-radius: inherit;
74
+ }
75
+ .db_image_container{
76
+ height: inherit;
77
+ background: black;
78
+ margin-right:10px ;
79
+ position: relative;
80
+ display: inline-block;
81
+
82
+ border-radius: 20%;
83
+ }
84
+
85
+ .db_image_container:hover{
86
+ cursor: pointer;
87
+ }
88
+ .db_image_container:hover .db_image{
89
+ opacity: 0.5;
90
+ filter: blur(3px);
91
+ }
92
+
93
+ .db_image_container>.close_text{
94
+ opacity: 0;
95
+ font-size: xxx-large;
96
+ color:white;
97
+ position: absolute;
98
+ top:50%;
99
+ left:50%;
100
+ transform: translate(-50%,-50%);
101
+ padding: 0px;
102
+ margin: 0px;
103
+ transition: 0.3s;
104
+ }
105
+ .db_image_container:hover .close_text{
106
+ opacity: 1;
107
+ }
108
+
109
+
110
+
111
+
112
+
113
+
114
+
115
+ /*new main container*/
116
+ #container{
117
+ height:452px;
118
+ width:1000px;
119
+ /* border:2px dotted black; */
120
+ margin: 0 auto;
121
+ display: flex;
122
+ position: absolute;
123
+ top:50%;
124
+ left:50%;
125
+ transform: translate(-50%,-50%);
126
+ }
127
+
128
+ #container>.left-section{
129
+ height: inherit;
130
+ width:50%;
131
+ border-right:2px solid black;
132
+ display: flex;
133
+ align-items: center;
134
+ flex-direction: column;
135
+ padding: 10px;
136
+ }
137
+
138
+ #face_rec_image{
139
+ height: 65%;
140
+ /* border: 1px solid turquoise; */
141
+ border:0;
142
+
143
+ width: 150px;
144
+ }
145
+
146
+
147
+ .buttons{
148
+ display: flex;
149
+ align-items: center;
150
+ justify-content: center;
151
+ /* border:2px solid red; */
152
+ height:50px;
153
+ width:100%;
154
+ }
155
+
156
+ #container>.right-section{
157
+ height: inherit;
158
+ width:50%;
159
+ display: flex;
160
+ align-items: center;
161
+ flex-direction: column;
162
+ /* justify-content: center; */
163
+ padding: 10px;
164
+ }
165
+
166
+ #unassigned_faces{
167
+ width:100%;
168
+ height:100px;
169
+ /* border:1px solid rgb(255, 66, 255); */
170
+ padding:10px;
171
+ display: flex;
172
+ flex-direction: row;
173
+ align-items: center;
174
+ overflow: scroll hidden;
175
+ }
176
+
177
+ .crop_img{
178
+ height: 50px;
179
+ margin: 2px;
180
+ }
181
+
182
+ #name_list{
183
+ width:100%;
184
+ height:55%;
185
+ /* border:2px solid rgb(66, 113, 255); */
186
+ overflow: hidden scroll;
187
+ padding:15px;
188
+ }
189
+
190
+ #name_list>.person{
191
+ width:100%;
192
+ height: 80px;
193
+ border-bottom:2px solid chartreuse;
194
+ position: relative;
195
+ padding: 4px 1px;
196
+ display: flex;
197
+ align-items: end;
198
+ }
199
+ #name_list>.person>input{
200
+ position: absolute;
201
+ left:5px;
202
+ top:5px;
203
+ /* padding: inherit; */
204
+ background-color: transparent;
205
+ border:none;
206
+ outline: none;
207
+ }
208
+ #name_list>.person>input:focus{
209
+ border-bottom: 1px solid black;
210
+ }
211
+
212
+ #name_list>.person>i{
213
+ color:red;
214
+ position: absolute;
215
+ top:50%;
216
+ transform: translate(0,-50%);
217
+ right:20px;
218
+
219
+ }
220
+ #name_list>.person>i:hover{
221
+ cursor:pointer;
222
+ }
223
+
224
+ #name_list>.person>.faces{
225
+ height:fit-content;
226
+ width: 100%;
227
+
228
+ }
229
+
230
+
231
+ #add_name_btn{
232
+ margin: 40px;
233
+ width:inherit;
234
+ height:inherit;
235
+ }
app/static/user/dashboard.css ADDED
@@ -0,0 +1,305 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ :root{
2
+ /* --color-primary:#7380ec; */
3
+ /* --color-primary:rgb(205, 18, 234); */
4
+ --color-primary:rgb(163 18 234);
5
+ --color-secondary:rgb(173, 54, 232);
6
+
7
+ --color-name-border:red;
8
+ }
9
+
10
+
11
+ #api-key{
12
+ border:2px dashed black;
13
+ width:fit-content;
14
+ display: flex;
15
+ flex-direction: row;
16
+ /* column-gap: 2px; */
17
+
18
+ }
19
+
20
+ #api-key>p{
21
+ border:none;
22
+ padding:0 4px;
23
+ /* border-right: 2px solid black; */
24
+
25
+ }
26
+
27
+ #api-key>button{
28
+ /* padding:6px; */
29
+ /* border: 2px solid black; */
30
+ /* line-height: 2; */
31
+ cursor: pointer;
32
+ }
33
+
34
+ #database-form{
35
+ border:1px solid black;
36
+ display: flex;
37
+ flex-direction: column;
38
+ width:500px;
39
+ padding: 4px;
40
+ row-gap: 3px;
41
+ height: fit-content;
42
+ }
43
+
44
+ #database-form>.crops{
45
+ width:300px;
46
+ height:60px;
47
+ border:1px solid black;
48
+ }
49
+ #database-form>.assigned-crops{
50
+ width:300px;
51
+ height:100px;
52
+ border:1px solid black;
53
+ }
54
+
55
+ #database-form>.assigned-crops>.remark-crops{
56
+ width:300px;
57
+ height:100px;
58
+ border:1px solid black;
59
+ }
60
+
61
+ #database-form>.field{
62
+ display: flex;
63
+ flex-direction: row;
64
+ justify-items: center;
65
+ height: 30px;
66
+ overflow: hidden;
67
+ height: fit-content;
68
+ }
69
+
70
+ #database-form>.field>p{
71
+ padding: 0;
72
+ margin: 0;
73
+ width: fit-content;
74
+ height: fit-content;
75
+ margin-top: 0.3rem;
76
+ }
77
+
78
+
79
+ /*Copied from demo page css*/
80
+
81
+ #unassigned_faces{
82
+ width:100%;
83
+ height:100px;
84
+ border:1px solid rgb(255, 66, 255);
85
+ padding:10px;
86
+ column-gap: 5px;
87
+
88
+ display: flex;
89
+ flex-direction: row;
90
+ align-items: center;
91
+ box-sizing: border-box;
92
+ overflow: scroll hidden;
93
+ }
94
+
95
+
96
+
97
+
98
+
99
+
100
+ #remark_list{
101
+ width:100%;
102
+ height: 206px;
103
+ /* border:2px solid rgb(66, 113, 255); */
104
+ overflow: hidden scroll;
105
+ padding:15px;
106
+ box-sizing: border-box;
107
+ }
108
+
109
+ #remark_list>.remark{
110
+ width:100%;
111
+ height: 80px;
112
+ border-bottom:2px solid var(--color-name-border);
113
+ position: relative;
114
+ padding: 4px 1px;
115
+ display: flex;
116
+ align-items: end;
117
+ }
118
+ #remark_list>.remark>input{
119
+ position: absolute;
120
+ left:5px;
121
+ top:5px;
122
+ /* padding: inherit; */
123
+ background-color: transparent;
124
+ border:none;
125
+ outline: none;
126
+ }
127
+ #remark_list>.remark>input:focus{
128
+ border-bottom: 1px solid var(--color-name-border);
129
+ }
130
+
131
+ #remark_list>.remark>i{
132
+ color:red;
133
+ position: absolute;
134
+ top:50%;
135
+ transform: translate(0,-50%);
136
+ right:20px;
137
+
138
+ }
139
+ #remark_list>.remark>i:hover{
140
+ cursor:pointer;
141
+ }
142
+
143
+ #remark_list>.remark>.faces{
144
+ height:fit-content;
145
+ width: 100%;
146
+ display: flex;
147
+ column-gap: 5px;
148
+ }
149
+
150
+ .buttons{
151
+ display: flex;
152
+ justify-content: center;
153
+ }
154
+
155
+ #add_remark_btn{
156
+ margin: 40px;
157
+ padding: 4px 12px;
158
+ width:fit-content;
159
+ height:inherit;
160
+ }
161
+
162
+ .btn{
163
+ background-color: var(--color-primary);
164
+ box-shadow: 0px 0px 43px -4px var(--color-secondary);
165
+ border-radius: 5px;
166
+ border:none;
167
+ }
168
+ .btn:hover{
169
+ cursor: pointer;
170
+ background-color: var(--color-secondary);
171
+ /* box-shadow: 0px 0px 43px -4px var(--color-secondary); */
172
+
173
+ }
174
+
175
+ /*end of Copied from demo page css*/
176
+
177
+ #database-form>.field>.add_button{
178
+ height: 60px;
179
+ width: 20%;
180
+ padding: 2px;
181
+ margin: auto 0;
182
+ margin-right: 5px;
183
+ display: flex;
184
+ align-items: center;
185
+ justify-content: center;
186
+ flex-direction: column;
187
+ z-index: 2;
188
+ }
189
+
190
+
191
+ #database-form>.field>.add_button>i{
192
+ color:white;
193
+ background-color: inherit;
194
+ font-size: 3em;
195
+ }
196
+ .crop_img{
197
+ height: 60px;
198
+ }
199
+
200
+ #face_recognition_image{
201
+ height:200px;
202
+ width:200px;
203
+ }
204
+
205
+
206
+ #db_people_table{
207
+ width:300px;
208
+ height:200px;
209
+ }
210
+
211
+
212
+ table, th, td {
213
+ border:2px solid black;
214
+ border-collapse: collapse;
215
+ text-align: center;
216
+ }
217
+
218
+ .remove{
219
+ background-color: red;
220
+ }
221
+
222
+ button:hover{
223
+ cursor: pointer;
224
+ }
225
+
226
+
227
+ /*copied from demo page*/
228
+
229
+ .settings_btn{
230
+ position: absolute;
231
+ top:40px;
232
+ right:40px;
233
+ font-size: larger;
234
+ }
235
+
236
+ #settings_menu{
237
+ background-color: white;
238
+ height: fit-content;
239
+ width:40%;
240
+ z-index: 10000;
241
+ position: absolute;
242
+ top:50%;
243
+ left:50%;
244
+ transform: translate(-50%,-50%);
245
+ border-radius: 10px;
246
+ box-shadow: 0px 0px 43px -4px var(--color-primary);
247
+ padding: 2px 20px;
248
+ display: none;
249
+ }
250
+ #settings_menu>h1{
251
+ background-color: inherit;
252
+ }
253
+ #settings_menu>.settings{
254
+ background-color: inherit;
255
+ height: 280px;
256
+ overflow: hidden scroll;
257
+ position: relative;
258
+ }
259
+
260
+ #settings_menu>.close_btn{
261
+ color:red;
262
+ position: absolute;
263
+ top: 20px;
264
+ right: 20px;
265
+ font-size: larger;
266
+ background-color: transparent;
267
+ }
268
+ #settings_menu>.close_btn:hover{
269
+ cursor: pointer;
270
+ }
271
+
272
+ .reset_btn_container{
273
+ position: absolute;
274
+ top: 20px;
275
+ right: 30px;
276
+ }
277
+ .reset_btn_container>.reset_btn{
278
+ color:white;
279
+ position: fixed;
280
+ font-size: larger;
281
+ background-color: transparent;
282
+ }
283
+ .reset_btn_container>.reset_btn:hover{
284
+ cursor: pointer;
285
+ }
286
+
287
+ #container.blur{
288
+ filter: blur(5px);
289
+ pointer-events: none;
290
+ }
291
+
292
+ #save_btn_container{
293
+ display: flex;
294
+ justify-content: center;
295
+ margin: 10px 0px;
296
+ font-size: large;
297
+ }
298
+ #save_settings_btn{
299
+ background-color: rgb(76, 76, 232);
300
+ outline: none;
301
+ border: none;
302
+ border-radius: 6px;
303
+ }
304
+
305
+ /*End copied from demo page*/
app/static/user/dashboard.js ADDED
@@ -0,0 +1,483 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var dragged_elem;
2
+ var features_updated=false;
3
+ var touch_start_time=null;
4
+ var elapsedTime=null;
5
+ var maxAllowedTime=500;
6
+
7
+ function drag(ev){
8
+ // ev.preventDefault();
9
+ console.log(ev.target.id);
10
+ dragged_elem=ev.target;
11
+ // ev.dataTransfer.setData("text",ev.target.id);
12
+ }
13
+
14
+ function dragTouchstart(e,elem) {
15
+ elapsedTime=null;
16
+ touch_start_time = new Date().getTime();
17
+ }
18
+ function dragTouchmove(e,elem) {
19
+
20
+ let touchX = e.touches[0].pageX;
21
+ let touchY = e.touches[0].pageY;
22
+
23
+ if(elapsedTime==null)
24
+ {
25
+ elapsedTime = new Date().getTime() - touch_start_time;
26
+ }
27
+
28
+ // console.log(elapsedTime);
29
+
30
+ if (elapsedTime<maxAllowedTime) return;
31
+
32
+ // console.log("no-scroll")
33
+ e.preventDefault()
34
+
35
+ if (dragged_elem==null)
36
+ {
37
+ dragged_elem=elem;
38
+ console.log(dragged_elem);
39
+ }
40
+
41
+ }
42
+
43
+ function allowDrop(ev){
44
+ ev.preventDefault();
45
+ console.log("ready to be dropped");
46
+ }
47
+
48
+ function drop(ev,element){
49
+ ev.preventDefault();
50
+ console.log("dropped!");
51
+ element.appendChild(dragged_elem);
52
+ dragged_elem=null;
53
+ features_updated=false;
54
+
55
+ }
56
+
57
+ function dragTouchend(e,elem) {
58
+
59
+ if(dragged_elem==null) return;
60
+
61
+ var droppable_element=document.elementFromPoint(e.changedTouches[0].clientX, e.changedTouches[0].clientY).closest(".droppable");
62
+ if(droppable_element==null) return;
63
+
64
+ if(droppable_element.hasAttribute("data-dropto")) droppable_element=droppable_element.querySelector(droppable_element.dataset.dropto)
65
+
66
+ droppable_element.appendChild(dragged_elem);
67
+
68
+ console.log(droppable_element)
69
+ dragged_elem=null;
70
+ features_updated=false;
71
+ // e.target.style.transform="scale(0.8)";
72
+ }
73
+
74
+
75
+
76
+ function count_words(elem){
77
+ var count = 0;
78
+
79
+ // Split the words on each
80
+ // space character
81
+ var split = elem.value.split(' ');
82
+
83
+ // Loop through the words and
84
+ // increase the counter when
85
+ // each split word is not empty
86
+ for (var i = 0; i < split.length; i++) {
87
+ if (split[i] != "") {
88
+ count += 1;
89
+ }
90
+ }
91
+ console.log("count:",count)
92
+ }
93
+
94
+ document.querySelector("#api-key>.copy").addEventListener("click",function(e){
95
+ var key_tag=document.querySelector("#api-key>p");
96
+ key_tag.focus();
97
+ console.log(key_tag.innerText);
98
+ navigator.clipboard.writeText(key_tag.innerText);
99
+ })
100
+
101
+
102
+ document.querySelector("#api-key>.refresh").addEventListener("click",function(e){
103
+ var key_tag=document.querySelector("#api-key>p");
104
+ fetch("update_key/").then(function(response){
105
+ return response.json();
106
+ }).then(function(response){
107
+ console.log(response);
108
+ if ("key" in response){
109
+ key_tag.innerText=response["key"];
110
+ }
111
+ });
112
+ })
113
+
114
+
115
+
116
+
117
+
118
+ function deselect(e,elem){
119
+ // document.body.focus();
120
+
121
+ if(e.key=="Enter")
122
+ elem.blur();
123
+ else if(elem.value!=elem.dataset.name)
124
+ features_updated=false;
125
+ }
126
+
127
+
128
+ function remove_remark(remark){
129
+ var unassigned_faces=document.querySelector("#unassigned_faces");
130
+ var all_crops=remark.querySelectorAll("#remark_list>.remark>.faces>img");
131
+ all_crops.forEach(function(crop){
132
+ unassigned_faces.appendChild(crop);
133
+ })
134
+ remark.remove();
135
+ }
136
+
137
+
138
+ function add_remark(){
139
+ // make such a structure:
140
+ // <div class="remark" ondragover="allowDrop(event)" ondrop="drop(event,this)">
141
+ // <input type="text" value="Anuj" ondrop="return false;" onkeypress="deselect(event,this);">
142
+ // <div class="faces"></div>
143
+ // <i class="fa-solid fa-xmark" onclick="this.parentElement.remove();"></i>
144
+ // </div>
145
+ var remark=document.createElement("div");
146
+ remark.setAttribute("class","remark droppable");
147
+ remark.dataset.dropto=".faces";
148
+ remark.setAttribute("ondragover","allowDrop(event)");
149
+ remark.setAttribute("ondrop","drop(event,this.querySelector('#remark_list>.remark>.faces'))");
150
+ var name=document.createElement("input");
151
+ name.setAttribute("type","text");
152
+ name.setAttribute("ondrop","return false;");
153
+ name.setAttribute("onkeyup","deselect(event,this);");
154
+ var faces=document.createElement("div");
155
+ faces.setAttribute("class","faces");
156
+ var close_icon=document.createElement("i");
157
+ close_icon.setAttribute("class","fa-solid fa-xmark");
158
+ close_icon.setAttribute("onclick","remove_remark(this.parentElement);");
159
+ remark.appendChild(name);
160
+ remark.appendChild(faces);
161
+ remark.appendChild(close_icon);
162
+ document.querySelector("#remark_list").appendChild(remark);
163
+ name.focus();
164
+ // name.select();
165
+
166
+ }
167
+
168
+
169
+ function filterFunction() {
170
+ var input, filter, ul, li, a, i;
171
+ input = document.getElementById("myInput");
172
+ filter = input.value.toUpperCase();
173
+ div = document.getElementById("myDropdown");
174
+ a = div.getElementsByTagName("a");
175
+ for (i = 0; i < a.length; i++) {
176
+ txtValue = a[i].textContent || a[i].innerText;
177
+ if (txtValue.toUpperCase().indexOf(filter) > -1) {
178
+ a[i].style.display = "";
179
+ } else {
180
+ a[i].style.display = "none";
181
+ }
182
+ }
183
+ }
184
+
185
+
186
+
187
+ var database_input=document.querySelector("#database-form>.field>.add_button>input")
188
+ database_input.addEventListener("change", function(e){
189
+ if(e.target.files[0]){
190
+ console.log(e.target.files[0].name);
191
+
192
+ const formdata = new FormData();
193
+ formdata.append("image",e.target.files[0]);
194
+
195
+
196
+ fetch("get_crops/",
197
+ {
198
+ method:'POST',
199
+ body:formdata,
200
+ }).then(
201
+ function(response)
202
+ {
203
+ return response.json();
204
+ }
205
+ ).then(
206
+ function(response)
207
+ {
208
+ console.log(response);
209
+
210
+ if (response['message']=='successful')
211
+ {
212
+ // add crops to the #unassigned_faces
213
+ var crop_container=document.querySelector("#unassigned_faces");
214
+ for(var i=0;i<response["crops"].length;i++)
215
+ {
216
+
217
+ var crop_img=document.createElement("img");
218
+ crop_img.src="data:image/jpeg;base64,"+response["crops"][i].split('\'')[1];
219
+ crop_img.setAttribute("class","crop_img");
220
+ // crop_img.setAttribute("id",crop_img.dataset.image_name+'\\'+crop_img.dataset.crop_name);
221
+ crop_img.setAttribute("draggable","true");
222
+ crop_img.setAttribute("ondragstart","drag(event)");
223
+ crop_container.appendChild(crop_img)
224
+
225
+ // disable right click
226
+ crop_img.addEventListener("contextmenu",function(ev){ev.preventDefault();});
227
+ //make it work with touch
228
+ crop_img.setAttribute("ontouchstart","dragTouchstart(event,this);");
229
+ crop_img.setAttribute("ontouchmove","dragTouchmove(event,this);");
230
+ crop_img.setAttribute("ontouchend","dragTouchend(event,this);");
231
+
232
+ }
233
+
234
+ // response['images'].forEach(img_name => {
235
+ // img_tag=document.createElement("img");
236
+ // img_tag.src=Flask.url_for('upload',{subfolder:'images',filename:img_name} );
237
+ // images_div.appendChild(img_tag);
238
+ // });
239
+ }
240
+
241
+
242
+ }
243
+ );
244
+ }
245
+ });
246
+
247
+
248
+ function update_db_crops(elem)
249
+ {
250
+ var all_remarks={};
251
+ var num_of_remarks=0;
252
+
253
+ var face_remarks=document.querySelectorAll("#remark_list>.remark");
254
+
255
+ for (var i=0;i<face_remarks.length;i++)
256
+ {
257
+ var faces=face_remarks[i].querySelectorAll("#remark_list>.remark>.faces>img");
258
+ var face_base64_list=[]
259
+ if (faces.length>0)
260
+ {
261
+ for(var j=0;j<faces.length;j++)
262
+ {
263
+ face_base64_list.push(faces[j].src.split(',',2)[1])
264
+ }
265
+ all_remarks[face_remarks[i].querySelector("input").value]=face_base64_list;
266
+
267
+ num_of_remarks+=1;
268
+
269
+ }
270
+
271
+ }
272
+
273
+ if (num_of_remarks>0)
274
+ {
275
+
276
+ var alldata={};
277
+ alldata["person_name"]=document.querySelector("#database-form>.field>.person_name").value;
278
+ alldata["remarks"]=all_remarks;
279
+ console.log(alldata);
280
+
281
+
282
+
283
+ fetch("set_crops/",{
284
+ method:"POST",
285
+ headers: { "Content-Type": "application/json"},
286
+ body:JSON.stringify(alldata)
287
+ }).then(function(response){
288
+ return response.json();
289
+ }).then(function(response){
290
+ console.log(response);
291
+ var person_ids=document.querySelectorAll("#db_people_table>tr>td:first-child");
292
+ var matching_person_id=null;
293
+ person_ids.forEach(element => {
294
+ if(element.innerText==alldata["person_name"])
295
+ {
296
+ element.parentElement.remove();
297
+ // element
298
+ }
299
+ });
300
+ alldata["remarks"]
301
+ add_person_row(alldata["person_name"],Object.keys(alldata["remarks"]).join(","));
302
+
303
+ });
304
+
305
+ }
306
+ else{
307
+ console.log("add database faces first");
308
+ }
309
+
310
+
311
+
312
+ }
313
+
314
+ function face_recoginization(elem){
315
+ if(elem.files[0]){
316
+ formdata=new FormData();
317
+ formdata.append("image",elem.files[0]);
318
+ fetch("face_recognize/",{
319
+ method:"POST",
320
+ body:formdata
321
+ }).then(function(response){
322
+ return response.json();
323
+ }).then(function(response){
324
+ console.log(response);
325
+ document.querySelector("#face_recognition_image").src="data:image/jpeg;base64,"+response["pred_image"].split('\'')[1];
326
+ document.querySelector("#face_recognition_image").style.width="unset";
327
+ })
328
+ }
329
+ }
330
+
331
+
332
+
333
+
334
+
335
+ function add_person_row(person_id,remarks)
336
+ {
337
+ //#db_people_table
338
+ // <tr>
339
+ // <td>anuj</td>
340
+ // <td>Front_face</td>
341
+ //
342
+ // <td>
343
+ // <button class="remove"><i class="fa-solid fa-close"></i></button>
344
+ // </td>
345
+ // </tr>
346
+ var table_row=document.createElement("tr");
347
+ var person_id_tag=document.createElement("td");
348
+ person_id_tag.innerText=person_id;
349
+ var remarks_tag=document.createElement("td");
350
+ remarks_tag.innerText=remarks;
351
+
352
+ var remove_tag=document.createElement("td");
353
+ remove_tag.innerHTML='<button class="remove" onclick="delete_person(this);"><i class="fa-solid fa-close"></i></button>';
354
+ table_row.appendChild(person_id_tag);
355
+ table_row.appendChild(remarks_tag);
356
+ table_row.appendChild(remove_tag);
357
+
358
+ // document.querySelector("#db_people_table").appendChild(table_row);
359
+ var table=document.querySelector("#db_people_table > tbody");
360
+ table.after(table_row);
361
+ }
362
+
363
+
364
+ // get_all_persons_from_db/
365
+ fetch("get_all_persons_from_db/").then(function(response){
366
+ return response.json();
367
+ }).then(function(response){
368
+ console.log(response);
369
+ for (var i=0 ; i<response['person_ids'].length;i++){
370
+ add_person_row(response['person_ids'][i],response['remarks'][i])
371
+ }
372
+ })
373
+
374
+
375
+
376
+
377
+ function delete_person(elem){
378
+ // console.log(elem);
379
+ console.log(elem.getAttribute("class"));
380
+ var row=elem.parentNode.parentNode;
381
+ // username:row.firstChild.innerText
382
+
383
+ if (elem.getAttribute("class")=="remove")
384
+ {
385
+ const response = confirm("Are you sure you want to do that?");
386
+ if (!response)
387
+ {
388
+ return;
389
+ }
390
+ }
391
+
392
+
393
+ fetch("remove_person_from_db/",{
394
+ method:"POST",
395
+ headers: { "Content-Type": "application/json"},
396
+ body:JSON.stringify({"person_id":row.firstChild.innerText})
397
+ }).then(function(response){
398
+ return response.json();
399
+ }).then(function(response){
400
+ console.log("response:",response);
401
+
402
+ row.remove();
403
+ })
404
+
405
+
406
+
407
+ }
408
+
409
+
410
+ function show_settings(){
411
+ document.querySelector('#settings_menu').style.display='block';
412
+ document.querySelector('#container').classList.add("blur");
413
+ }
414
+ function hide_settings(){
415
+ document.querySelector('#settings_menu').style.display='none';
416
+ document.querySelector('#container').classList.remove("blur");
417
+ }
418
+
419
+
420
+
421
+ function get_settings(){
422
+ fetch("get_settings/",{
423
+ method:"GET"
424
+ }).then(function(response){
425
+ return response.json();
426
+ }).then(function(res){
427
+ console.log(res);
428
+
429
+ p_thres.value=p_thresValue.innerText=res['p_thres'];
430
+ nms_thres.value=nms_thresValue.innerText=res['nms_thres'];
431
+
432
+ small_size.value=small_sizeValue.innerText=res['small_size'];
433
+ large_size.value=large_sizeValue.innerText=res['large_size'];
434
+
435
+ d_thres.value=d_thresValue.innerText=res['d_thres'];
436
+ a_thres.value=a_thresValue.innerText=res['a_thres'];
437
+
438
+ db_mode.value=res['db_mode'];
439
+ fr_mode.value=res['fr_mode'];
440
+ console.log(res['db_mode'],res['fr_mode']);
441
+ })
442
+ }
443
+ get_settings();
444
+ // document.querySelector('#p_thres')
445
+ // document.querySelector('#p_thres').value
446
+
447
+ function update_settings(){
448
+ var new_settings=new Object();
449
+ new_settings['p_thres']=p_thres.value;
450
+ new_settings['nms_thres']=nms_thres.value;
451
+ new_settings['small_size']=small_size.value;
452
+ new_settings['large_size']=large_size.value;
453
+ new_settings['d_thres']=d_thres.value;
454
+ new_settings['a_thres']=a_thres.value;
455
+ new_settings['db_mode']=db_mode.value;
456
+ new_settings['fr_mode']=fr_mode.value;
457
+
458
+ fetch("update_settings/",{
459
+ method:"POST",
460
+ headers:{'content-type': 'application/json'},
461
+ body:JSON.stringify(new_settings)
462
+ }).then(function(response){
463
+ return response.json();
464
+ }).then(function(res){
465
+ console.log(res);
466
+ if(res['message']=='success')
467
+ hide_settings();
468
+ }
469
+ );
470
+ }
471
+
472
+ function reset_settings(){
473
+ fetch("reset_settings/",{
474
+ method:"GET"
475
+ }).then(function(response){
476
+ return response.json();
477
+ }).then(function(res){
478
+ console.log(res);
479
+ if(res['message']=='success')
480
+ get_settings();
481
+ }
482
+ );
483
+ }
app/static/user/login.css ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #container{
2
+ position: absolute;
3
+ top:50%;
4
+ left:50%;
5
+ transform:translate(-50%,-50%);
6
+ display: flex;
7
+ row-gap: 20px;
8
+ flex-direction: column;
9
+ align-items: center;
10
+ border:2px solid black;
11
+ /* box-sizing: border-box; */
12
+
13
+ padding: 20px;
14
+ }
15
+ #container>h1{
16
+ text-align: center;
17
+ margin: 0px;
18
+ }
19
+ #container>p{
20
+ text-align: center;
21
+ margin: 0px;
22
+ margin-bottom: 5px;
23
+ visibility: hidden;
24
+ color:red;
25
+ }
26
+ .active{
27
+ visibility: visible !important;
28
+ }
29
+
30
+ #container>div{
31
+ display: flex;
32
+ width:314px;
33
+ justify-content: space-between;
34
+ }
35
+ #container>div>p{
36
+ margin: 0;
37
+ }
38
+
39
+ #container>div>input{
40
+ border:none;
41
+ outline:none;
42
+ border-bottom:1px solid black;
43
+ }
44
+
45
+ #container>input{
46
+ width:30%;
47
+ margin: 10px;
48
+ }
49
+
app/static/user/registeration.css ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #container{
2
+ position: absolute;
3
+ top:50%;
4
+ left:50%;
5
+ transform:translate(-50%,-50%);
6
+ display: flex;
7
+ row-gap: 20px;
8
+ flex-direction: column;
9
+ align-items: center;
10
+ border:2px solid black;
11
+ /* box-sizing: border-box; */
12
+
13
+ padding: 20px;
14
+ }
15
+ #container>h1{
16
+ text-align: center;
17
+ margin: 0px;
18
+ }
19
+ #container>p{
20
+ text-align: center;
21
+ margin: 0px;
22
+ margin-bottom: 5px;
23
+ visibility: hidden;
24
+ color:red;
25
+ }
26
+
27
+ #container>div{
28
+ display: flex;
29
+ width:314px;
30
+ justify-content: space-between;
31
+ }
32
+ #container>div>p{
33
+ margin: 0;
34
+ }
35
+
36
+ #container>div>input{
37
+ border:none;
38
+ outline:none;
39
+ border-bottom:1px solid black;
40
+ }
41
+
42
+ #container>input{
43
+ width:30%;
44
+ }
app/static/user/registeration.js ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function check_username(elem){
2
+ if(elem.value!=''){
3
+ fetch(`/user/is_username_available/?username=${elem.value}`,{
4
+ method:"GET",
5
+
6
+ }).then(function(response){
7
+ return response.json();
8
+ }).then(function(response){
9
+ // show a indicator that this username is available
10
+ if(response['available'])
11
+ {
12
+ // show green indicator
13
+ console.log("Username available");
14
+ elem.dataset.valid=true;
15
+ elem.style.borderColor='green';
16
+ elem.style.borderWidth=4;
17
+ }
18
+ else
19
+ {
20
+ // show red indicator
21
+ console.log("Username unavailable");
22
+ elem.dataset.valid=false;
23
+ elem.style.borderColor='red';
24
+ elem.style.borderWidth=4;
25
+ }
26
+ });
27
+ }
28
+ }
29
+
30
+ function check_password_is_matching(confirm_password){
31
+ var password=document.querySelector("#password");
32
+ if(confirm_password.value!=password.value){
33
+ confirm_password.style.borderColor='red';
34
+ confirm_password.style.borderWidth=4;
35
+ }
36
+ else{
37
+ confirm_password.style.borderColor='green';
38
+ confirm_password.style.borderWidth=4;
39
+ }
40
+ }
41
+
42
+ function validate_form(form){
43
+ if(form.username.dataset.valid=="false"){
44
+ document.querySelector("#container>p").style.visibility='visible';
45
+ document.querySelector("#container>p").innerText="username not available";
46
+ return false;
47
+ }
48
+ else if(form.password.value!=form.confirm_password.value){
49
+ document.querySelector("#container>p").style.visibility='visible';
50
+ document.querySelector("#container>p").innerText="password not matching";
51
+ return false;
52
+ }
53
+ else{
54
+ return true;
55
+ }
56
+ }
57
+
58
+ function count_words(elem){
59
+ var count = 0;
60
+
61
+ // Split the words on each
62
+ // space character
63
+ var split = elem.value.split(' ');
64
+
65
+ // Loop through the words and
66
+ // increase the counter when
67
+ // each split word is not empty
68
+ for (var i = 0; i < split.length; i++) {
69
+ if (split[i] != "") {
70
+ count += 1;
71
+ }
72
+ }
73
+ console.log("count:",count)
74
+ }
app/templates/admin/dashboard.html ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+ {% block title %}Dashboard{% endblock %}
3
+ {% block css %}
4
+ <link type="text/css" rel="stylesheet" href="{{ url_for('static',filename='admin/dashboard.css') }}">
5
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css">
6
+ {% endblock %}
7
+ {% block body %}
8
+
9
+
10
+ <table id="access_requests_table">
11
+ <tr>
12
+ <th>Username</th>
13
+ <th>request message</th>
14
+ <th>accept/cancel</th>
15
+ </tr>
16
+ </table>
17
+ <br>
18
+ <br>
19
+ <table id="access_granted_table">
20
+ <tr>
21
+ <th>Username</th>
22
+ <th>remove_access</th>
23
+ </tr>
24
+ </table>
25
+
26
+ <script src="{{ url_for('static',filename='admin/dashboard.js') }}"></script>
27
+
28
+ {% endblock %}
app/templates/admin/login.html ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+ {% block title %}Login{% endblock %}
3
+ {% block css %}
4
+ <link type="text/css" rel="stylesheet" href="{{ url_for('static',filename='admin/login.css') }}">
5
+ <!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css"> -->
6
+ {% endblock %}
7
+ {% block body %}
8
+ <form id="container" action="/admin/authenticate/" method="post">
9
+ <h1>Log-In</h1>
10
+ <p class="{{message_class}}">{{message}}</p>
11
+ <div>
12
+ <p>Enter Username:</p>
13
+ <input type="username" name="username" required>
14
+ </div>
15
+ <div>
16
+ <p>Enter password:</p>
17
+ <input type="password" name="password" required>
18
+ </div>
19
+ <input type="submit">
20
+ <!-- <button>Sign-in</button> -->
21
+
22
+ </form>
23
+ <!-- <script src="{{ url_for('static',filename='/login.js') }}"></script> -->
24
+
25
+ {% endblock %}
app/templates/base.html ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <html>
2
+ <head>
3
+
4
+ <title>{% block title %}Face Recognization{% endblock %}</title>
5
+
6
+ <link type="image/*" rel="icon" href="{{ url_for('static',filename='demo/index/icon.jpg' ) }}">
7
+
8
+ {% block css %}{% endblock %}
9
+ </head>
10
+ <body>
11
+ {% block body %}{% endblock %}
12
+ </body>
13
+ </html>
app/templates/demo.html ADDED
@@ -0,0 +1 @@
 
 
1
+ <h1>demo page</h1>
app/templates/demo/index.html ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+ {% block title %}Face Recognization{% endblock %}
3
+ {% block css %}
4
+ <link type="text/css" rel="stylesheet" href="{{ url_for('static',filename='demo/index/dark.css') }}">
5
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css">
6
+ <link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">
7
+ {% endblock %}
8
+ {% block body %}
9
+ <i class="fa-solid fa-gear settings_btn" onclick="show_settings();"></i>
10
+ <div id="container">
11
+ <div class="left-section">
12
+ <!-- Databases images upload -->
13
+ <div id="db_images_bar">
14
+ <button class="btn add_button" onclick="document.querySelector('.add_button>input').click();">
15
+ <input type="file" accept="image/*" style="display:none;" >
16
+ <i class="fa-solid fa-plus"></i>
17
+ add image
18
+ </button>
19
+ <div id="db_images"></div>
20
+ </div>
21
+
22
+ <!-- Face Recognition output -->
23
+ <img id="face_rec_image">
24
+
25
+ <!-- Face Recognition buttons -->
26
+ <div class="buttons">
27
+ <div>
28
+ <input type="file" id="face_rec_input" accept="image/*" style="display:none;" onchange="load_image_preview(this);">
29
+ <input type="button" value="Upload" class="btn" onclick="document.querySelector('.buttons>div>#face_rec_input').click();">
30
+ <input type="button" value="recognize" class="btn" onclick="update_crops_labels(document.querySelector('.buttons>div>#face_rec_input'))">
31
+ </div>
32
+ </div>
33
+ </div>
34
+ <div class="right-section">
35
+ <!--all unassigned cropped images-->
36
+ <div id="unassigned_faces" class="droppable" ondragover="allowDrop(event)" ondrop="drop(event,this)"></div>
37
+ <p>Drag faces to names</p>
38
+ <!--assigned faces with names list-->
39
+ <div id="name_list">
40
+ <div class="person droppable" data-dropto=".faces" ondragover="allowDrop(event)" ondrop="drop(event,this.querySelector('.faces'))">
41
+ <input type="text" value="person-1" ondrop="return false;" onkeyup="deselect(event,this);">
42
+ <div class="faces"></div>
43
+ <i class="fa-solid fa-xmark" onclick="remove_person(this.parentElement);"></i>
44
+
45
+ </div>
46
+ </div>
47
+ <!--add name button-->
48
+ <div class="buttons">
49
+ <input type="button" value="add name" class="btn" onclick="add_person();" id="add_name_btn">
50
+ </div>
51
+
52
+
53
+ </div>
54
+ </div>
55
+
56
+ <div id="settings_menu">
57
+ <h1>settings</h1>
58
+ <i class="fa-solid fa-xmark close_btn" onclick="hide_settings();"></i>
59
+
60
+ <div class="settings">
61
+ <div class="reset_btn_container">
62
+ <i class="fa-solid fa-rotate-left reset_btn" onclick="reset_settings();"></i>
63
+ </div>
64
+ <dl>
65
+ <li>Face detector Modes</li>
66
+ <dd>
67
+ <a>db_mode :</a>
68
+ <select id="db_mode">
69
+ <option value="small">small</option>
70
+ <option value="large">large</option>
71
+ <option value="both">both</option>
72
+ </select>
73
+
74
+ </dd>
75
+ <dd>
76
+ <a>fr_mode :</a>
77
+ <select id="fr_mode">
78
+ <option value="small">small</option>
79
+ <option value="large">large</option>
80
+ <option value="both">both</option>
81
+ </select>
82
+
83
+ </dd>
84
+ <br>
85
+ <li>Face detector</li>
86
+ <dd>
87
+ <a>p_thres :</a>
88
+ <input id="p_thres" type="range" min="0" max="1" step="0.05" oninput="p_thresValue.innerText=this.value">
89
+ <a id="p_thresValue"></a>
90
+ </dd>
91
+ <dd>
92
+ <a>nms_thres :</a>
93
+ <input id="nms_thres" type="range" min="0" max="1" step="0.05" oninput="nms_thresValue.innerText=this.value">
94
+ <a id="nms_thresValue"></a>
95
+ </dd>
96
+ <dd>
97
+ <a>small_size :</a>
98
+ <input id="small_size" type="range" min="64" max="2080" step="32" oninput="small_sizeValue.innerText=this.value">
99
+ <a id="small_sizeValue"></a>
100
+ </dd>
101
+ <dd>
102
+ <a>large_size :</a>
103
+ <input id="large_size" type="range" min="64" max="2080" step="32" oninput="large_sizeValue.innerText=this.value">
104
+ <a id="large_sizeValue"></a>
105
+ </dd>
106
+ <br>
107
+ <li>Face Recognizer</li>
108
+ <dd>
109
+ <a>d_thres :</a>
110
+ <input id="d_thres" type="range" min="0" max="1" step="0.05" oninput="d_thresValue.innerText=this.value">
111
+ <a id="d_thresValue"></a>
112
+ </dd>
113
+ <br>
114
+ <li>Aligner</li>
115
+ <dd>
116
+ <a>a_thres :</a>
117
+ <input id="a_thres" type="range" min="0" max="1" step="0.05" oninput="a_thresValue.innerText=this.value">
118
+ <a id="a_thresValue"></a>
119
+ </dd>
120
+
121
+
122
+ </dl>
123
+ </div>
124
+ <div id="save_btn_container"><button id="save_settings_btn" onclick="update_settings();">Save</button></div>
125
+
126
+ </div>
127
+
128
+ <script src="{{ url_for('static',filename='demo/index/script.js' ) }}"></script>
129
+
130
+ {% endblock %}
app/templates/user/dashboard.html ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+ {% block title %}Dashboard{% endblock %}
3
+ {% block css %}
4
+ <link type="text/css" rel="stylesheet" href="{{ url_for('static',filename='user/dashboard.css') }}">
5
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css">
6
+ {% endblock %}
7
+ {% block body %}
8
+ <!--
9
+ <div id="request-api-access">
10
+ <textarea onkeyup="count_words(this);" id="inputField" rows=10 cols="60">{{data_dict["request_message"]}}</textarea>
11
+ <button><i class="fa-solid fa-plus"></i> Request Api Access</button>
12
+ </div> -->
13
+
14
+ <br>
15
+ <br>
16
+
17
+ {% if data_dict['access_key']==None %}
18
+
19
+ <p>You will be soon provided access after someone reviews your api access request</p>
20
+
21
+
22
+ {% elif data_dict['access_key']=='rejected' %}
23
+ <p>sorry you are not given access </p>
24
+ {% else %}
25
+ <i class="fa-solid fa-gear settings_btn" onclick="show_settings();"></i>
26
+ <div id="container">
27
+ <div id="api-key">
28
+ <!-- <input type="text" value="{{data_dict['access_key']}}"> -->
29
+ <p>{{data_dict['access_key']}}</p>
30
+ <button class="copy"><i class="fa fa-copy"></i></button>
31
+ <button class="refresh"><i class="fa fa-refresh"></i> Request new key</button>
32
+ </div>
33
+ <br>
34
+ <form id="database-form" onsubmit="return false;">
35
+
36
+ <div class="field">
37
+ <p>Name:</p>
38
+ <input class="person_name" type="text">
39
+ </div>
40
+
41
+ <div class="field">
42
+ <button class="btn add_button" onclick="document.querySelector('.add_button>input').click();">
43
+ <input type="file" accept="image/*" style="display:none;" >
44
+ <i class="fa-solid fa-plus"></i>
45
+ add image
46
+ </button>
47
+ </div>
48
+
49
+
50
+ <div id="unassigned_faces" class="droppable" ondragover="allowDrop(event)" ondrop="drop(event,this)"></div>
51
+ <p>Drag faces to remarks</p>
52
+
53
+ <!--assigned faces with names list-->
54
+ <div id="remark_list">
55
+ <div class="remark droppable" data-dropto=".faces" ondragover="allowDrop(event)" ondrop="drop(event,this.querySelector('#remark_list>.remark>.faces'))">
56
+ <input type="text" value="front-face" ondrop="return false;" onkeyup="deselect(event,this);">
57
+ <div class="faces"></div>
58
+ <i class="fa-solid fa-xmark" onclick="remove_remark(this.parentElement);"></i>
59
+
60
+ </div>
61
+ </div>
62
+ <!--add name button-->
63
+ <div class="buttons">
64
+ <input type="button" value="add remark" class="btn" onclick="add_remark();" id="add_remark_btn">
65
+ </div>
66
+ <input type="button" value="submit" onclick="update_db_crops();">
67
+ </form>
68
+ <table id="db_people_table">
69
+ <tbody>
70
+ <tr>
71
+ <th>Person_ID</th>
72
+ <th>Remarks</th>
73
+ <th>Remove</th>
74
+ </tr>
75
+ </tbody>
76
+ </table>
77
+ <br>
78
+ <br>
79
+ <input type="file" onchange="face_recoginization(this);">
80
+ <img id="face_recognition_image">
81
+ </div>
82
+
83
+ <div id="settings_menu">
84
+ <h1>settings</h1>
85
+ <i class="fa-solid fa-xmark close_btn" onclick="hide_settings();"></i>
86
+
87
+ <div class="settings">
88
+ <div class="reset_btn_container">
89
+ <i class="fa-solid fa-rotate-left reset_btn" onclick="reset_settings();"></i>
90
+ </div>
91
+ <dl>
92
+ <li>Face detector Modes</li>
93
+ <dd>
94
+ <a>db_mode :</a>
95
+ <select id="db_mode">
96
+ <option value="small">small</option>
97
+ <option value="large">large</option>
98
+ <option value="both">both</option>
99
+ </select>
100
+
101
+ </dd>
102
+ <dd>
103
+ <a>fr_mode :</a>
104
+ <select id="fr_mode">
105
+ <option value="small">small</option>
106
+ <option value="large">large</option>
107
+ <option value="both">both</option>
108
+ </select>
109
+
110
+ </dd>
111
+ <br>
112
+ <li>Face detector</li>
113
+ <dd>
114
+ <a>p_thres :</a>
115
+ <input id="p_thres" type="range" min="0" max="1" step="0.05" oninput="p_thresValue.innerText=this.value">
116
+ <a id="p_thresValue"></a>
117
+ </dd>
118
+ <dd>
119
+ <a>nms_thres :</a>
120
+ <input id="nms_thres" type="range" min="0" max="1" step="0.05" oninput="nms_thresValue.innerText=this.value">
121
+ <a id="nms_thresValue"></a>
122
+ </dd>
123
+ <dd>
124
+ <a>small_size :</a>
125
+ <input id="small_size" type="range" min="64" max="2080" step="32" oninput="small_sizeValue.innerText=this.value">
126
+ <a id="small_sizeValue"></a>
127
+ </dd>
128
+ <dd>
129
+ <a>large_size :</a>
130
+ <input id="large_size" type="range" min="64" max="2080" step="32" oninput="large_sizeValue.innerText=this.value">
131
+ <a id="large_sizeValue"></a>
132
+ </dd>
133
+ <br>
134
+ <li>Face Recognizer</li>
135
+ <dd>
136
+ <a>d_thres :</a>
137
+ <input id="d_thres" type="range" min="0" max="1" step="0.05" oninput="d_thresValue.innerText=this.value">
138
+ <a id="d_thresValue"></a>
139
+ </dd>
140
+ <br>
141
+ <li>Aligner</li>
142
+ <dd>
143
+ <a>a_thres :</a>
144
+ <input id="a_thres" type="range" min="0" max="1" step="0.05" oninput="a_thresValue.innerText=this.value">
145
+ <a id="a_thresValue"></a>
146
+ </dd>
147
+
148
+
149
+ </dl>
150
+ </div>
151
+ <div id="save_btn_container"><button id="save_settings_btn" onclick="update_settings();">Save</button></div>
152
+
153
+ </div>
154
+ <script src="{{ url_for('static',filename='user/dashboard.js') }}"></script>
155
+ {% endif %}
156
+
157
+ {% endblock %}
app/templates/user/login.html ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+ {% block title %}Login{% endblock %}
3
+ {% block css %}
4
+ <link type="text/css" rel="stylesheet" href="{{ url_for('static',filename='user/login.css') }}">
5
+ <!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css"> -->
6
+ {% endblock %}
7
+ {% block body %}
8
+ <form id="container" action="/user/authenticate/" method="post">
9
+ <h1>Log-In</h1>
10
+ <p class="{{message_class}}">{{message}}</p>
11
+ <div>
12
+ <p>Enter Username:</p>
13
+ <input type="username" name="username" required>
14
+ </div>
15
+ <div>
16
+ <p>Enter password:</p>
17
+ <input type="password" name="password" required>
18
+ </div>
19
+ <input type="submit">
20
+ <!-- <button>Sign-in</button> -->
21
+
22
+ </form>
23
+ <script src="{{ url_for('static',filename='user/login.js') }}"></script>
24
+
25
+ {% endblock %}
app/templates/user/registeration.html ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+ {% block title %}Sign Up{% endblock %}
3
+ {% block css %}
4
+ <link type="text/css" rel="stylesheet" href="{{ url_for('static',filename='user/registeration.css') }}">
5
+ <!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css"> -->
6
+ {% endblock %}
7
+ {% block body %}
8
+ <form id="container" method="post" action="/user/add_account/" onsubmit="return validate_form(this)">
9
+ <h1>Sign-Up</h1>
10
+ <p>message</p>
11
+ <div>
12
+ <p>Enter Username:</p>
13
+ <input type="username" name="username" required onblur="check_username(this);">
14
+ </div>
15
+ <div>
16
+ <p>Enter password:</p>
17
+ <input type="password" name="password" id="password" required>
18
+ </div>
19
+ <div>
20
+ <p>Confirm password:</p>
21
+ <input type="password" name="confirm_password" required onkeyup="check_password_is_matching(this);">
22
+ </div>
23
+ <div>
24
+ <!-- <p>What will you use this api for:</p> -->
25
+ <textarea placeholder="What will you use this api for, Write atleast 2-3 lines" rows=10 cols="60" name="request_message" id="request_message" required></textarea>
26
+ <!-- <input type="text"> -->
27
+ </div>
28
+ <input type="submit" >
29
+ <!-- <button>Sign-in</button> -->
30
+
31
+ </form>
32
+ <script src="{{ url_for('static',filename='user/registeration.js') }}"></script>
33
+
34
+ {% endblock %}
app/user/__init__.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ from flask import Blueprint
2
+ from datetime import timedelta
3
+
4
+ bp=Blueprint("user",__name__)
5
+ session_expiring_time=timedelta(minutes=45)
6
+ settings=dict()
7
+
8
+ from app.user import routes