baagas0 commited on
Commit
16ddda1
·
1 Parent(s): 50f5aeb
.gitignore ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app specific files
2
+ peter*.jpg
3
+ # received_files/
4
+
5
+ # Byte-compiled / optimized / DLL files
6
+ __pycache__/
7
+ *.py[cod]
8
+ *$py.class
9
+
10
+ # C extensions
11
+ *.so
12
+
13
+ # Distribution / packaging
14
+ .Python
15
+ build/
16
+ develop-eggs/
17
+ dist/
18
+ downloads/
19
+ eggs/
20
+ .eggs/
21
+ lib/
22
+ lib64/
23
+ parts/
24
+ sdist/
25
+ var/
26
+ wheels/
27
+ *.egg-info/
28
+ .installed.cfg
29
+ *.egg
30
+ MANIFEST
31
+
32
+ # PyInstaller
33
+ # Usually these files are written by a python script from a template
34
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
35
+ *.manifest
36
+ *.spec
37
+
38
+ # Installer logs
39
+ pip-log.txt
40
+ pip-delete-this-directory.txt
41
+
42
+ # Unit test / coverage reports
43
+ htmlcov/
44
+ .tox/
45
+ .coverage
46
+ .coverage.*
47
+ .cache
48
+ nosetests.xml
49
+ coverage.xml
50
+ *.cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+
63
+ # Flask stuff:
64
+ instance/
65
+ .webassets-cache
66
+
67
+ # Scrapy stuff:
68
+ .scrapy
69
+
70
+ # Sphinx documentation
71
+ docs/_build/
72
+
73
+ # PyBuilder
74
+ target/
75
+
76
+ # Jupyter Notebook
77
+ .ipynb_checkpoints
78
+
79
+ # pyenv
80
+ .python-version
81
+
82
+ # celery beat schedule file
83
+ celerybeat-schedule
84
+
85
+ # SageMath parsed files
86
+ *.sage.py
87
+
88
+ # Environments
89
+ .env
90
+ .venv
91
+ env/
92
+ venv/
93
+ ENV/
94
+ env.bak/
95
+ venv.bak/
96
+
97
+ # Spyder project settings
98
+ .spyderproject
99
+ .spyproject
100
+
101
+ # Rope project settings
102
+ .ropeproject
103
+
104
+ # mkdocs documentation
105
+ /site
106
+
107
+ # mypy
108
+ .mypy_cache/
Dockerfile ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
2
+ # you will also find guides on how best to write your Dockerfile
3
+
4
+ FROM python:3.9
5
+
6
+ WORKDIR /code
7
+
8
+ COPY ./requirements.txt /code/requirements.txt
9
+
10
+ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
11
+
12
+ COPY . .
13
+
14
+ CMD ["uvicorn", "-b", "0.0.0.0:7860", "flask_server:app"]
Info.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Peter2.jpg file size: 89KB
2
+ Post form data content length: 91162
3
+ Post base64 data content length: 121396
4
+ (121396 - 91162) / 91162 = 33%
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Peter Jiping Xie
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
Medium/face_makeup.png ADDED
Medium/face_makeup_m.png ADDED
Medium/face_rec_HTML.jpg ADDED
Medium/face_rec_resp_web.jpg ADDED
Medium/face_rec_response.jpg ADDED
Medium/form_example.jpg ADDED
app.py ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, redirect, jsonify
2
+ from werkzeug.utils import secure_filename
3
+ import os
4
+ import json
5
+ from face_util import compare_faces, face_rec, find_facial_features, find_face_locations
6
+ import re
7
+ import base64
8
+
9
+ app = Flask(__name__)
10
+
11
+ UPLOAD_FOLDER = 'received_files'
12
+ ALLOWED_EXTENSIONS = ['png', 'jpg', 'jpeg']
13
+
14
+ def allowed_file(filename):
15
+ return '.' in filename and \
16
+ filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
17
+
18
+ def print_request(request):
19
+ # Print request url
20
+ print(request.url)
21
+ # print relative headers
22
+ print('content-type: "%s"' % request.headers.get('content-type'))
23
+ print('content-length: %s' % request.headers.get('content-length'))
24
+ # print body content
25
+ if request.is_json:
26
+ json_data = request.get_json(cache=True)
27
+ # replace image_data with '<image base64 data>'
28
+ if json_data.get('image_data', None) is not None:
29
+ json_data['image_data'] = '<image base64 data>'
30
+ else:
31
+ print('request image_data is None.')
32
+ print(json.dumps(json_data,indent=4))
33
+ else: # form data
34
+ body_data=request.get_data()
35
+ # replace image raw data with string '<image raw data>'
36
+ body_sub_image_data=re.sub(b'(\r\n\r\n)(.*?)(\r\n--)',br'\1<image raw data>\3', body_data,flags=re.DOTALL)
37
+ print(body_sub_image_data.decode('utf-8'))
38
+ # print(body_data[0:500] + b'...' + body_data[-500:]) # raw binary
39
+
40
+ @app.route('/face_rec', methods=['POST', 'GET'])
41
+ def face_recognition():
42
+ if request.method == 'POST':
43
+ # Print request url, headers and content
44
+ print_request(request)
45
+
46
+ # JSON data format
47
+ if request.is_json:
48
+ """ Sample data
49
+ {'file_format':'jpg', 'image_data': <base64 ascii string>}
50
+ """
51
+ # print('Request is a JSON format.')
52
+ json_data = request.get_json(cache=False)
53
+ file_format = json_data.get('file_format', None)
54
+ image_data = json_data.get('image_data', None)
55
+ if file_format not in ALLOWED_EXTENSIONS or image_data is None:
56
+ return '{"error":"Invalid JSON."}'
57
+
58
+ file = os.path.join(UPLOAD_FOLDER, 'image.' + file_format)
59
+ with open(file,'wb') as f:
60
+ # Note: Convert ascii string to binary string first, e.g. 'abc' to b'abc', before decode as base64 string.
61
+ f.write(base64.b64decode(image_data.encode('ascii')))
62
+
63
+ # form data format
64
+ else:
65
+ # check if the post request has the file part
66
+ if 'file' not in request.files:
67
+ print('No file part')
68
+ return redirect(request.url)
69
+ file = request.files.get('file')
70
+ # if user does not select file, browser also submit an empty part without filename
71
+ if file.filename == '':
72
+ print('No selected file')
73
+ return redirect(request.url)
74
+
75
+ if not allowed_file(file.filename):
76
+ return '{"error":"Invalid image file format."}'
77
+
78
+ # Process image file
79
+ # Note file could be a filename or a file object.
80
+ name = face_rec(file)
81
+ resp_data = {'name': name }
82
+
83
+ # get parameters from url if any.
84
+ # facial_features parameter:
85
+ param_features = request.args.get('facial_features', '')
86
+ if param_features.lower() == 'true':
87
+ facial_features = find_facial_features(file)
88
+ # append facial_features to resp_data
89
+ resp_data.update({'facial_features': facial_features})
90
+
91
+ # face_locations parameter:
92
+ param_locations = request.args.get('face_locations', '')
93
+ if param_locations.lower() == 'true':
94
+ face_locations = find_face_locations(file)
95
+ resp_data.update({'face_locations': face_locations})
96
+
97
+ return json.dumps(resp_data)
98
+
99
+ return '''
100
+ <!doctype html>
101
+ <title>Face Recognition</title>
102
+ <h1>Upload an image</h1>
103
+ <form method=post enctype=multipart/form-data>
104
+ <input type=file name=file>
105
+ <input type=submit value=Upload>
106
+ </form>
107
+ '''
108
+
109
+ @app.route('/face_match', methods=['POST', 'GET'])
110
+ def face_match():
111
+ if request.method == 'POST':
112
+ # check if the post request has the file part
113
+ if ('file1' not in request.files) or ('file2' not in request.files):
114
+ print('No file part')
115
+ return redirect(request.url)
116
+
117
+ file1 = request.files.get('file1')
118
+ file2 = request.files.get('file2')
119
+ # if user does not select file, browser also submit an empty part without filename
120
+ if file1.filename == '' or file2.filename == '':
121
+ print('No selected file')
122
+ return redirect(request.url)
123
+
124
+ if allowed_file(file1.filename) and allowed_file(file2.filename):
125
+ file1.save( os.path.join(UPLOAD_FOLDER, secure_filename(file1.filename)) )
126
+ file2.save( os.path.join(UPLOAD_FOLDER, secure_filename(file2.filename)) )
127
+ ret = compare_faces(file1, file2)
128
+ resp_data = {
129
+ "success": ret[0],
130
+ "message": ret[1],
131
+ "data": {
132
+ "match": bool(ret[2] < 0.5),
133
+ "error_procentage": ret[2],
134
+ },
135
+ } # convert ret (numpy._bool) to bool for json.dumps
136
+ return jsonify(resp_data)
137
+
138
+ # Return a demo page for GET request
139
+ return '''
140
+ <!doctype html>
141
+ <title>Face Match</title>
142
+ <h1>Upload two images</h1>
143
+ <form method=post enctype=multipart/form-data>
144
+ <input type=file name=file1>
145
+ <input type=file name=file2>
146
+ <input type=submit value=Upload>
147
+ </form>
148
+ '''
149
+
150
+ @app.route('/')
151
+ def hello_world():
152
+ return 'Hello, World!'
153
+
154
+ # Run in HTTP
155
+ # When debug = True, code is reloaded on the fly while saved
156
+ app.run(host='0.0.0.0', port='7860', debug=True)
demo_client.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
+ import base64
4
+ # import ipdb
5
+
6
+ def test_face_match():
7
+ url = 'http://127.0.0.1:5001/face_match'
8
+ # open file in binary mode
9
+ files = {'file1': open('sample_images/obama.jpg', 'rb'),
10
+ 'file2': open('sample_images/obama2.jpg', 'rb')}
11
+ resp = requests.post(url, files=files)
12
+ print( 'face_match response:\n', json.dumps(resp.json()) )
13
+
14
+ def test_face_rec():
15
+ url = 'http://127.0.0.1:5001/face_rec'
16
+ # open file in binary mode
17
+ files = {'file': open('sample_images/obama2.jpg', 'rb')}
18
+ params = {'facial_features': 'true', 'face_locations':'true'}
19
+ resp = requests.post(url, files = files, params = params)
20
+ print( 'face_rec response:\n', json.dumps(resp.json()) )
21
+
22
+ def test_face_rec_json():
23
+ url = 'http://127.0.0.1:5001/face_rec'
24
+ # encode image as base64 text string.
25
+ # Note: Must convert output bytes string from b64encode to an ascii string to form a JSON, e.g. b'abc' to 'abc'.
26
+ with open('sample_images/obama2.jpg', 'rb') as f:
27
+ image_data = base64.b64encode(f.read()).decode('ascii')
28
+
29
+ data = {'file_format':'jpg', 'image_data': image_data}
30
+ params = {'facial_features': 'true', 'face_locations':'true'}
31
+ resp = requests.post(url, json = data, params = params)
32
+ print( 'face_rec response:\n', json.dumps(resp.json()) )
33
+
34
+ def main():
35
+ test_face_match()
36
+ test_face_rec()
37
+ test_face_rec_json()
38
+
39
+ if __name__ == '__main__':
40
+ main()
face_makeup.png ADDED
face_util.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import face_recognition as fr
2
+ import logging
3
+ import logging.config
4
+
5
+ def compare_faces(file1, file2):
6
+ """
7
+ Compare two images and return True / False for matching.
8
+ """
9
+ # Load the jpg files into numpy arrays
10
+ image1 = fr.load_image_file(file1)
11
+ image2 = fr.load_image_file(file2)
12
+
13
+ # Get the face encodings for each face in each image file
14
+ # Assume there is only 1 face in each image, so get 1st face of an image.
15
+ encoding1 = fr.face_encodings(image1)
16
+ encoding2 = fr.face_encodings(image2)
17
+
18
+ # print(len(encoding1))
19
+ # print(len(encoding2))
20
+
21
+ # Defind response format
22
+ # [0] = status success or error
23
+ # [1] = message
24
+ # [2] = data error procentage
25
+
26
+ res = [bool(1), '', 100]
27
+
28
+ # RESPONSE
29
+
30
+ # asd
31
+ if len(encoding1) > 0:
32
+ image1_encoding = encoding1[0]
33
+ else:
34
+ res[0] = bool(0)
35
+ res[1] = 'Wajah tidak ditemukan. (E001)'
36
+ return res
37
+
38
+ if len(encoding2) > 0:
39
+ image2_encoding = encoding2[0]
40
+ else:
41
+ res[0] = bool(0)
42
+ res[1] = 'Wajah tidak ditemukan. (E002)'
43
+ return res
44
+
45
+ # results is an array of True/False telling if the unknown face matched anyone in the known_faces array
46
+ results = fr.face_distance([image1_encoding], image2_encoding)
47
+ # print(results[0])
48
+ # for i, face_distance in enumerate(results):
49
+ # print("The test image has a distance of {:.2} from known image #{}".format(face_distance, i))
50
+ # print("- With a normal cutoff of 0.6, would the test image match the known image? {}".format(face_distance < 0.6))
51
+ # print("- With a very strict cutoff of 0.5, would the test image match the known image? {}".format(face_distance < 0.5))
52
+ # print()
53
+ res[0] = bool(1)
54
+ res[1] = 'Berhasil mendeteksi wajah'
55
+ res[2] = results[0]
56
+ return res
57
+
58
+ # Each face is tuple of (Name,sample image)
59
+ known_faces = [('Obama','sample_images/obama.jpg'),
60
+ ('Peter','sample_images/peter.jpg'),
61
+ ]
62
+
63
+ def face_rec(file):
64
+ """
65
+ Return name for a known face, otherwise return 'Unknown'.
66
+ """
67
+ for name, known_file in known_faces:
68
+ if compare_faces(known_file,file):
69
+ return name
70
+ return 'Unknown'
71
+
72
+ def find_facial_features(file):
73
+ # Load the jpg file into a numpy array
74
+ image = fr.load_image_file(file)
75
+
76
+ # Find all facial features in all the faces in the image
77
+ face_landmarks_list = fr.face_landmarks(image)
78
+
79
+ # return facial features if there is only 1 face in the image
80
+ if len(face_landmarks_list) != 1:
81
+ return {}
82
+ else:
83
+ return face_landmarks_list[0]
84
+
85
+ def find_face_locations(file):
86
+ # Load the jpg file into a numpy array
87
+ image = fr.load_image_file(file)
88
+
89
+ # Find all face locations for the faces in the image
90
+ face_locations = fr.face_locations(image)
91
+
92
+ # return facial features if there is only 1 face in the image
93
+ if len(face_locations) != 1:
94
+ return []
95
+ else:
96
+ return face_locations[0]
find_facial_features_in_picture_w_api.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image, ImageDraw
2
+ import requests
3
+ import json
4
+
5
+ image_file = 'sample_images/obama.jpg'
6
+
7
+ # call face recognition REST API
8
+ url = 'http://127.0.0.1:5001/face_rec'
9
+ files = {'file': open(image_file, 'rb')}
10
+ params = {'facial_features': 'true', 'face_locations':'true'}
11
+ resp = requests.post(url, files = files, params = params)
12
+
13
+ # get facial features
14
+ resp_dict = resp.json() # convert to dict
15
+ facial_features = resp_dict['facial_features']
16
+ face_locations = resp_dict['face_locations']
17
+
18
+ pil_image = Image.open(image_file)
19
+ d = ImageDraw.Draw(pil_image)
20
+
21
+ facial_feature_names = [
22
+ 'chin',
23
+ 'left_eyebrow',
24
+ 'right_eyebrow',
25
+ 'nose_bridge',
26
+ 'nose_tip',
27
+ 'left_eye',
28
+ 'right_eye',
29
+ 'top_lip',
30
+ 'bottom_lip'
31
+ ]
32
+
33
+ def convert_list(list_of_list):
34
+ list_of_tuple = [tuple(i) for i in list_of_list]
35
+ return list_of_tuple
36
+
37
+ # Let's trace out each facial feature in the image with a line!
38
+ for feature_name in facial_feature_names:
39
+ d.line( convert_list(facial_features[feature_name]), width=5)
40
+
41
+ # draw rectangle for face location:
42
+ top, right, bottom, left = face_locations
43
+ d.rectangle([left,top,right,bottom],outline='red')
44
+
45
+ # Display drawed image
46
+ pil_image.show()
47
+ pil_image.save('face_makeup.png')
flask_server.py ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, redirect, jsonify
2
+ from werkzeug.utils import secure_filename
3
+ import os
4
+ import json
5
+ from face_util import compare_faces, face_rec, find_facial_features, find_face_locations
6
+ import re
7
+ import base64
8
+
9
+ app = Flask(__name__)
10
+
11
+ UPLOAD_FOLDER = 'received_files'
12
+ ALLOWED_EXTENSIONS = ['png', 'jpg', 'jpeg']
13
+
14
+ def allowed_file(filename):
15
+ return '.' in filename and \
16
+ filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
17
+
18
+ def print_request(request):
19
+ # Print request url
20
+ print(request.url)
21
+ # print relative headers
22
+ print('content-type: "%s"' % request.headers.get('content-type'))
23
+ print('content-length: %s' % request.headers.get('content-length'))
24
+ # print body content
25
+ if request.is_json:
26
+ json_data = request.get_json(cache=True)
27
+ # replace image_data with '<image base64 data>'
28
+ if json_data.get('image_data', None) is not None:
29
+ json_data['image_data'] = '<image base64 data>'
30
+ else:
31
+ print('request image_data is None.')
32
+ print(json.dumps(json_data,indent=4))
33
+ else: # form data
34
+ body_data=request.get_data()
35
+ # replace image raw data with string '<image raw data>'
36
+ body_sub_image_data=re.sub(b'(\r\n\r\n)(.*?)(\r\n--)',br'\1<image raw data>\3', body_data,flags=re.DOTALL)
37
+ print(body_sub_image_data.decode('utf-8'))
38
+ # print(body_data[0:500] + b'...' + body_data[-500:]) # raw binary
39
+
40
+ @app.route('/face_rec', methods=['POST', 'GET'])
41
+ def face_recognition():
42
+ if request.method == 'POST':
43
+ # Print request url, headers and content
44
+ print_request(request)
45
+
46
+ # JSON data format
47
+ if request.is_json:
48
+ """ Sample data
49
+ {'file_format':'jpg', 'image_data': <base64 ascii string>}
50
+ """
51
+ # print('Request is a JSON format.')
52
+ json_data = request.get_json(cache=False)
53
+ file_format = json_data.get('file_format', None)
54
+ image_data = json_data.get('image_data', None)
55
+ if file_format not in ALLOWED_EXTENSIONS or image_data is None:
56
+ return '{"error":"Invalid JSON."}'
57
+
58
+ file = os.path.join(UPLOAD_FOLDER, 'image.' + file_format)
59
+ with open(file,'wb') as f:
60
+ # Note: Convert ascii string to binary string first, e.g. 'abc' to b'abc', before decode as base64 string.
61
+ f.write(base64.b64decode(image_data.encode('ascii')))
62
+
63
+ # form data format
64
+ else:
65
+ # check if the post request has the file part
66
+ if 'file' not in request.files:
67
+ print('No file part')
68
+ return redirect(request.url)
69
+ file = request.files.get('file')
70
+ # if user does not select file, browser also submit an empty part without filename
71
+ if file.filename == '':
72
+ print('No selected file')
73
+ return redirect(request.url)
74
+
75
+ if not allowed_file(file.filename):
76
+ return '{"error":"Invalid image file format."}'
77
+
78
+ # Process image file
79
+ # Note file could be a filename or a file object.
80
+ name = face_rec(file)
81
+ resp_data = {'name': name }
82
+
83
+ # get parameters from url if any.
84
+ # facial_features parameter:
85
+ param_features = request.args.get('facial_features', '')
86
+ if param_features.lower() == 'true':
87
+ facial_features = find_facial_features(file)
88
+ # append facial_features to resp_data
89
+ resp_data.update({'facial_features': facial_features})
90
+
91
+ # face_locations parameter:
92
+ param_locations = request.args.get('face_locations', '')
93
+ if param_locations.lower() == 'true':
94
+ face_locations = find_face_locations(file)
95
+ resp_data.update({'face_locations': face_locations})
96
+
97
+ return json.dumps(resp_data)
98
+
99
+ return '''
100
+ <!doctype html>
101
+ <title>Face Recognition</title>
102
+ <h1>Upload an image</h1>
103
+ <form method=post enctype=multipart/form-data>
104
+ <input type=file name=file>
105
+ <input type=submit value=Upload>
106
+ </form>
107
+ '''
108
+
109
+ @app.route('/face_match', methods=['POST', 'GET'])
110
+ def face_match():
111
+ if request.method == 'POST':
112
+ # check if the post request has the file part
113
+ if ('file1' not in request.files) or ('file2' not in request.files):
114
+ print('No file part')
115
+ return redirect(request.url)
116
+
117
+ file1 = request.files.get('file1')
118
+ file2 = request.files.get('file2')
119
+ # if user does not select file, browser also submit an empty part without filename
120
+ if file1.filename == '' or file2.filename == '':
121
+ print('No selected file')
122
+ return redirect(request.url)
123
+
124
+ if allowed_file(file1.filename) and allowed_file(file2.filename):
125
+ file1.save( os.path.join(UPLOAD_FOLDER, secure_filename(file1.filename)) )
126
+ file2.save( os.path.join(UPLOAD_FOLDER, secure_filename(file2.filename)) )
127
+ ret = compare_faces(file1, file2)
128
+ resp_data = {
129
+ "success": ret[0],
130
+ "message": ret[1],
131
+ "data": {
132
+ "match": bool(ret[2] < 0.5),
133
+ "error_procentage": ret[2],
134
+ },
135
+ } # convert ret (numpy._bool) to bool for json.dumps
136
+ return jsonify(resp_data)
137
+
138
+ # Return a demo page for GET request
139
+ return '''
140
+ <!doctype html>
141
+ <title>Face Match</title>
142
+ <h1>Upload two images</h1>
143
+ <form method=post enctype=multipart/form-data>
144
+ <input type=file name=file1>
145
+ <input type=file name=file2>
146
+ <input type=submit value=Upload>
147
+ </form>
148
+ '''
149
+
150
+ @app.route('/')
151
+ def hello_world():
152
+ return 'Hello, World!'
153
+
154
+ # Run in HTTP
155
+ # When debug = True, code is reloaded on the fly while saved
156
+ app.run(host='0.0.0.0', port='80', debug=True)
gists/demo_client_part1.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
+
4
+ def test_face_match():
5
+ url = 'http://127.0.0.1:5001/face_match'
6
+ # open file in binary mode
7
+ files = {'file1': open('sample_images/peter.jpg', 'rb'),
8
+ 'file2': open('sample_images/peter2.jpg', 'rb')}
9
+ resp = requests.post(url, files=files)
10
+ print( 'face_match response:\n', json.dumps(resp.json()) )
11
+
12
+ if __name__ == '__main__':
13
+ test_face_match()
gists/demo_client_part2.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
+
4
+ def test_face_rec():
5
+ url = 'http://127.0.0.1:5001/face_rec'
6
+ # open file in binary mode
7
+ files = {'file': open('sample_images/peter2.jpg', 'rb')}
8
+ params = {'facial_features': 'true', 'face_locations':'true'}
9
+ resp = requests.post(url, files = files, params = params)
10
+ print( 'face_rec response:\n', json.dumps(resp.json()) )
11
+
12
+ if __name__ == '__main__':
13
+ test_face_rec()
gists/demo_client_part2_v1.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
+
4
+ def test_face_rec():
5
+ url = 'http://127.0.0.1:5001/face_rec'
6
+ # open file in binary mode
7
+ files = {'file': open('sample_images/peter2.jpg', 'rb')}
8
+ resp = requests.post(url, files = files)
9
+ print( 'face_rec response:\n', json.dumps(resp.json()) )
10
+
11
+ if __name__ == '__main__':
12
+ test_face_rec()
gists/demo_client_v1.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
+
4
+ def test_face_match():
5
+ url = 'http://127.0.0.1:5001/face_match'
6
+ # open file in binary mode
7
+ files = {'file1': open('sample_images/peter.jpg', 'rb'),
8
+ 'file2': open('sample_images/peter2.jpg', 'rb')}
9
+ resp = requests.post(url, files=files)
10
+ print( 'face_match response:\n', json.dumps(resp.json()) )
11
+
12
+ def test_face_rec():
13
+ url = 'http://127.0.0.1:5001/face_rec'
14
+ # open file in binary mode
15
+ files = {'file': open('sample_images/peter2.jpg', 'rb')}
16
+ params = {'facial_features': 'true', 'face_locations':'true'}
17
+ resp = requests.post(url, files = files, params = params)
18
+ print( 'face_rec response:\n', json.dumps(resp.json()) )
19
+
20
+ if __name__ == '__main__':
21
+ test_face_match()
22
+ # test_face_rec()
gists/demo_client_v3.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
+ import base64
4
+
5
+ def test_face_match():
6
+ url = 'http://127.0.0.1:5001/face_match'
7
+ # open file in binary mode
8
+ files = {'file1': open('sample_images/obama.jpg', 'rb'),
9
+ 'file2': open('sample_images/obama2.jpg', 'rb')}
10
+ resp = requests.post(url, files=files)
11
+ print( 'face_match response:\n', json.dumps(resp.json()) )
12
+
13
+ def test_face_rec():
14
+ url = 'http://127.0.0.1:5001/face_rec'
15
+ # open file in binary mode
16
+ files = {'file': open('sample_images/obama2.jpg', 'rb')}
17
+ params = {'facial_features': 'true', 'face_locations':'true'}
18
+ resp = requests.post(url, files = files, params = params)
19
+ print( 'face_rec response:\n', json.dumps(resp.json()) )
20
+
21
+ def test_face_rec_json():
22
+ url = 'http://127.0.0.1:5001/face_rec'
23
+ # encode image as base64 text string.
24
+ # Note: Must convert output bytes string from b64encode to an ascii string to form a JSON, e.g. b'abc' to 'abc'.
25
+ with open('sample_images/obama2.jpg', 'rb') as f:
26
+ image_data = base64.b64encode(f.read()).decode('ascii')
27
+
28
+ data = {'file_format':'jpg', 'image_data': image_data}
29
+ params = {'facial_features': 'true', 'face_locations':'true'}
30
+ resp = requests.post(url, json = data, params = params)
31
+ print( 'face_rec response:\n', json.dumps(resp.json()) )
32
+
33
+ def main():
34
+ test_face_match()
35
+ test_face_rec()
36
+ test_face_rec_json()
37
+
38
+ if __name__ == '__main__':
39
+ main()
gists/face_util_part1.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import face_recognition as fr
2
+
3
+ def compare_faces(file1, file2):
4
+ # Load the jpg files into numpy arrays
5
+ image1 = fr.load_image_file(file1)
6
+ image2 = fr.load_image_file(file2)
7
+
8
+ # Get the face encodings for 1st face in each image file
9
+ image1_encoding = fr.face_encodings(image1)[0]
10
+ image2_encoding = fr.face_encodings(image2)[0]
11
+
12
+ # Compare faces and return True / False
13
+ results = fr.compare_faces([image1_encoding], image2_encoding)
14
+ return results[0]
gists/face_util_part2.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import face_recognition as fr
2
+
3
+ # Each face is tuple of (Name,sample image)
4
+ known_faces = [('Obama','sample_images/obama.jpg'),
5
+ ('Peter','sample_images/peter.jpg'),
6
+ ]
7
+
8
+ def face_rec(file):
9
+ """
10
+ Return name for a known face, otherwise return 'Uknown'.
11
+ """
12
+ for name, known_file in known_faces:
13
+ if compare_faces(known_file,file):
14
+ return name
15
+ return 'Unknown'
gists/face_util_part3.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import face_recognition as fr
2
+
3
+ def find_face_locations(file):
4
+ # Load the jpg file into a numpy array
5
+ image = fr.load_image_file(file)
6
+
7
+ # Find all face locations for the faces in the image
8
+ face_locations = fr.face_locations(image)
9
+
10
+ # return facial features if there is only 1 face in the image
11
+ if len(face_locations) != 1:
12
+ return []
13
+ else:
14
+ return face_locations[0]
gists/face_util_part4.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import face_recognition as fr
2
+
3
+ def find_facial_features(file):
4
+ # Load the jpg file into a numpy array
5
+ image = fr.load_image_file(file)
6
+
7
+ # Find all facial features in all the faces in the image
8
+ face_landmarks_list = fr.face_landmarks(image)
9
+
10
+ # return facial features if there is only 1 face in the image
11
+ if len(face_landmarks_list) != 1:
12
+ return {}
13
+ else:
14
+ return face_landmarks_list[0]
gists/flask_server_v1.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request
2
+ import os
3
+ import json
4
+ from face_util import compare_faces, face_rec
5
+
6
+ app = Flask(__name__)
7
+
8
+ @app.route('/face_match', methods=['POST'])
9
+ def face_match():
10
+ if request.method == 'POST':
11
+ # check if the post request has the file part
12
+ if ('file1' in request.files) and ('file2' in request.files):
13
+ file1 = request.files.get('file1')
14
+ file2 = request.files.get('file2')
15
+ ret = compare_faces(file1, file2)
16
+ resp_data = {"match": bool(ret)} # convert numpy._bool to bool for json.dumps
17
+ return json.dumps(resp_data)
18
+
19
+ @app.route('/face_rec', methods=['POST'])
20
+ def face_recognition():
21
+ if request.method == 'POST':
22
+ # check if the post request has the file part
23
+ if 'file' in request.files:
24
+ file = request.files.get('file')
25
+ name = face_rec(file)
26
+ resp_data = {'name': name }
27
+ return json.dumps(resp_data)
28
+
29
+ # When debug = True, code is reloaded on the fly while saved
30
+ app.run(host='0.0.0.0', port='5001', debug=True)
gists/flask_server_v1_part1.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request
2
+ import json
3
+ from face_util import compare_faces, face_rec
4
+
5
+ app = Flask(__name__)
6
+
7
+ @app.route('/face_match', methods=['POST'])
8
+ def face_match():
9
+ if request.method == 'POST':
10
+ # check if the post request has the file part
11
+ if ('file1' in request.files) and ('file2' in request.files):
12
+ file1 = request.files.get('file1')
13
+ file2 = request.files.get('file2')
14
+ ret = compare_faces(file1, file2)
15
+ resp_data = {"match": bool(ret)} # convert numpy._bool to bool for json.dumps
16
+ return json.dumps(resp_data)
17
+
18
+ # When debug = True, code is reloaded on the fly while saved
19
+ app.run(host='0.0.0.0', port='5001', debug=True)
gists/flask_server_v1_part2.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ @app.route('/face_rec', methods=['POST'])
2
+ def face_recognition():
3
+ if request.method == 'POST':
4
+ # check if the post request has the file part
5
+ if 'file' in request.files:
6
+ file = request.files.get('file')
7
+ name = face_rec(file)
8
+ resp_data = {'name': name }
9
+ return json.dumps(resp_data)
gists/flask_server_v2.py ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request
2
+ import re, json
3
+ from face_util import compare_faces, face_rec
4
+
5
+ app = Flask(__name__)
6
+
7
+ @app.route('/face_match', methods=['POST'])
8
+ def face_match():
9
+ if request.method == 'POST':
10
+ # check if the post request has the file part
11
+ if ('file1' in request.files) and ('file2' in request.files):
12
+ file1 = request.files.get('file1')
13
+ file2 = request.files.get('file2')
14
+ ret = compare_faces(file1, file2)
15
+ resp_data = {"match": bool(ret)} # convert numpy._bool to bool for json.dumps
16
+ return json.dumps(resp_data)
17
+
18
+ def print_request(request):
19
+ # Print request url
20
+ print(request.url)
21
+ # print relative headers
22
+ print('content-type: "%s"' % request.headers.get('content-type'))
23
+ print('content-length: %s' % request.headers.get('content-length'))
24
+ # print body content
25
+ body_bytes = request.get_data()
26
+ # replace image raw data with string '<image raw data>'
27
+ body_sub = re.sub(b'(\r\n\r\n)(.*?)(\r\n--)',br'\1<image raw data>\3', body_bytes,flags=re.DOTALL)
28
+ print(body_sub.decode('utf-8'))
29
+
30
+ @app.route('/face_rec', methods=['POST', 'GET'])
31
+ def face_recognition():
32
+ if request.method == 'POST':
33
+ print_request(request)
34
+ # check if the post request has the file part
35
+ if 'file' in request.files:
36
+ file = request.files.get('file')
37
+ name = face_rec(file)
38
+ resp_data = {'name': name }
39
+ return json.dumps(resp_data)
40
+
41
+ return '''
42
+ <!doctype html>
43
+ <title>Face Recognition</title>
44
+ <h1>Upload an image</h1>
45
+ <form method=post enctype=multipart/form-data>
46
+ <input type=file name=file>
47
+ <input type=submit value=Upload>
48
+ </form>
49
+ '''
50
+
51
+ app.run(host='0.0.0.0', port='5001', debug=True)
gists/flask_server_v2_part1.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request
2
+ import re, json
3
+ from face_util import compare_faces, face_rec
4
+
5
+ app = Flask(__name__)
6
+
7
+ def print_request(request):
8
+ # Print request url
9
+ print(request.url)
10
+ # print relative headers
11
+ print('content-type: "%s"' % request.headers.get('content-type'))
12
+ print('content-length: %s' % request.headers.get('content-length'))
13
+ # print body content
14
+ body_bytes = request.get_data()
15
+ # replace image raw data with string '<image raw data>'
16
+ body_sub = re.sub(b'(\r\n\r\n)(.*?)(\r\n--)',br'\1<image raw data>\3', body_bytes,flags=re.DOTALL)
17
+ print(body_sub.decode('utf-8'))
gists/flask_server_v2_part2.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @app.route('/face_rec', methods=['POST', 'GET'])
2
+ def face_recognition():
3
+ if request.method == 'POST':
4
+ print_request(request)
5
+ # check if the post request has the file part
6
+ if 'file' in request.files:
7
+ file = request.files.get('file')
8
+ name = face_rec(file)
9
+ resp_data = {'name': name }
10
+ return json.dumps(resp_data)
11
+
12
+ return '''
13
+ <!doctype html>
14
+ <title>Face Recognition</title>
15
+ <h1>Upload an image</h1>
16
+ <form method=post enctype=multipart/form-data>
17
+ <input type=file name=file>
18
+ <input type=submit value=Upload>
19
+ </form>
20
+ '''
21
+
22
+ app.run(host='0.0.0.0', port='5001', debug=True)
gists/flask_server_v3.py ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, redirect
2
+ from werkzeug.utils import secure_filename
3
+ import os
4
+ import json
5
+ from face_util import compare_faces, face_rec, find_facial_features, find_face_locations
6
+ import re
7
+ import base64
8
+
9
+ app = Flask(__name__)
10
+
11
+ UPLOAD_FOLDER = 'received_files'
12
+ ALLOWED_EXTENSIONS = ['png', 'jpg', 'jpeg']
13
+
14
+ def allowed_file(filename):
15
+ return '.' in filename and \
16
+ filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
17
+
18
+ def print_request(request):
19
+ # Print request url
20
+ print(request.url)
21
+ # print relative headers
22
+ print('content-type: "%s"' % request.headers.get('content-type'))
23
+ print('content-length: %s' % request.headers.get('content-length'))
24
+ # print body content
25
+ if request.is_json:
26
+ json_data = request.get_json(cache=True)
27
+ # replace image_data with '<image base64 data>'
28
+ if json_data.get('image_data', None) is not None:
29
+ json_data['image_data'] = '<image base64 data>'
30
+ else:
31
+ print('request image_data is None.')
32
+ print(json.dumps(json_data,indent=4))
33
+ else: # form data
34
+ body_data=request.get_data()
35
+ # replace image raw data with string '<image raw data>'
36
+ body_sub_image_data=re.sub(b'(\r\n\r\n)(.*?)(\r\n--)',br'\1<image raw data>\3', body_data,flags=re.DOTALL)
37
+ print(body_sub_image_data.decode('utf-8'))
38
+ # print(body_data[0:500] + b'...' + body_data[-500:]) # raw binary
39
+
40
+ @app.route('/face_rec', methods=['POST', 'GET'])
41
+ def face_recognition():
42
+ if request.method == 'POST':
43
+ # Print request url, headers and content
44
+ print_request(request)
45
+
46
+ # JSON data format
47
+ if request.is_json:
48
+ """ Sample data
49
+ {'file_format':'jpg', 'image_data': <base64 ascii string>}
50
+ """
51
+ # print('Request is a JSON format.')
52
+ json_data = request.get_json(cache=False)
53
+ file_format = json_data.get('file_format', None)
54
+ image_data = json_data.get('image_data', None)
55
+ if file_format not in ALLOWED_EXTENSIONS or image_data is None:
56
+ return '{"error":"Invalid JSON."}'
57
+
58
+ file = os.path.join(UPLOAD_FOLDER, 'image.' + file_format)
59
+ with open(file,'wb') as f:
60
+ # Note: Convert ascii string to bytes string first, e.g. 'abc' to b'abc', before decode as base64 string.
61
+ f.write(base64.b64decode(image_data.encode('ascii')))
62
+
63
+ # form data format
64
+ else:
65
+ # check if the post request has the file part
66
+ if 'file' not in request.files:
67
+ print('No file part')
68
+ return redirect(request.url)
69
+ file = request.files.get('file')
70
+ # if user does not select file, browser also submit an empty part without filename
71
+ if file.filename == '':
72
+ print('No selected file')
73
+ return redirect(request.url)
74
+
75
+ if not allowed_file(file.filename):
76
+ return '{"error":"Invalid image file format."}'
77
+
78
+ # Process image file
79
+ # Note file could be a filename or a file object.
80
+ name = face_rec(file)
81
+ resp_data = {'name': name }
82
+
83
+ # get parameters from url if any.
84
+ # facial_features parameter:
85
+ param_features = request.args.get('facial_features', '')
86
+ if param_features.lower() == 'true':
87
+ facial_features = find_facial_features(file)
88
+ # append facial_features to resp_data
89
+ resp_data.update({'facial_features': facial_features})
90
+
91
+ # face_locations parameter:
92
+ param_locations = request.args.get('face_locations', '')
93
+ if param_locations.lower() == 'true':
94
+ face_locations = find_face_locations(file)
95
+ resp_data.update({'face_locations': face_locations})
96
+
97
+ return json.dumps(resp_data)
98
+
99
+ return '''
100
+ <!doctype html>
101
+ <title>Face Recognition</title>
102
+ <h1>Upload an image</h1>
103
+ <form method=post enctype=multipart/form-data>
104
+ <input type=file name=file>
105
+ <input type=submit value=Upload>
106
+ </form>
107
+ '''
108
+
109
+ @app.route('/face_match', methods=['POST', 'GET'])
110
+ def face_match():
111
+ if request.method == 'POST':
112
+ # check if the post request has the file part
113
+ if ('file1' not in request.files) or ('file2' not in request.files):
114
+ print('No file part')
115
+ return redirect(request.url)
116
+
117
+ file1 = request.files.get('file1')
118
+ file2 = request.files.get('file2')
119
+ # if user does not select file, browser also submit an empty part without filename
120
+ if file1.filename == '' or file2.filename == '':
121
+ print('No selected file')
122
+ return redirect(request.url)
123
+
124
+ if allowed_file(file1.filename) and allowed_file(file2.filename):
125
+ #file1.save( os.path.join(UPLOAD_FOLDER, secure_filename(file1.filename)) )
126
+ #file2.save( os.path.join(UPLOAD_FOLDER, secure_filename(file2.filename)) )
127
+ ret = compare_faces(file1, file2)
128
+ resp_data = {"match": bool(ret)} # convert ret (numpy._bool) to bool for json.dumps
129
+ return json.dumps(resp_data)
130
+
131
+ # Return a demo page for GET request
132
+ return '''
133
+ <!doctype html>
134
+ <title>Face Match</title>
135
+ <h1>Upload two images</h1>
136
+ <form method=post enctype=multipart/form-data>
137
+ <input type=file name=file1>
138
+ <input type=file name=file2>
139
+ <input type=submit value=Upload>
140
+ </form>
141
+ '''
142
+
143
+ @app.route('/')
144
+ def hello_world():
145
+ return 'Hello, World!'
146
+
147
+ # Run in HTTP
148
+ # When debug = True, code is reloaded on the fly while saved
149
+ app.run(host='0.0.0.0', port='5001', debug=True)
gists/form-data_example.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ content-type:"multipart/form-data; boundary=--------------------------706175916610648661144841"
2
+ content-length:278
3
+
4
+ ----------------------------706175916610648661144841
5
+ Content-Disposition: form-data; name="firstname"
6
+
7
+ Mickey
8
+ ----------------------------706175916610648661144841
9
+ Content-Disposition: form-data; name="lastname"
10
+
11
+ Mouse
12
+ ----------------------------706175916610648661144841--
gists/form-data_file.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ http://127.0.0.1:5001/face_rec
2
+ content-type: "multipart/form-data; boundary=---------------------------151482349718403643091396029930"
3
+ content-length: 91238
4
+ -----------------------------151482349718403643091396029930
5
+ Content-Disposition: form-data; name="file"; filename="peter2.jpg"
6
+ Content-Type: image/jpeg
7
+
8
+ <image raw data>
9
+ -----------------------------151482349718403643091396029930--
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ cmake
2
+ Werkzeug
3
+ requests
4
+ Flask
5
+ gunicorn
6
+ face_recognition
7
+ Pillow
sample_images/biden.jpg ADDED
sample_images/obama.jpg ADDED
sample_images/obama2.jpg ADDED
sample_images/turnbull.jpg ADDED
sample_outputs.txt ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ face_rec response:
2
+ {"name": "Peter", "face_locations": [206, 526, 527, 205], "facial_features": {"left_eye": [[285, 285], [301, 278], [320, 279], [335, 289], [318, 292], [300, 292]], "nose_bridge": [[376, 277], [377, 304], [377, 328], [378, 354]], "top_lip": [[329, 433], [348, 420], [366, 411], [379, 416], [393, 412], [410, 420], [425, 432], [417, 432], [393, 429], [379, 430], [366, 429], [337, 434]], "left_eyebrow": [[255, 259], [275, 243], [301, 236], [328, 241], [350, 249]], "bottom_lip": [[425, 432], [410, 442], [395, 449], [380, 452], [366, 451], [349, 447], [329, 433], [337, 434], [366, 430], [379, 432], [393, 429], [417, 432]], "nose_tip": [[349, 378], [363, 381], [378, 384], [392, 381], [405, 378]], "right_eyebrow": [[399, 246], [421, 238], [444, 237], [466, 244], [482, 259]], "right_eye": [[411, 290], [428, 280], [446, 281], [458, 289], [446, 295], [429, 294]], "chin": [[228, 301], [229, 338], [237, 377], [246, 414], [261, 445], [282, 475], [311, 498], [344, 515], [381, 518], [415, 512], [441, 493], [462, 468], [477, 440], [488, 408]]}}
3
+
4
+
5
+ http://127.0.0.1:5001/face_rec
6
+ content-type: "multipart/form-data; boundary=---------------------------151482349718403643091396029930"
7
+ content-length: 91238
8
+ -----------------------------151482349718403643091396029930
9
+ Content-Disposition: form-data; name="file"; filename="peter2.jpg"
10
+ Content-Type: image/jpeg
11
+
12
+ <image raw data>
13
+ -----------------------------151482349718403643091396029930--
ssl_keys/gen_ssl_keys.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from werkzeug.serving import make_ssl_devcert
2
+ make_ssl_devcert('key', host='localhost')
ssl_keys/key.crt ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIC+TCCAeECCBojnT0ZPNwAMA0GCSqGSIb3DQEBCwUAMD8xITAfBgNVBAMMGCou
3
+ bG9jYWxob3N0L0NOPWxvY2FsaG9zdDEaMBgGA1UECgwRRHVtbXkgQ2VydGlmaWNh
4
+ dGUwHhcNMTkwMzIyMDY1MjEyWhcNMjAwMzIxMDY1MjEyWjA/MSEwHwYDVQQDDBgq
5
+ LmxvY2FsaG9zdC9DTj1sb2NhbGhvc3QxGjAYBgNVBAoMEUR1bW15IENlcnRpZmlj
6
+ YXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5JD+A+MK51iKFKG8
7
+ T+5rWOYWs3i8Z3L/YqjAe4yxS7vWPRmTKgf5B1YIKM8+wSsyX+2sH6iQQtOR8qmr
8
+ 4FjY94mGH365GPBVLgvExoGJyoVtdha3c5mkiRufhVxIou8Pss3kaKkRBrlevOaE
9
+ b9f65abeZmazxYTYP/mX201/Z/cLNRP5EaIBL+Ixpxsu19uP1Xhua/p6LF86W6AS
10
+ FhThTKR5/XtCKWxB7RIn2pPsipP51iragAsP1GQ3kX96dZZ9ovkc/Vf4hZdFucgS
11
+ 2OucuOJMHG5F80UuNnXlUjVvUTvbcX/0/vCEG2zYvr/qI2km56Qmgei89r7UNc9m
12
+ TD5sgQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQDJFD8LplIAdUAbTAoCuuUt+oyl
13
+ zBExrEotUO7xTUqLYCP73dEVb/63Rzoc7CsfZU+Wk3G5d0gTGstr4FThke4tDpE+
14
+ ODyiYNubYb/R55Q25JzeShKptvMcNQyh9G2MCGnCMO3Y//yO37YrUjttv39L4LCO
15
+ tU8EgOr1DsMnKSNUIS0+HEXaRry7QJv2J4jpXufx+UsScAq9yxniPox6SeeyzEqX
16
+ wJwi/uSUi8dxt++JZQOoQ08VVUQzy2cbZO5zDv5KmmQ2EgdQGdfFYly7wT9UIku6
17
+ QocprekLImbV88dOqTf+76V7n7zx02nw+GiP/F8XcW7McZU3NUmx6/kupyjc
18
+ -----END CERTIFICATE-----
ssl_keys/key.key ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN PRIVATE KEY-----
2
+ MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDkkP4D4wrnWIoU
3
+ obxP7mtY5hazeLxncv9iqMB7jLFLu9Y9GZMqB/kHVggozz7BKzJf7awfqJBC05Hy
4
+ qavgWNj3iYYffrkY8FUuC8TGgYnKhW12FrdzmaSJG5+FXEii7w+yzeRoqREGuV68
5
+ 5oRv1/rlpt5mZrPFhNg/+ZfbTX9n9ws1E/kRogEv4jGnGy7X24/VeG5r+nosXzpb
6
+ oBIWFOFMpHn9e0IpbEHtEifak+yKk/nWKtqACw/UZDeRf3p1ln2i+Rz9V/iFl0W5
7
+ yBLY65y44kwcbkXzRS42deVSNW9RO9txf/T+8IQbbNi+v+ojaSbnpCaB6Lz2vtQ1
8
+ z2ZMPmyBAgMBAAECggEBAM9A8jRQEbkJPdvLdFf+VvR7XqZKmnwreIvbfP4K61FC
9
+ 99bbc+gu5o7SYf+vPLYoFzuI5gSm8njGI5coZyO9LK/40deJLwoAExz3quxc1bcA
10
+ Get0WdDGxr1UgOeKcIrdvxxhOfX1J+0y9UbQt9I6w9St5QhxpB08gmIwTpSaxyZa
11
+ 03d/a/Y/7rzaSFpTbIw+ydc+oyczQ9q9yTFa0WTvQAbsrnLvq4YIjQID9bhzhO7z
12
+ 6yLjXZXJrjoXxmlgSMrTyr9m21df564jnEfqRSL2dMRawScM3iaGPsFpMQGEd6HT
13
+ ihKBKciHsHhnnozdXmPaV7VUZ1GGvjmruCz2EiZAGokCgYEA/Tycey0zWX/GosTu
14
+ lZ1muZrNxuBJHc0/IRDIZd2t8k7UGv09Yc6sICQ/GHgv495u7bOuw9MOnZQaPPB3
15
+ 1fj0vGJJcQIbZwAMcneuYIDimGh9jYP445J4EMXv+kOLkCCy91L7xxgjp2twoJ+l
16
+ PonKFAsDf63Hr0jtqknGr7Dbe18CgYEA5w93je16r96YCI13DVpa01NU22eVFoYL
17
+ V/4wItfXrw/RXVb53JLN53HaUwZefyDicnyGnXA9VN0fIXSNZI/O2gJcjWlkbdON
18
+ arDYTqDf5R8a1zYrfYmhLYA0OvuMJrDEQQxvZZhbJaDHLS+e9bmMWEwxSBcOWYWO
19
+ TCqtmwJjBB8CgYBKIaEpSd0bWRVb9sxlDfPRZ6jPjD67M6dEVbZkY5WVNlBPKkz6
20
+ wdaPfizeS+ixCx9sBEqn1rQTmxRnPHnIMJ3sO9WF+HjvGQuLws9QPsqWlRgUAkss
21
+ y2bMejU7DOThJ0Fct3UvHjjpvMD2tGVaPlniriqzCLtI689vJzO7oMlPfwKBgDdt
22
+ PWedZQXVJrE+hiV83Da/UabEBT5+7y+veQqSrll/OODkIVHpIV14sT+jUn26fLer
23
+ 6XrQ1tWJqZMT62sJGDyxvlPpyT6TNeQ3AdxyuOK0gHLJussFfdV1YJIZj3gkhR95
24
+ hStgzdSL6duMBdy6ItF3jYbWiQmugQECZ9y8SNZPAoGBAMIG5YmMcnRmJLoW1y9h
25
+ RWtJ0HP1hKZpLeWzkjEoRJe6PmVj+W/zmXWynjyLE47QiFsgm0EGCkGMvbBtWgbY
26
+ yM+fjKIPeYGS/zHgK+4TgN6HHM9HxGL76NSH5yzBP0lpxDpiWdEOmYt7ahwiF1ga
27
+ KUZzUGXJ6p9vr4nIIwz3Bd96
28
+ -----END PRIVATE KEY-----
wsgi.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from app import app
2
+
3
+ if __name__ == "__main__":
4
+ app.run()