-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfacialrecognition.py
More file actions
286 lines (260 loc) · 12 KB
/
facialrecognition.py
File metadata and controls
286 lines (260 loc) · 12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
def main(csvfile, SubjIDs):
#Type checking for validity
try:
if type(csvfile) != str or type (SubjIDs) != list or len(SubjIDs) != 2:
print("The input data is invalid")
return None
file = open(csvfile)
#Splitting list into two inputs
subj1, subj2 = SubjIDs[0].upper(), SubjIDs[1].upper()
OP1 = [face_symm(csvfile,subj1), face_symm1(csvfile,subj2)]
OP2 = [fac_dist(csvfile,subj1),fac_dist1(csvfile,subj2)]
OP3 = op3function(csvfile)
OP4 = cosine_similarity(fac_dist(csvfile,subj1),fac_dist1(csvfile,subj2))
except Exception as e:
print(e)
return
return OP1, OP2, OP3, OP4
def read_with_ID(csvfile,adultID):
file = open(csvfile)
#This header is used to make sure everything is in order (SubjID, Landmark and both X, Y, Z 's) and to also make sure all 8 columns exist
try:
header = next(file)
first, second, third, fourth, fifth, sixth, seventh, eighth = header[:-1].split(',')
header_list = [first.upper(), second.upper(), third.upper(), fourth.upper(), fifth.upper(), sixth.upper(), seventh.upper(), eighth.strip('\n').upper()]
except:
return None
#Set for no duplicates
corrupted = set()
newlist = {}
for line in file:
row = line.split(',')
#Getting index of each column in header, returning none if at least one column is missing/mispelled
try:
id_ind = header_list.index('SUBJID')
mark_ind = header_list.index('LANDMARK')
ox_ind = header_list.index('OX')
oy_ind = header_list.index('OY')
oz_ind = header_list.index('OZ')
mx_ind = header_list.index('MX')
my_ind = header_list.index('MY')
mz_ind = header_list.index('MZ')
except:
return None
#Checking to see if subject ID is valid
try:
if(row[id_ind] in newlist):
newlist[row[id_ind]][row[mark_ind].upper()] = [float(row[ox_ind]), float(row[oy_ind]), float(row[oz_ind]), float(row[mx_ind]), float(row[my_ind]), float(row[mz_ind])]
else:
newlist[row[id_ind]] = {row[mark_ind].upper(): [float(row[ox_ind]), float(row[oy_ind]), float(row[oz_ind]), float(row[mx_ind]), float(row[my_ind]), float(row[mz_ind])]}
except:
corrupted.add(row[id_ind])
#List comprehension to remove anything invalid from final dictionary
#Try statement to see if all 7 landmarks (Ft, En, Ex, etc) exist. Returning none if at least one value is missing
try:
[newlist.pop(subject)for subject in corrupted]
except:
return None
#Try statement to see if all values in columns exist (returns final dictionary of subjectID), return none otherwise
#[adultID] to get values of adultID
try:
if adultID == 'op4input':
return newlist.keys()
else:
final_dict= newlist[adultID]
for k in final_dict:
for x in final_dict[k]:
if (-200.0 > x) or (x > 200.0):
return None
else:
return final_dict
except:
return None
#Comments are numbered throughout each function for OP1 (OP2 functions are very similar to OP1 functions, so less comments)
#1. Both functions are for OP1, one face each. The ind/test = face.get('landmark') is just to get the values for each landmark
#2. Since after it outputs a list, we put it in a list of lists and loop through it using the index into the facial asymmetry formula
#3. Then it is made into a dictionary by zipping. We then check if PRN is equal to 0.0, remove it from the dictionary if it is otherwise return false
#4. Try statements in both functions. It is to check if anything is invalid, return None for EACH subjectID if so.
def face_symm(csvfile, subj1):
try:
#1.
face1 = read_with_ID(csvfile, subj1)
ind1 = face1.get('FT')
ind2 = face1.get('EX')
ind3 = face1.get('EN')
ind4 = face1.get('AL')
ind5 = face1.get('SBAL')
ind6 = face1.get('CH')
ind7 = face1.get('PRN')
#2.
lst = []
indexxlist = [ind1,ind2,ind3,ind4,ind5,ind6,ind7]
i = 0
while i < len(indexxlist):
addedind = round((((indexxlist[i][3]-indexxlist[i][0]) ** 2) + ((indexxlist[i][4]-indexxlist[i][1]) ** 2) + ((indexxlist[i][5]-indexxlist[i][2]) ** 2) )** (1/2),4)
i += 1
lst.append(addedind)
#3.
lndmrk_dict = ['FT', 'EX', 'EN', 'AL', 'SBAL', 'CH', 'PRN']
dict1=zip(lndmrk_dict,lst)
face1dict = dict(dict1)
if face1dict.get('PRN') == 0.0:
face1dict.pop('PRN')
else:
return None
except:
return None
return face1dict
def face_symm1(csvfile, subj2):
try:
#1.
face2 = read_with_ID(csvfile, subj2)
test11 = face2.get('FT')
test22 = face2.get('EX')
test33 = face2.get('EN')
test44 = face2.get('AL')
test55 = face2.get('SBAL')
test66 = face2.get('CH')
test77 = face2.get('PRN')
#2.
lst1 = []
testlst1 = [test11,test22,test33,test44,test55,test66,test77]
i = 0
while i < len(testlst1):
test = round((((testlst1[i][3]-testlst1[i][0]) ** 2) + ((testlst1[i][4]-testlst1[i][1]) ** 2) + ((testlst1[i][5]-testlst1[i][2]) ** 2) )** (1/2),4)
i += 1
lst1.append(test)
#3.
lndmrk_dict1 = ['FT', 'EX', 'EN', 'AL', 'SBAL', 'CH', 'PRN']
dict2=zip(lndmrk_dict1,lst1)
face2dict = dict(dict2)
if face2dict.get('PRN') == 0.0:
face2dict.pop('PRN')
else:
return None
except:
return None
return face2dict
#These are functions for OP2
#Very similar process to OP1 functions above, just different inputs for the formula
def fac_dist(csvfile, subj1):
try:
face1 = read_with_ID(csvfile, subj1)
ftindex = face1.get('FT')
exindex = face1.get('EX')
enindex = face1.get('EN')
alindex = face1.get('AL')
sbalindex = face1.get('SBAL')
chindex = face1.get('CH')
exen1 = round((((exindex[0]-enindex[0]) ** 2) + ((exindex[1]-enindex[1]) ** 2) + ((exindex[2]-enindex[2]) ** 2) )** (1/2),4)
enal1 = round((((enindex[0]-alindex[0]) ** 2) + ((enindex[1]-alindex[1]) ** 2) + ((enindex[2]-alindex[2]) ** 2) )** (1/2),4)
alex1 = round((((alindex[0]-exindex[0]) ** 2) + ((alindex[1]-exindex[1]) ** 2) + ((alindex[2]-exindex[2]) ** 2) )** (1/2),4)
ftsbal1 = round((((ftindex[0]-sbalindex[0]) ** 2) + ((ftindex[1]-sbalindex[1]) ** 2) + ((ftindex[2]-sbalindex[2]) ** 2) )** (1/2),4)
sbalch1 = round((((sbalindex[0]-chindex[0]) ** 2) + ((sbalindex[1]-chindex[1]) ** 2) + ((sbalindex[2]-chindex[2]) ** 2) )** (1/2),4)
chft1 = round((((chindex[0]-ftindex[0]) ** 2) + ((chindex[1]-ftindex[1]) ** 2) + ((chindex[2]-ftindex[2]) ** 2) )** (1/2),4)
joined_lndmrk = ['EXEN','ENAL','ALEX','FTSBAL','SBALCH','CHFT']
lndmrk_values = [exen1,enal1,alex1,ftsbal1,sbalch1,chft1]
joinedict=zip(joined_lndmrk, lndmrk_values)
face1op2 = dict(joinedict)
except:
return None
return face1op2
def fac_dist1(csvfile, subj2):
try:
face2= read_with_ID(csvfile, subj2)
ftindex1 = face2.get('FT')
exindex1 = face2.get('EX')
enindex1 = face2.get('EN')
alindex1 = face2.get('AL')
sbalindex11 = face2.get('SBAL')
chindex1 = face2.get('CH')
exen2 = round((((exindex1[0]-enindex1[0]) ** 2) + ((exindex1[1]-enindex1[1]) ** 2) + ((exindex1[2]-enindex1[2]) ** 2) )** (1/2),4)
enal2 = round((((enindex1[0]-alindex1[0]) ** 2) + ((enindex1[1]-alindex1[1]) ** 2) + ((enindex1[2]-alindex1[2]) ** 2) )** (1/2),4)
alex2 = round((((alindex1[0]-exindex1[0]) ** 2) + ((alindex1[1]-exindex1[1]) ** 2) + ((alindex1[2]-exindex1[2]) ** 2) )** (1/2),4)
ftsbal2 = round((((ftindex1[0]-sbalindex11[0]) ** 2) + ((ftindex1[1]-sbalindex11[1]) ** 2) + ((ftindex1[2]-sbalindex11[2]) ** 2) )** (1/2),4)
sbalch2 = round((((sbalindex11[0]-chindex1[0]) ** 2) + ((sbalindex11[1]-chindex1[1]) ** 2) + ((sbalindex11[2]-chindex1[2]) ** 2) )** (1/2),4)
chft2 = round((((chindex1[0]-ftindex1[0]) ** 2) + ((chindex1[1]-ftindex1[1]) ** 2) + ((chindex1[2]-ftindex1[2]) ** 2) )** (1/2),4)
joined_lndmrk1 = ['EXEN','ENAL','ALEX','FTSBAL','SBALCH','CHFT']
lndmrk_values1 = [exen2,enal2,alex2,ftsbal2,sbalch2,chft2]
joinedict1=zip(joined_lndmrk1, lndmrk_values1)
face2op2 = dict(joinedict1)
except:
return None
return face2op2
#These are the functions for OP3
#The function below is just an unrounded version of face_symm
def unrounded(csvfile, subj1):
try:
#1.
faceop3 = read_with_ID(csvfile, subj1)
test1 = faceop3.get('FT')
test2 = faceop3.get('EX')
test3 = faceop3.get('EN')
test4 = faceop3.get('AL')
test5 = faceop3.get('SBAL')
test6 = faceop3.get('CH')
test7 = faceop3.get('PRN')
#2.
lst = []
testlst = [test1,test2,test3,test4,test5,test6,test7]
i = 0
while i < len(testlst):
test = (((testlst[i][3]-testlst[i][0]) ** 2) + ((testlst[i][4]-testlst[i][1]) ** 2) + ((testlst[i][5]-testlst[i][2]) ** 2) )** (1/2)
i += 1
lst.append(test)
#3.
lndmrk_dict = ['FT', 'EX', 'EN', 'AL', 'SBAL', 'CH', 'PRN']
dict1=zip(lndmrk_dict,lst)
faceop3dict = dict(dict1)
if faceop3dict.get('PRN') == 0.0:
faceop3dict.pop('PRN')
else:
return None
except:
return None
return faceop3dict
def op3function(csvfile):
try:
allIDs = read_with_ID(csvfile,'op4input')
allIDlist = list(allIDs)
newarray = [] #new empty array
#looping through the index elements of list
i = 0
while i < len(allIDlist):
eachdict = unrounded(csvfile, allIDlist[i])
i += 1
newarray.append(eachdict)
#Checking for indexes that are None to remove in adultID as well
l=[i for i in range(len(newarray)) if newarray[i] == None]
for z in sorted(l, reverse=True):
del allIDlist[z]
#Here we remove none values from the numbered list so it can loop
noNone = []
for val in newarray:
if val != None:
noNone.append(val)
#List of the total facial asymmetries for each valid subjID
onlynumbers = []
x = 0
while x < len(noNone):
adding = round(sum(noNone[x].values()),4)
x += 1
onlynumbers.append(adding)
#Using lambda to get tuples and first 5 from minimum sorted list
min_list = sorted(zip(allIDlist, onlynumbers), key=lambda t: t[1])[:5]
except:
return None
return min_list
#This is the function for OP4
def cosine_similarity(op2lst1, op2lst2):
try:
#initializing, then we match the landmarks and use the index for the formula
numerator, denom1, denom2 = 0, 0, 0
both_dist = ['EXEN','ENAL','ALEX','FTSBAL','SBALCH','CHFT']
for i in both_dist:
numerator += op2lst1[i] * op2lst2[i]
denom1 += op2lst1[i] * op2lst1[i]
denom2 += op2lst2[i] * op2lst2[i]
except:
return None
return round(numerator / ((denom1 ** 0.5) * (denom2 ** 0.5)),4)