Commented most relevant files for submission

This commit is contained in:
fabrice 2019-06-26 10:45:52 +02:00
parent ffc345aaab
commit 4fa3571a27
3 changed files with 29 additions and 16 deletions

View File

@ -1,9 +1,11 @@
FROM python:3.6 FROM python:3.6
#copy requirements file and install required libraries. CMake is installed seperately because it is needed for face recognition and the way pip installs the requirements file fails as CMake isnt installed in time
COPY ./requirements.txt /app/requirements.txt COPY ./requirements.txt /app/requirements.txt
WORKDIR /app WORKDIR /app
RUN pip install CMake RUN pip install CMake
RUN pip install -r requirements.txt RUN pip install -r requirements.txt
RUN rm requirements.txt RUN rm requirements.txt
#make new user so the container duesnt run using root, then copy the api and start it
RUN useradd -ms /bin/bash admin RUN useradd -ms /bin/bash admin
USER admin USER admin
COPY /app . COPY /app .

View File

@ -11,6 +11,7 @@ import cv2
import numpy as np import numpy as np
import imutils import imutils
app = Flask(__name__) app = Flask(__name__)
#establish connection to minio for this instance of the api
minioClient = Minio('minio:9000', access_key=os.environ['s3-name'], secret_key=os.environ['s3-password'], secure=False) minioClient = Minio('minio:9000', access_key=os.environ['s3-name'], secret_key=os.environ['s3-password'], secure=False)
@app.route('/') @app.route('/')
@ -27,25 +28,29 @@ def access_minio():
def new_user_id(): def new_user_id():
#save demo object to reserve id in minio #save demo object to reserve id in minio
id = None id = None
#five tries to generate unique id
for limited_try in range(0,5): for limited_try in range(0,5):
id = str(uuid.uuid4()) id = str(uuid.uuid4())
if check_id(id) == False: if check_id(id) == False:
break break
demo_object = ['test'] demo_object = ['test']
#dump demo object and save it like its a face encoding to reserve id
with open('/tmp/demo_object.pkl', 'wb') as f: with open('/tmp/demo_object.pkl', 'wb') as f:
pickle.dump(demo_object, f) pickle.dump(demo_object, f)
minioClient.fput_object('users', str(id), '/tmp/demo_object.pkl') minioClient.fput_object('users', str(id), '/tmp/demo_object.pkl')
return jsonify({'id':id}) return jsonify({'id':id})
@app.route('/init_face') @app.route('/init_face')
#call like https://face.sguba.de/init_face?id=123&encoded_string=abc #call like https://face.sguba.de/init_face?id=123&encoded_string=base64encoded_urlsafe_string
def new_face(): def new_face():
id = request.args.get('id', None) id = request.args.get('id', None)
img = request.args.get('encoded_string', None) img = request.args.get('encoded_string', None)
temporary_img_path = '/tmp/'+str(id)+'.jpg' temporary_img_path = '/tmp/'+str(id)+'.jpg'
temporary_pkl_path = '/tmp/'+str(id)+'.pkl' temporary_pkl_path = '/tmp/'+str(id)+'.pkl'
#transcode base64_string to img and generate encoding
save_img(img, temporary_img_path) save_img(img, temporary_img_path)
face_encoding_response = encode_face(temporary_img_path) face_encoding_response = encode_face(temporary_img_path)
#check if encoding was successfull, if yes save encoding in minio
if face_encoding_response['success']==True: if face_encoding_response['success']==True:
with open(temporary_pkl_path, 'wb') as file: with open(temporary_pkl_path, 'wb') as file:
pickle.dump(face_encoding_response['encoding'], file) pickle.dump(face_encoding_response['encoding'], file)
@ -59,8 +64,10 @@ def check_face():
img = request.args.get('encoded_string', None) img = request.args.get('encoded_string', None)
temporary_img_path = '/tmp/'+str(id)+'.jpg' temporary_img_path = '/tmp/'+str(id)+'.jpg'
temporary_pkl_path = '/tmp/'+str(id)+'.pkl' temporary_pkl_path = '/tmp/'+str(id)+'.pkl'
#transcode base64_string to img and generate encoding
save_img(img, temporary_img_path) save_img(img, temporary_img_path)
face_encoding_response = encode_face(temporary_img_path) face_encoding_response = encode_face(temporary_img_path)
#check if encoding was successfull, if yes get initial encoding from minio and compare encodings
if face_encoding_response['success']==True: if face_encoding_response['success']==True:
minioClient.fget_object('users', str(id), temporary_pkl_path) minioClient.fget_object('users', str(id), temporary_pkl_path)
with open(temporary_pkl_path, 'rb') as file: with open(temporary_pkl_path, 'rb') as file:
@ -84,7 +91,9 @@ def check_id(id):
return known return known
def save_img(encoded_data, filename): def save_img(encoded_data, filename):
#length of base64 string is always a multiple of 4, if not its padded with =, here we add padding that might have been lost so there are no errors when decoding the img
encoded_data += "=" * ((4 - len(encoded_data) % 4) % 4) encoded_data += "=" * ((4 - len(encoded_data) % 4) % 4)
#convert string to binary, decode base64, decode image and rotate it 90 degree because android studio rotates the camera, then save image to temp
encoded_data = bytes(encoded_data, encoding='utf-8') encoded_data = bytes(encoded_data, encoding='utf-8')
nparr = np.fromstring(base64.urlsafe_b64decode(encoded_data), np.uint8) nparr = np.fromstring(base64.urlsafe_b64decode(encoded_data), np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_ANYCOLOR) img = cv2.imdecode(nparr, cv2.IMREAD_ANYCOLOR)
@ -92,18 +101,18 @@ def save_img(encoded_data, filename):
return cv2.imwrite(filename, img) return cv2.imwrite(filename, img)
def encode_face(path): def encode_face(path):
#create face encoding from data, and check wether it was succesfull. If it was unsuccesfull the encodings list is empty
success = None success = None
face = face_recognition.load_image_file(path) face = face_recognition.load_image_file(path)
face_encoding = face_recognition.face_encodings(face) face_encoding = face_recognition.face_encodings(face)
if len(face_encoding)==0: if len(face_encoding)==0:
success = False response = {'success':False, 'encoding':None}
response = {'success':success, 'encoding':None}
else: else:
success = True response = {'success':True, 'encoding':face_encoding[0]}
response = {'success':success, 'encoding':face_encoding[0]}
return response return response
def setup(): def setup():
#create minio buckets that are used at startup if they dont exist already
try: try:
minioClient.make_bucket("users") minioClient.make_bucket("users")
except BucketAlreadyOwnedByYou as err: except BucketAlreadyOwnedByYou as err:
@ -113,7 +122,8 @@ def setup():
except ResponseError as err: except ResponseError as err:
raise raise
#check if the script is run primarily and not imported etc.
if __name__ == '__main__': if __name__ == '__main__':
setup() setup()
#start running the api
app.run(host='0.0.0.0') app.run(host='0.0.0.0')

View File

@ -1,5 +1,6 @@
version: "2" version: "2"
#customized for the environment. Requires traefik reverse proxy
networks: networks:
face-recognition: face-recognition:
external: false external: false
@ -18,9 +19,9 @@ services:
image: face-recognition-flask:latest image: face-recognition-flask:latest
container_name: flask container_name: flask
environment: environment:
- s3-adress = minio - s3-adress=minio
- s3-name = face-minio - s3-name=face-minio
- s3-password = testpw1 - s3-password=testpw123
restart: unless-stopped restart: unless-stopped
networks: networks:
- face-recognition - face-recognition
@ -30,7 +31,7 @@ services:
labels: labels:
- traefik.enable=true - traefik.enable=true
- traefik.frontend.rule=Host:face.sguba.de - traefik.frontend.rule=Host:face.sguba.de
- traefik.port=5555 - traefik.port=5000
- traefik.docker.network=proxy - traefik.docker.network=proxy
depends_on: depends_on:
- minio - minio
@ -40,19 +41,19 @@ services:
restart: unless-stopped restart: unless-stopped
container_name: minio container_name: minio
ports: ports:
- "9999:9000" - "9009:9000"
environment: environment:
- MINIO_ACCESS_KEY=face-minio - MINIO_ACCESS_KEY=face-minio
- MINIO_ACCESS_KEY=testpw1 - MINIO_SECRET_KEY=testpw123
networks: networks:
- face-recognition - face-recognition
- proxy - proxy
labels: labels:
- traefik.enable=true - traefik.enable=true
- treafik.frontend.rule=face-minio.sguba.de - traefik.frontend.rule=Host:face-minio.sguba.de
- traefik.port=9999 - traefik.port=9000
- traeffik.docker.network=proxy - traefik.docker.network=proxy
volumes: volumes:
- face_minio_data:/data - face_minio_data:/data
- face_minio_config:/root/.minio - face_minio_config:/root/.minio
command: server /mlflow-minio/storage command: minio server /data