303 lines
9.3 KiB
Python
303 lines
9.3 KiB
Python
import sys
|
|
import os
|
|
import cv2
|
|
import json
|
|
import base64
|
|
import time
|
|
import numpy as np
|
|
from copy import copy, deepcopy
|
|
|
|
from matplotlib import pyplot as plt
|
|
|
|
class FaceClass(object):
|
|
|
|
backend = None
|
|
model = None
|
|
imgs = {}
|
|
encs = {}
|
|
crops = {}
|
|
visual = 0
|
|
files = {}
|
|
boxes = []
|
|
jsonx = ""
|
|
errstr = ""
|
|
vidcap = None
|
|
tree = { "device1":"NA", "device2":"NA", "threshold":380, "device1_qual":0.5, "device2_qual":0.5, "score":0, "detectms":0, "comparems":0 }
|
|
|
|
|
|
|
|
def json2obj(self,jsonx):
|
|
print(jsonx)
|
|
self.jsonx = jsonx
|
|
return json.loads(jsonx)
|
|
|
|
|
|
|
|
# # # # #####
|
|
# ## # # #
|
|
# # # # # #
|
|
# # # # # #
|
|
# # ## # #
|
|
# # # # #
|
|
|
|
|
|
# Prep tasks
|
|
def init(self, backend=None, mod=None):
|
|
self.backend = backend
|
|
self.model = mod
|
|
return None
|
|
|
|
def clear(self):
|
|
self.imgs = {}
|
|
self.files = {}
|
|
self.faces = {}
|
|
|
|
|
|
# #### ## #####
|
|
# # # # # # #
|
|
# # # # # # #
|
|
# # # ###### # #
|
|
# # # # # # #
|
|
###### #### # # #####
|
|
|
|
# @doc Load a pic using the device label
|
|
def load1(self, name,fname):
|
|
print(" Loading image '%s' from file %s" % (name, fname))
|
|
if not os.path.isfile(fname):
|
|
print(" * file not found: %s" % (fname))
|
|
return '{ "status":442565, "remark":"file name not found", "guilty_param":"fname", "guilty_value":"%s" }' % (fname)
|
|
self.files[name] = fname
|
|
self.imgs[name] = cv2.imread(fname)
|
|
print(" Loaded %s from file %s" % (name, fname))
|
|
return '{ "status":0, "remark":"OK", "name":"%s", "fname":"%s" }' % (name,fname)
|
|
|
|
|
|
def load2(self, name1,fname1,name2,fname2):
|
|
print("FaceClass loading files ....................... ")
|
|
self.load1(name1,fname1)
|
|
self.load1(name2,fname2)
|
|
return '{ "status":0, "remark":"OK", "name1":"%s", "fname1":"%s", "name2":"%s", "fname2":"%s" }' % (name1,fname1,name2,fname2)
|
|
|
|
|
|
##### ###### ##### ###### #### #####
|
|
# # # # # # # #
|
|
# # ##### # ##### # #
|
|
# # # # # # #
|
|
# # # # # # # #
|
|
##### ###### # ###### #### #
|
|
|
|
|
|
# Find all faces - put resul in self.boxes - an array of rectangles where faces are
|
|
def detect(self,name):
|
|
self.faces = []
|
|
return '{ "status":88241, "remark":"override this!" }'
|
|
|
|
|
|
|
|
|
|
# @doc find the biggest face in the named image
|
|
# Imge has origin at top left and value are b = [ X1, Y1, X2, Y2 ]
|
|
def ideal(self, name, rectname, cropname):
|
|
found = -1
|
|
biggest = -1
|
|
self.crops[name] = []
|
|
print("** faceclass::ideal ... %s with %d boxes => %s + %s" % (name, len(self.boxes), rectname, cropname ))
|
|
# resize boxes
|
|
for i in range(len(self.boxes)):
|
|
b = self.boxes[i]
|
|
area = (b[2]-b[0]) * (b[3]-b[1])
|
|
print(b,area)
|
|
if area > biggest:
|
|
found = i
|
|
biggest = area
|
|
if found < 0:
|
|
return '{ "status":8572421, "remark":"no ideal face", "guilty_param":"name", "guilty_value":"%s" }' % name
|
|
b = self.boxes[found]
|
|
# extract crops and highlights - colours are BGR
|
|
self.imgs[cropname] = self.crop(name,b[0],b[1],b[2],b[3])
|
|
self.crops[name].append(self.imgs[cropname])
|
|
self.imgs[rectname] = deepcopy(self.imgs[name])
|
|
#print(self.imgs[name])
|
|
#print(self.imgs[rectname])
|
|
for bs in self.boxes:
|
|
self.rect(rectname,bs[0],bs[1],bs[2],bs[3],(255,0,0))
|
|
self.rect(rectname,b[0],b[1],b[2],b[3],(0,255,0))
|
|
return '{ "status":0, "remark":"OK", "faces":%d, "ideal_ix":%s, "ideal_area":%d, "boxes":%s }' % (len(self.boxes), found, biggest, json.dumps(self.boxes))
|
|
|
|
# Find landmarks
|
|
def landmarks(self):
|
|
return '{ "status":88243, "remark":"override this!" }'
|
|
|
|
# Find metadata (age etc)
|
|
def metadata(self,name):
|
|
return '{ "status":88244, "remark":"override this!" }'
|
|
|
|
|
|
#### #### # # ##### ## ##### ######
|
|
# # # # ## ## # # # # # # #
|
|
# # # # ## # # # # # # # #####
|
|
# # # # # ##### ###### ##### #
|
|
# # # # # # # # # # # #
|
|
#### #### # # # # # # # ######
|
|
|
|
|
|
# Match two faces
|
|
def compare(self,name1,name2):
|
|
return '{ "status":88245, "remark":"override this!" }'
|
|
|
|
|
|
# @doc This does everything for you.
|
|
# If you are smartserv, "crowd" means cam and "govid" means regula pic
|
|
def crowd_vs_govid(self, name1,file1,scale1, name2,file2,scale2):
|
|
print("##1##")
|
|
if self.json2obj(self.load1(name1, file1))["status"] != 0:
|
|
return self.jsonx
|
|
if scale1 !=0:
|
|
self.shrink(name1,scale1)
|
|
if self.json2obj(self.detect(name1))["status"] != 0:
|
|
return self.jsonx
|
|
self.boxscale(name1,0.3)
|
|
|
|
if self.json2obj(self.ideal(name1,name1+"_rect",name1+"_crop"))["status"] != 0:
|
|
return self.jsonx
|
|
self.save(name1,"/tmp")
|
|
self.save(name1+"_rect","/tmp")
|
|
self.save(name1+"_crop","/tmp")
|
|
print(self.imgs.keys())
|
|
|
|
print("##2##")
|
|
if self.json2obj(self.load1(name2, file2))["status"] != 0:
|
|
return self.jsonx
|
|
if scale2 !=0:
|
|
self.shrink(name2,scale2)
|
|
self.save(name2,"/tmp")
|
|
if self.json2obj(self.detect(name2))["status"]!=0:
|
|
return self.jsonx
|
|
self.boxscale(name2,0.3)
|
|
if self.json2obj(self.ideal(name2,name2+"_rect",name2+"_crop"))["status"] != 0:
|
|
return self.jsonx
|
|
self.save(name2,"/tmp")
|
|
self.save(name2+"_rect","/tmp")
|
|
self.save(name2+"_crop","/tmp")
|
|
print(self.imgs.keys())
|
|
|
|
print("##R##")
|
|
jsonstr = self.compare(name1+"_crop",name2+"_crop")
|
|
print(jsonstr)
|
|
return jsonstr
|
|
|
|
|
|
# @doc This does deomgraphic examination on a pic.
|
|
# If you are smartserv, "crowd" means cam and "govid" means regula pic
|
|
def traffic(self, name, file, scale=0):
|
|
print("##1##")
|
|
jsons = []
|
|
if self.json2obj(self.load1(name, file))["status"] != 0:
|
|
return self.jsonx
|
|
if scale !=0:
|
|
self.shrink(name,scale)
|
|
if self.json2obj(self.detect(name))["status"] != 0:
|
|
return self.jsonx
|
|
for i in range(len(self.boxes)):
|
|
b = self.boxes[i]
|
|
print(">>>>" , b)
|
|
analysis = self.metadata(self.imgs[name][b[0]:b[0]+b[1],b[2]:b[2]+b[3]])
|
|
jsons.append(analysis)
|
|
print(json.dumps(jsons))
|
|
return jsonx
|
|
|
|
|
|
|
|
|
|
###### ##### # #####
|
|
# # # # #
|
|
##### # # # #
|
|
# # # # #
|
|
# # # # #
|
|
###### ##### # #
|
|
|
|
|
|
# use this when the face isolation boxes arent big enough
|
|
def boxscale(self,name,skale=0.2):
|
|
i = 0
|
|
for b in self.boxes:
|
|
self.boxes[i] = self.rebox(b[0],b[1],b[2],b[3],self.imgs[name].shape, skale)
|
|
i += 1
|
|
|
|
def rebox(self,x1,y1,x2,y2,shape,scale=0.2):
|
|
print("!!!!!!1 rebox with shape ",shape)
|
|
xx1 = x1 - int((x2-x1)*scale*0.8)
|
|
xx2 = x2 + int((x2-x1)*scale*0.8)
|
|
yy1 = y1 - int((y2-y1)*scale*1.3)
|
|
yy2 = y2 + int((y2-y1)*scale*1.3)
|
|
if xx1 < 0:
|
|
xx1 = 0
|
|
if yy1 < 0:
|
|
yy1 = 0
|
|
if xx2 > shape[1]:
|
|
xx2 = shape[1]
|
|
if yy2 > shape[0]:
|
|
yy2 = shape[0]
|
|
return (xx1,yy1,xx2,yy2)
|
|
|
|
# @doc draw a box on an image
|
|
def rect(self, name, x1, y1, x2, y2, color):
|
|
print ("recting ",x1,y1,x2,y2)
|
|
cv2.rectangle(self.imgs[name],(x1,y1),(x2,y2), color, 4)
|
|
|
|
# @doc crop an image, allowing a gutter.
|
|
def crop(self, name, x1, y1, x2, y2):
|
|
print ("cropping ",x1,y1,x2,y2)
|
|
return self.imgs[name][y1:y2 , x1:x2]
|
|
|
|
# @doc crop an image, allowing a gutter.
|
|
def shrink(self, name, skale=0.5):
|
|
print ("shrinking ",name)
|
|
self.imgs[name] = cv2.resize(self.imgs[name],None,fx=skale,fy=skale)
|
|
|
|
|
|
|
|
|
|
##### ###### ##### # # ##### # #
|
|
# # # # # # # # ## #
|
|
# # ##### # # # # # # # #
|
|
##### # # # # ##### # # #
|
|
# # # # # # # # # ##
|
|
# # ###### # #### # # # #
|
|
|
|
def scores(self):
|
|
return json.dumps(self.tree)
|
|
|
|
# return a base64 version of the pic in memory
|
|
def dump64(self,which):
|
|
_ , im_arr = cv2.imencode('.png', self.imgs[which])
|
|
img_as_txt = base64.b64encode(im_arr)
|
|
return b'data:image/png;base64, '+img_as_txt
|
|
|
|
def save(self,which,dir,format="png"):
|
|
cv2.imwrite(dir + "/" + which + "." + format, self.imgs[which])
|
|
|
|
def stats(self,which):
|
|
print(which + " stats....")
|
|
print(type(self.imgs[which]))
|
|
print(np.shape(self.imgs[which]))
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
d = FaceClass()
|
|
|
|
d.load1("messi1","testimg/messi1.jpg")
|
|
d.load2("messi2","testimg/messi2.jpg", "messi3","testimg/messi3.jpg")
|
|
|
|
|
|
# look for pics in /tmp
|
|
d.save("messi1", "/tmp")
|
|
d.save("messi2", "/tmp")
|
|
d.save("messi3", "/tmp")
|
|
|
|
|
|
|
|
|