Deploying a REST API to Serve the Prediction
After quite a long search, I have identified several products that can be used to ease the lift required to deploy a model into production. Since our end application is not clear (though we have several ideas), the best approach to productionizing this model is to deploy it as a REST service that can be maintained separately. To me, the ability to easily deploy REST endpoints enables us to keep developing and iterating the accuracy of the various models over time. UbiOps is a product that offers a hosting service for deep learning services, running on Kubernetes that greatly simplifies the process of creating and maintaining REST services.
- Introduction
- Code
- Conclusions
Introduction
Objective
The simple first use case for the facial profiling technology we developed is the ability to submit a collection of portraits, and recieve back the facial profiles and the labeled input image. The idea is to make it easy for social science researchers to control for the facial profile. For example, in designing experiment subjects cohorts, an experimental economics or psychology researcher may want to pair up subjects who have maximally different facial skin-tones, or facial width to height ratios. This service would enable them to either build that assignment directly into their computerized experiment, or at least remove the manual work needed to obtain those measurements today.
import sys
!{sys.executable} -m pip install ubiops
### Create a service user
import os
import json
from pathlib import Path
with open(Path(os.getenv('HOME'))/'.ubiops/ubiops.json') as f:
data = json.load(f)
import ubiops
from os import environ
import ubiops
configuration = ubiops.Configuration()
configuration.api_key['Authorization'] = data['API_TOKEN']
client = ubiops.ApiClient(configuration)
api = ubiops.api.CoreApi(client)
print(api.service_status())
client.close()
API_TOKEN = data['API_TOKEN']
PROJECT_NAME = 'facial-profile'
DEPLOYMENT_NAME = 'simple-tutorial'
DEPLOYMENT_VERSION = 'v1'
configuration = ubiops.Configuration()
configuration.api_key['Authorization'] = API_TOKEN
client = ubiops.ApiClient(configuration)
api = ubiops.CoreApi(client)
api.service_status()
# deployment_template = ubiops.DeploymentCreate(
# name=DEPLOYMENT_NAME,
# description='A simple deployment that multiplies the input float by a random number.',
# input_type='structured',
# output_type='structured',
# input_fields=[ubiops.DeploymentInputFieldCreate(name='input', data_type='double')],
# output_fields=[ubiops.DeploymentOutputFieldCreate(name='output', data_type='double')]
# )
#
# deployment = api.deployments_create(project_name=PROJECT_NAME, data=deployment_template)
# print(deployment)
# version_template = ubiops.VersionCreate(
# version=DEPLOYMENT_VERSION,
# language='python3.7',
# memory_allocation=256,
# maximum_instances=1,
# minimum_instances=0,
# maximum_idle_time=1800 # = 30 minutes
# )
#
# version = api.versions_create(
# project_name=PROJECT_NAME,
# deployment_name=DEPLOYMENT_NAME,
# data=version_template
# )
# print(version)
%matplotlib inline
from pathlib import Path
# import random
#
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import pandas as pd
import numpy as np
import skimage
from skimage import color
from prcvd.img import (
compute_theta, apply_rgb2lab, calc_euclidean_error, MaskedImg,
LabelMask, FaceMask, MeshMask, TrainedSegmentationModel
)
from prcvd.core import IndexerDict
## shared with training
def get_y_fn(fp):
l_str = str(img_to_l[fp])
out = l_str \
.replace('labels', 'labels_int') \
.replace('png', 'tif')
return out
class FacialProfile:
def __init__(self, img, model, sampling_strategy='use_all', align_face=True):
self.segmask = None
self.eye_slope_threshold = 0.50 #degrees
self.model = model
self.img = img
self.eye_slope = np.nan
self.apply_rotation(angle=0.0)
self.fix_rotation()
self.mesh = MeshMask(img=self.segmask.decoded_img)
self.skin_tones = self.compute_skintones(
sampling_strategy=sampling_strategy
)
self.tot_head_area, self.face_areas = self.create_area_features()
self.bizygomatic_left, self.bizygomatic_right, self.bizygomatic_dist = \
self.compute_bizygomatic_width()
self.upperfacial_top, self.upperfacial_bottom, self.upperfacial_dist = \
self.compute_upperfacial_height()
self.fwhr = self.bizygomatic_dist / self.upperfacial_dist
# self.modeled_img_fp = write_to/'imgs'/(fp.stem+'.jpg') #TODO
def get_profile(self):
"""Returns the face profile object."""
tones = {'rgb_of_{}'.format(k):v for k,v in self.skin_tones.items()}
other = {
'img_rot_degrees': self.img.rotation_degrees,
'img_num_rotations': self.img.num_rotations,
'img_eye_slope': self.eye_slope,
'fwhr': self.fwhr,
'bizygoatic_w_px': self.bizygomatic_dist,
'upperfacial_h_px': self.upperfacial_dist,
'tot_head_area_px': self.tot_head_area
}
out = {**tones, **other}
out = {**out, **self.face_areas}
return out
def apply_rotation(self, angle):
"""Applies a rotation by angle (in degrees) to self.img"""
if angle != 0.0:
self.img.rotate(angle)
self.segmask = FaceMask(img=self.img, model=self.model)
self.create_eye_features()
# TODO: add check to see if the face rotation worked out
self.create_secondary_features()
def fix_rotation(self,):
"""Loops over rotations until the image is corrected."""
while abs(self.theta_degrees) > self.eye_slope_threshold:
self.apply_rotation(angle=self.theta_degrees)
def create_area_features(self):
nots = ['Background/undefined']
total_area = {
lab: np.count_nonzero(self.segmask.mask == code)
for lab, code in self.segmask.label_to_code.items()
if lab not in nots
}
s = sum(total_area.values())
total_area = {'pct_of_head_{}'.format(k): v/s for k,v in total_area.items()}
return s, total_area
def create_eye_features(self):
"""Writes the eye features."""
self.segmask.add_eyes()
self.eye_slope = self.segmask.compute_eye_slope()
if self.eye_slope > 0.0:
self.theta_degrees = \
-1.0*compute_theta(slope1=self.eye_slope, slope2=0.0)
elif self.eye_slope < 0.0:
self.theta_degrees = \
compute_theta(slope2=self.eye_slope, slope1=0.0)
elif self.eye_slope == 0.0:
self.theta_degrees = \
compute_theta(slope2=self.eye_slope, slope1=0.0)
def create_secondary_features(self):
"""Writes the secondary facial features, dependent on reference features."""
self.segmask.add_cheeks()
self.segmask.add_forehead()
def compute_skintones(self, sampling_strategy, thresh=None):
"""Computes skin tones for all regions"""
if thresh:
self.segmask.calc_new_decision(thresh=thresh)
return {
region: self.segmask.calc_region_color(
region=region,
sampling_strategy=sampling_strategy
)
for region in self.segmask.label_to_code.keys()
}
def compute_bizygomatic_width(self):
""""""
# Sources:
# https://carta.anthropogeny.org/moca/topics/upper-facial-height
right_eye_right = self.segmask.find_region_extrema(
region='right_eye',direction='right',
)
right_cheek_right = self.segmask.find_region_extrema(
region='right_cheek',direction='right',
)
bizygomatic_right = (float(right_cheek_right[0]), float(right_eye_right[1]))
left_eye_left = self.segmask.find_region_extrema(
region='left_eye',direction='left',
)
left_cheek_left = self.segmask.find_region_extrema(
region='left_cheek',direction='left',
)
bizygomatic_left = (float(left_cheek_left[0]), float(left_eye_left[1]))
bizygomatic_dist = bizygomatic_right[0] - bizygomatic_left[0]
return bizygomatic_left, bizygomatic_right, bizygomatic_dist
def compute_upperfacial_height(self):
""""""
upperfacial_top = self.segmask.find_region_extrema(
region='Eyebrows',direction='bottom',
)
upperfacial_bottom = self.segmask.find_region_extrema(
region='Lips',direction='top',
)
upperfacial_top = (float(upperfacial_top[0]), float(upperfacial_top[1]))
upperfacial_bottom = (float(upperfacial_bottom[0]), float(upperfacial_bottom[1]))
upperfacial_dist = upperfacial_bottom[1] - upperfacial_top[1]
return upperfacial_top, upperfacial_bottom, upperfacial_dist
def get_skintones_in_lab(self):
"""
Returns skin tones in LAB colors
"""
return {
k: apply_rgb2lab(v)
for k, v in self.skin_tones.items()
}
path = Path("/ws/data/skin-tone/headsegmentation_dataset_ccncsa")
mod_dir = path/'Models'
mod_fp = mod_dir/'checkpoint_20201007'
# TODO: figure out how to get the labels from the trained model...
output_classes = ['Background/undefined', 'Lips', 'Eyes', 'Nose', 'Hair',
'Ears', 'Eyebrows', 'Teeth', 'General face', 'Facial hair',
'Specs/sunglasses']
size = 224
truth_fp = Path('/ws/data/skin-tone/ScreenshotFaceAfterStatement/erics_imgs/MasterFacesDatabaseLabels.xlsx - labels.csv')
truth = pd.read_csv(truth_fp)
truth.index = truth['PostStatementPhotoFilename']
del truth['PostStatementPhotoFilename']
truth['L_m'] = (truth['L_l'] + truth['L_r']) / 2
truth['a_m'] = (truth['a_l'] + truth['a_r']) / 2
truth['b_m'] = (truth['b_l'] + truth['b_r']) / 2
def run_summary(fp, summary, attempt=1, num_attempts=10):
print(fp)
outimg = write_to/'imgs'/(fp.stem+'.jpg')
if outimg.exists():
return None, None
try: del img
except: pass
img = MaskedImg()
img.load_from_file(fn=fp)
try: del model
except: pass
model = TrainedSegmentationModel(
mod_fp=mod_fp,
input_size=size,
output_classes=output_classes
)
try: del profile
except: pass
try:
profile = FacialProfile(
model=model,
img=img,
sampling_strategy='use_all',
align_face=True
)
except:
if not attempt > num_attempts:
return run_summary(
fp=fp,
summary=summary,
attempt=attempt+1,
num_attempts=num_attempts
)
else:
return None, None
plt.figure(figsize=(10,10))
plt.imshow(profile.segmask.decoded_img.img)
plt.imshow(
skimage.color.label2rgb(np.array(profile.segmask.mask)),
alpha=0.3
)
plt.title('Computed fWHR based on Segmentation Only (not FaceMesh).\nfWHR: {}'.format(profile.fwhr))
plt.scatter(x=[profile.bizygomatic_right[0]],
y=[profile.bizygomatic_right[1]],
marker='+', c='orange')
plt.scatter(x=[profile.bizygomatic_left[0]],
y=[profile.bizygomatic_left[1]],
marker='+', c='orange')
plt.plot(
[profile.bizygomatic_right[0], profile.bizygomatic_right[0]],
[0, profile.segmask.mask.shape[1]-1],'ro-')
plt.plot(
[profile.bizygomatic_left[0], profile.bizygomatic_left[0]],
[0, profile.segmask.mask.shape[1]-1],'ro-')
plt.scatter(x=[profile.upperfacial_top[0]],
y=[profile.upperfacial_top[1]],
marker='+', c='red')
plt.plot(
[0, profile.segmask.mask.shape[0]-1],
[profile.upperfacial_top[1], profile.upperfacial_top[1]],
'go-'
)
plt.scatter(x=[profile.upperfacial_bottom[0]],
y=[profile.upperfacial_bottom[1]],
marker='+', c='red')
plt.plot(
[0, profile.segmask.mask.shape[0]-1],
[profile.upperfacial_bottom[1], profile.upperfacial_bottom[1]], 'go-')
plt.savefig(outimg, format='jpeg')
row = profile.get_profile()
row['model_id'] = mod_fp
return row, plt
erics_img = Path('/ws/data/skin-tone/from_zenodo/Media/MediaForExport/')
ls = [fp for fp in list(erics_img.ls()) if str(fp)[-4:] == '.jpg']
# row = truth.loc[fp.name].to_dict()
write_to = Path('/ws/data/skin-tone/output1')
summary = []
fp = ls[1]
outimg = write_to/'imgs'/(fp.stem+'.jpg')
try: del img
except: pass
img = MaskedImg()
img.load_from_file(fn=fp)
try: del model
except: pass
model = TrainedSegmentationModel(
mod_fp=mod_fp,
input_size=size,
output_classes=output_classes
)
try: del profile
except: pass
profile = FacialProfile(
model=model,
img=img,
sampling_strategy='use_all',
align_face=True
)
plt.imshow(profile.img.img)
print(profile.bizygomatic_right)
profile.bizygomatic_left
def plot_all(save=False)
plt.figure(figsize=(10,10))
plt.imshow(profile.segmask.decoded_img.img)
plt.imshow(
skimage.color.label2rgb(np.array(profile.segmask.mask)),
alpha=0.3
)
plt.title('Computed fWHR based on Segmentation Only (not FaceMesh).\nfWHR: {}'.format(profile.fwhr))
plt.scatter(x=[profile.bizygomatic_right[0]],
y=[profile.bizygomatic_right[1]],
marker='+', c='orange')
plt.scatter(x=[profile.bizygomatic_left[0]],
y=[profile.bizygomatic_left[1]],
marker='+', c='orange')
plt.plot(
[profile.bizygomatic_right[0], profile.bizygomatic_right[0]],
[0, profile.segmask.mask.shape[1]-1],'ro-')
plt.plot(
[profile.bizygomatic_left[0], profile.bizygomatic_left[0]],
[0, profile.segmask.mask.shape[1]-1],'ro-')
plt.scatter(x=[profile.upperfacial_top[0]],
y=[profile.upperfacial_top[1]],
marker='+', c='red')
plt.plot(
[0, profile.segmask.mask.shape[0]-1],
[profile.upperfacial_top[1], profile.upperfacial_top[1]],
'go-'
)
plt.scatter(x=[profile.upperfacial_bottom[0]],
y=[profile.upperfacial_bottom[1]],
marker='+', c='red')
plt.plot(
[0, profile.segmask.mask.shape[0]-1],
[profile.upperfacial_bottom[1], profile.upperfacial_bottom[1]], 'go-')
plt.savefig(outimg, format='jpeg')
row = profile.get_profile()
row['model_id'] = mod_fp
##Exceptions
# ZeroDivisionError, RuntimeError
summary = []
failures = []
for fp in ls[:10]:
if str(fp)[-4:] != '.jpg': continue
try:
row, plt = run_summary(fp=fp, summary=summary)
except:
failures.append(fp)
continue
if not row and not plt:
failures.append(fp)
continue
summary.append(row)
failures
profile.get_profile()
plt.figure(figsize = (8,8))
plt.title('Original Image, Rotated and Shrunken to size={}'.format(size))
plt.imshow(profile.segmask.decoded_img.img)
plt.figure(figsize = (8,8))
plt.title('Enhanced Segmentation Model Output')
plt.imshow(profile.segmask.mask)
profile.mesh.draw(thickness=1, circle_radius=1)
plt.figure(figsize=(10,10))
plt.imshow(profile.segmask.decoded_img.img)
plt.imshow(
skimage.color.label2rgb(np.array(profile.segmask.mask)),
alpha=0.3
)
plt.title('Computed fWHR based on Segmentation Only (not FaceMesh).\nfWHR: {}'.format(profile.fwhr))
plt.scatter(x=[profile.bizygomatic_right[0]],
y=[profile.bizygomatic_right[1]],
marker='+', c='orange')
plt.scatter(x=[profile.bizygomatic_left[0]],
y=[profile.bizygomatic_left[1]],
marker='+', c='orange')
plt.plot(
[profile.bizygomatic_right[0], profile.bizygomatic_right[0]],
[0, profile.segmask.mask.shape[1]-1],'ro-')
plt.plot(
[profile.bizygomatic_left[0], profile.bizygomatic_left[0]],
[0, profile.segmask.mask.shape[1]-1],'ro-')
plt.scatter(x=[profile.upperfacial_top[0]],
y=[profile.upperfacial_top[1]],
marker='+', c='red')
plt.plot(
[0, profile.segmask.mask.shape[0]-1],
[profile.upperfacial_top[1], profile.upperfacial_top[1]],
'go-'
)
plt.scatter(x=[profile.upperfacial_bottom[0]],
y=[profile.upperfacial_bottom[1]],
marker='+', c='red')
plt.plot(
[0, profile.segmask.mask.shape[0]-1],
[profile.upperfacial_bottom[1], profile.upperfacial_bottom[1]], 'go-')
plt.figure(figsize=(10,10))
# plt.imshow(profile.segmask.decoded_img.img)
plt.imshow(profile.segmask.decoded_img.img)
plt.imshow(
skimage.color.label2rgb(np.array(profile.segmask.mask)),
alpha=0.3
)
plt.title('fWHR: {}'.format(profile.fwhr))
plt.scatter(x=[profile.bizygomatic_right[0]],
y=[profile.bizygomatic_right[1]],
marker='+', c='orange')
plt.scatter(x=[profile.bizygomatic_left[0]],
y=[profile.bizygomatic_left[1]],
marker='+', c='orange')
plt.plot(
[profile.bizygomatic_right[0], profile.bizygomatic_right[0]],
[0, profile.segmask.mask.shape[1]-1],'ro-')
plt.plot(
[profile.bizygomatic_left[0], profile.bizygomatic_left[0]],
[0, profile.segmask.mask.shape[1]-1],'ro-')
plt.scatter(x=[profile.upperfacial_top[0]],
y=[profile.upperfacial_top[1]],
marker='+', c='red')
plt.plot(
[0, profile.segmask.mask.shape[0]-1],
[profile.upperfacial_top[1], profile.upperfacial_top[1]],
'go-'
)
plt.scatter(x=[profile.upperfacial_bottom[0]],
y=[profile.upperfacial_bottom[1]],
marker='+', c='red')
plt.plot(
[0, profile.segmask.mask.shape[0]-1],
[profile.upperfacial_bottom[1], profile.upperfacial_bottom[1]], 'go-')
(a1,b1) = profile.segmask.find_region_extrema(
region='right_eye', direction='bottom'
)
(a2,b2) = profile.segmask.find_region_extrema(
region='left_eye', direction='bottom'
)
# view region in isolation
plt.figure(figsize = (10,10))
grp = (profile.segmask.mask == 1).nonzero()
plt.gca().invert_yaxis()
plt.scatter(grp[:,1],grp[:,0],)
plt.figure(figsize = (10,10))
plt.imshow(profile.segmask.decoded_img.img)
plt.figure(figsize = (10,10))
plt.imshow(profile.segmask.mask)
# plot centroid eye points
centroid_leye = profile.segmask.find_region_extrema(region='left_eye', direction='centroid')
centroid_reye = profile.segmask.find_region_extrema(region='right_eye', direction='centroid')
slope = (float(centroid_reye[1])-centroid_leye[1])/(centroid_reye[0]-centroid_leye[0])
plt.figure(figsize = (10,10))
plt.imshow(profile.segmask.mask)
plt.scatter(x=[centroid_leye[0]], y=[centroid_leye[1]], marker='+', c='black')
plt.scatter(x=[centroid_reye[0]], y=[centroid_reye[1]], marker='+', c='black')
plt.plot([centroid_leye[0],centroid_reye[0]], [[centroid_leye[1]],[centroid_reye[1]]],'ro-')
flat_pt1 = centroid_leye
flat_pt2 = torch.Tensor([centroid_leye[0], centroid_reye[1]])
plt.scatter(x=[flat_pt2[0]], y=[flat_pt2[1]], marker='+', c='black')
plt.plot([centroid_leye[0],flat_pt2[0]], [[centroid_leye[1]],[flat_pt2[1]]],'bo-')
left_cheek_truth = np.array([row['L_l'], row['a_l'], row['b_l']])
right_cheek_truth = np.array([row['L_r'], row['a_r'], row['b_r']])
left_cheek_truth_rgb = color.lab2rgb(left_cheek_truth.astype(float))
right_cheek_truth_rgb = color.lab2rgb(right_cheek_truth.astype(float))
pred_left_cheek_lab = abs(skimage.color.rgb2lab(profile.skin_tones['left_cheek'],
illuminant='D50', observer='2'
)).astype('int')
pred_right_cheek_lab = abs(skimage.color.rgb2lab(
profile.skin_tones['right_cheek'],
illuminant='D50', observer='2'
)).astype('int')
print('predicted left cheek (LAB)', pred_left_cheek_lab)
print('predicted right cheek (LAB)', pred_right_cheek_lab)
print('true left cheek',left_cheek_truth)
print('true right cheek',right_cheek_truth)
print('left cheek error', calc_euclidean_error(pred_left_cheek_lab, left_cheek_truth))
print('right cheek error',calc_euclidean_error(pred_right_cheek_lab, right_cheek_truth))
plt.figure(figsize = (10,10))
# plt.imshow(img)
region = 'Nose'
fig, ax = plt.subplots()
ax.add_patch(
patches.Rectangle(
(0, 0), 1, 1,
edgecolor = (np.array(profile.skin_tones[region]).astype(float)) / 255,
facecolor = (np.array(profile.skin_tones[region]).astype(float)) / 255,
fill=True
)
)
ax.annotate('predicted - {}'.format(region), (0.5, 0.5), color='w', weight='bold',
fontsize=18, ha='center', va='center')
plt.show()
fig, ax = plt.subplots()
ax.add_patch(
patches.Rectangle(
(0, 0),1,1,
edgecolor = right_cheek_truth_rgb,
facecolor = right_cheek_truth_rgb,
fill=True
)
)
ax.annotate('Right Cheek Truth', (0.5, 0.5), color='w', weight='bold',
fontsize=18, ha='center', va='center')
plt.show()
fig, ax = plt.subplots()
ax.add_patch(
patches.Rectangle(
(0, 0),1,1,
edgecolor = left_cheek_truth_rgb,
facecolor = left_cheek_truth_rgb,
fill=True
)
)
ax.annotate('Left Cheek Truth', (0.5, 0.5), color='w', weight='bold',
fontsize=18, ha='center', va='center')
plt.show()
# plt.imshow(img)
region = 'left_cheek'
fig, ax = plt.subplots()
ax.add_patch(
patches.Rectangle(
(0, 0),1,1,
edgecolor = (np.array(profile.skin_tones[region]).astype(float)) / 255,
facecolor = (np.array(profile.skin_tones[region]).astype(float)) / 255,
fill=True
)
)
ax.annotate('predicted - {}'.format(region), (0.5, 0.5), color='w', weight='bold',
fontsize=18, ha='center', va='center')
plt.show()
fig, ax = plt.subplots()
ax.add_patch(
patches.Rectangle(
(0, 0),1,1,
edgecolor = right_cheek_truth_rgb,
facecolor = right_cheek_truth_rgb,
fill=True
)
)
ax.annotate('Right Cheek Truth', (0.5, 0.5), color='w', weight='bold',
fontsize=18, ha='center', va='center')
plt.show()
fig, ax = plt.subplots()
ax.add_patch(
patches.Rectangle(
(0, 0),1,1,
edgecolor = left_cheek_truth_rgb,
facecolor = left_cheek_truth_rgb,
fill=True
)
)
ax.annotate('Left Cheek Truth', (0.5, 0.5), color='w', weight='bold',
fontsize=18, ha='center', va='center')
plt.show()
region = 'right_cheek'
fig, ax = plt.subplots()
ax.add_patch(
patches.Rectangle(
(0, 0),1,1,
edgecolor = (np.array(profile.skin_tones[region]).astype(float)) / 255,
facecolor = (np.array(profile.skin_tones[region]).astype(float)) / 255,
fill=True
)
)
ax.annotate('predicted - {}'.format(region), (0.5, 0.5), color='w', weight='bold',
fontsize=18, ha='center', va='center')
plt.show()
fig, ax = plt.subplots()
ax.add_patch(
patches.Rectangle(
(0, 0),1,1,
edgecolor = right_cheek_truth_rgb,
facecolor = right_cheek_truth_rgb,
fill=True
)
)
ax.annotate('Right Cheek Truth', (0.5, 0.5), color='w', weight='bold',
fontsize=18, ha='center', va='center')
plt.show()
fig, ax = plt.subplots()
ax.add_patch(
patches.Rectangle(
(0, 0),1,1,
edgecolor = left_cheek_truth_rgb,
facecolor = left_cheek_truth_rgb,
fill=True
)
)
ax.annotate('Left Cheek Truth', (0.5, 0.5), color='w', weight='bold',
fontsize=18, ha='center', va='center')
plt.show()
region = 'forehead'
fig, ax = plt.subplots()
ax.add_patch(
patches.Rectangle(
(0, 0),1,1,
edgecolor = (np.array(profile.skin_tones[region]).astype(float)) / 255,
facecolor = (np.array(profile.skin_tones[region]).astype(float)) / 255,
fill=True
)
)
ax.annotate('predicted - {}'.format(region), (0.5, 0.5), color='w', weight='bold',
fontsize=18, ha='center', va='center')
plt.show()
fig, ax = plt.subplots()
ax.add_patch(
patches.Rectangle(
(0, 0),1,1,
edgecolor = right_cheek_truth_rgb,
facecolor = right_cheek_truth_rgb,
fill=True
)
)
ax.annotate('Right Cheek Truth', (0.5, 0.5), color='w', weight='bold',
fontsize=18, ha='center', va='center')
plt.show()
fig, ax = plt.subplots()
ax.add_patch(
patches.Rectangle(
(0, 0),1,1,
edgecolor = left_cheek_truth_rgb,
facecolor = left_cheek_truth_rgb,
fill=True
)
)
ax.annotate('Left Cheek Truth', (0.5, 0.5), color='w', weight='bold',
fontsize=18, ha='center', va='center')
plt.show()
# hor_lip: Top of lip, parallel to hor_eye
# ver_rear: left side of right ear (subject perspective), orthogonal to hor_eye
# ver_rear: right side of left ear (subject perspective), orthogonal to hor_eye
# requires: right eye vs left eye
# requires facial orientation transform (up side down -> right side up)
# Simplifying Assumptions
import cv2
import imutils
import traceback
for im in ls:
try:
if im in out: continue
if 'jpg' not in str(im): continue
colors = run_img(fn=im, tags=tags)
row = truth.loc[im.name].to_dict()
row['fp'] = im
row['PostStatementPhotoFilename'] = im.name
for tag in tags:
row['Lab_{}'.format(tag)] = colors_profile_lab[tag]
row['error_{}'.format(tag)] = calc_euclidean_error(
colors_profile_lab[tag],
np.array([row['L_m'], row['a_m'], row['b_m']])
)
out[im] = row
except KeyboardInterrupt:
break
except:
traceback.print_exc()
df = pd.DataFrame(out.values())
df[['error_forehead','error_right_cheek','error_left_cheek','error_Nose']].sum()
df.to_csv('early_look_validation.csv')
df