model_used is now per file, not per face, implemented split of default_model to default_refimg_model and default_scan_model in settings, and default_refimg_model actualy works when creating refimgs in person.py. The model_used in face_file_link is based on default settings model and will scan with cnn if chosen and store that in DB as needed. Need viewer to allow changing per file / not just default for future scans

This commit is contained in:
2021-07-27 17:14:03 +10:00
parent 50e28ed27c
commit b7d346c206
7 changed files with 59 additions and 62 deletions

View File

@@ -190,11 +190,12 @@ class Settings(Base):
import_path = Column(String)
storage_path = Column(String)
recycle_bin_path = Column(String)
default_model = Column(Integer,ForeignKey('ai_model.id'), unique=True, nullable=False)
default_refimg_model = Column(Integer,ForeignKey('ai_model.id'), unique=True, nullable=False)
default_scan_model = Column(Integer,ForeignKey('ai_model.id'), unique=True, nullable=False)
default_threshold = Column(Integer)
def __repr__(self):
return f"<id: {self.id}, import_path: {self.import_path}, recycle_bin_path: {self.recycle_bin_path}, default_model: {self.default_model}, default_threshold: {self.default_threshold}>"
return f"<id: {self.id}, import_path: {self.import_path}, recycle_bin_path: {self.recycle_bin_path}, default_refimg_model: {self.default_refimg_model}, default_scan_model: {self.default_scan_model}, default_threshold: {self.default_threshold}>"
class PersonRefimgLink(Base):
__tablename__ = "person_refimg_link"
@@ -225,6 +226,7 @@ class Refimg(Base):
orig_w = Column(Integer)
orig_h = Column(Integer)
face_locn = Column(String)
model_used = Column(Integer, ForeignKey("ai_model.id") )
def __repr__(self):
return f"<id: {self.id}, fname: {self.fname}, created_on: {self.created_on}>"
@@ -259,7 +261,6 @@ class FaceRefimgLink(Base):
__tablename__ = "face_refimg_link"
face_id = Column(Integer, ForeignKey("face.id"), primary_key=True )
refimg_id = Column(Integer, ForeignKey("refimg.id"), primary_key=True )
model_used = Column(Integer, ForeignKey("ai_model.id") )
face_distance = Column(Integer)
def __repr__(self):
@@ -981,6 +982,10 @@ def JobRunAIOn(job):
else:
job.refimgs=session.query(Refimg).join(PersonRefimgLink).join(Person).filter(Person.tag==which_person).all()
if not job.refimgs:
FinishJob(job, "Failed Processesing AI - the person(s) you chose has no reference images!", "Failed" )
return
# start by working out how many images in this selection we will need face match on
job.num_files = 0
for jex in job.extra:
@@ -1060,25 +1065,6 @@ def GenHashAndThumb(job, e):
e.file_details.last_hash_date = time.time()
return
def lookForPersonInImage(job, person, unknown_encoding, e):
FinishJob( job, "THIS CODE HAS BEEN REMOVED, need to use new Face* tables, and rethink", "Failed" )
return
def generateUnknownEncodings(im):
unknown_image = numpy.array(im)
face_locations = face_recognition.face_locations(unknown_image)
if not face_locations:
return None
unknown_encodings = face_recognition.face_encodings(unknown_image, known_face_locations=face_locations)
return unknown_encodings
def compareAI(known_encoding, unknown_encoding):
results = face_recognition.compare_faces([known_encoding], unknown_encoding, tolerance=0.55)
return results
def ProcessFilesInDir(job, e, file_func, count_dirs):
if DEBUG==1:
print( f"DEBUG: ProcessFilesInDir: {e.FullPathOnFS()}")
@@ -1353,11 +1339,11 @@ def InitialValidationChecks():
FinishJob(job,"Finished Initial Validation Checks")
return
def AddFaceToFile( locn_data, face_data, file_eid ):
def AddFaceToFile( locn_data, face_data, file_eid, model ):
face = Face( face=face_data.tobytes(), locn=json.dumps(locn_data) )
session.add(face)
session.commit()
ffl = FaceFileLink( face_id=face.id, file_eid=file_eid )
ffl = FaceFileLink( face_id=face.id, file_eid=file_eid, model_used=model )
session.add(ffl)
session.commit()
return face
@@ -1367,10 +1353,10 @@ def DelFacesForFile( eid ):
session.commit()
return
def MatchRefimgToFace( refimg_id, face_id, model, face_dist ):
def MatchRefimgToFace( refimg_id, face_id, face_dist ):
# remove any match to this face from previous attempts, and 'replace' with new one
session.query(FaceRefimgLink).filter(FaceRefimgLink.face_id==face_id).delete()
rfl = FaceRefimgLink( refimg_id = refimg_id, face_id = face_id, model_used=model, face_distance=face_dist )
rfl = FaceRefimgLink( refimg_id = refimg_id, face_id = face_id, face_distance=face_dist )
session.add(rfl)
session.commit()
return
@@ -1398,24 +1384,24 @@ def ScanFileForPerson( job, e, force=False ):
DelFacesForFile( e.id )
file_h.faces_created_on = 0
# get default_scan_model from settings (test this)
settings = session.query(Settings).first()
model=settings.default_scan_model
threshold = settings.default_threshold
# optimise: dont rescan if we already have faces
if file_h.faces_created_on == 0:
if DEBUG:
AddLogForJob( job, f"DEBUG: {e.name} is missing unknown faces, generating them" )
im = face_recognition.load_image_file(e.FullPathOnFS())
# TODO: use setting to use model
face_locations = face_recognition.face_locations(im)
model=AIModel.query.get(model)
face_locations = face_recognition.face_locations(im, model=model.name)
unknown_encodings = face_recognition.face_encodings(im, known_face_locations=face_locations)
for locn, face in zip( face_locations, unknown_encodings ):
AddFaceToFile( locn, face, e.id )
AddFaceToFile( locn, face, e.id, model )
file_h.faces_created_on = time.time()
session.commit()
# get default_model from settings (test this)
settings = session.query(Settings).first()
model=settings.default_model
threshold = settings.default_threshold
faces = session.query(Face).join(FaceFileLink).filter(FaceFileLink.file_eid==e.id).all()
# if there are no faces for this file, then dont go any futher
if not faces:
@@ -1437,7 +1423,7 @@ def ScanFileForPerson( job, e, force=False ):
for face in faces:
who, fd = BestFaceMatch(dist, face.id, threshold )
if who != None:
MatchRefimgToFace( who, face.id, model, fd )
MatchRefimgToFace( who, face.id, fd )
AddLogForJob(job, f'WE MATCHED: {name[who]} with file: {e.name} - face distance of {fd}')
del( dist[who] )
return