yoloserv/src/faceclass.py

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")