implemented ai in our pa_job_manager, with refimgs, a job, and the whole deal
This commit is contained in:
@@ -11,28 +11,37 @@
|
|||||||
#
|
#
|
||||||
###
|
###
|
||||||
|
|
||||||
|
### SQLALCHEMY IMPORTS ###
|
||||||
|
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
from sqlalchemy import Column, Integer, String, Sequence, Float, ForeignKey, DateTime
|
from sqlalchemy import Column, Integer, String, Sequence, Float, ForeignKey, DateTime, LargeBinary
|
||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import sessionmaker
|
||||||
from sqlalchemy.orm import scoped_session
|
from sqlalchemy.orm import scoped_session
|
||||||
|
|
||||||
|
### SQLALCHEMY IMPORTS ###
|
||||||
|
|
||||||
|
### LOCAL FILE IMPORTS ###
|
||||||
|
|
||||||
from shared import DB_URL, PA_JOB_MANAGER_HOST, PA_JOB_MANAGER_PORT
|
from shared import DB_URL, PA_JOB_MANAGER_HOST, PA_JOB_MANAGER_PORT
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import pytz
|
import pytz
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
import glob
|
import glob
|
||||||
from PIL import Image
|
from PIL import Image, ImageOps
|
||||||
from pymediainfo import MediaInfo
|
from pymediainfo import MediaInfo
|
||||||
import hashlib
|
import hashlib
|
||||||
import exifread
|
#import exifread
|
||||||
import base64
|
import base64
|
||||||
import numpy
|
import numpy
|
||||||
import cv2
|
import cv2
|
||||||
import socket
|
import socket
|
||||||
import threading
|
import threading
|
||||||
|
import io
|
||||||
|
import face_recognition
|
||||||
|
|
||||||
DEBUG=1
|
DEBUG=1
|
||||||
|
|
||||||
@@ -114,6 +123,43 @@ class Settings(Base):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<id: {}, import_path: {}>".format(self.id, self.import_path )
|
return "<id: {}, import_path: {}>".format(self.id, self.import_path )
|
||||||
|
|
||||||
|
class Person_Refimg_Link(Base):
|
||||||
|
__tablename__ = "person_refimg_link"
|
||||||
|
person_id = Column(Integer, ForeignKey('person.id'), unique=True, nullable=False, primary_key=True)
|
||||||
|
refimg_id = Column(Integer, ForeignKey('refimg.id'), unique=True, nullable=False, primary_key=True)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<person_id: {}, refimg_id>".format(self.person_id, self.refimg_id)
|
||||||
|
|
||||||
|
class Person(Base):
|
||||||
|
__tablename__ = "person"
|
||||||
|
id = Column(Integer, Sequence('person_id_seq'), primary_key=True )
|
||||||
|
tag = Column(String(48), unique=False, nullable=False)
|
||||||
|
surname = Column(String(48), unique=False, nullable=False)
|
||||||
|
firstname = Column(String(48), unique=False, nullable=False)
|
||||||
|
refimg = relationship('Refimg', secondary=Person_Refimg_Link.__table__)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<tag: {}, firstname: {}, surname: {}, refimg: {}>".format(self.tag,self.firstname, self.surname, self.refimg)
|
||||||
|
|
||||||
|
class Refimg(Base):
|
||||||
|
__tablename__ = "refimg"
|
||||||
|
id = Column(Integer, Sequence('refimg_id_seq'), primary_key=True )
|
||||||
|
fname = Column(String(256), unique=True, nullable=False)
|
||||||
|
encodings = Column(LargeBinary)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<id: {}, fname: {}, encodings: {}>".format(self.id, self.fname, self.encodings )
|
||||||
|
|
||||||
|
class File_Person_Link(Base):
|
||||||
|
__tablename__ = "file_person_link"
|
||||||
|
file_id = Column(Integer, ForeignKey('file.eid'), unique=True, nullable=False, primary_key=True)
|
||||||
|
person_id = Column(Integer, ForeignKey('person.id'), unique=True, nullable=False, primary_key=True)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<file_id: {}, person_id: {}>".format(self.file_id, self.person_id)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# classes for the job manager:
|
# classes for the job manager:
|
||||||
@@ -199,6 +245,13 @@ def ProcessImportDirs(parent_job=None):
|
|||||||
session.commit()
|
session.commit()
|
||||||
if parent_job:
|
if parent_job:
|
||||||
AddLogForJob(parent_job, "adding <a href='/job/{}'>job id={} {}</a> (wait for: {})".format( job2.id, job2.id, job2.name, job2.wait_for ) )
|
AddLogForJob(parent_job, "adding <a href='/job/{}'>job id={} {}</a> (wait for: {})".format( job2.id, job2.id, job2.name, job2.wait_for ) )
|
||||||
|
jex3=JobExtra( name="path", value=path )
|
||||||
|
job3=Job(start_time='now()', last_update='now()', name="processai", state="New", wait_for=job.id, pa_job_state="New" )
|
||||||
|
job3.extra.append(jex3)
|
||||||
|
session.add(job3)
|
||||||
|
session.commit()
|
||||||
|
if parent_job:
|
||||||
|
AddLogForJob(parent_job, "adding <a href='/job/{}'>job id={} {}</a> (wait for: {})".format( job3.id, job3.id, job3.name, job3.wait_for ) )
|
||||||
HandleJobs()
|
HandleJobs()
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -225,6 +278,8 @@ def RunJob(job):
|
|||||||
JobNewImportDir(job)
|
JobNewImportDir(job)
|
||||||
elif job.name =="getfiledetails":
|
elif job.name =="getfiledetails":
|
||||||
JobGetFileDetails(job)
|
JobGetFileDetails(job)
|
||||||
|
elif job.name == "processai":
|
||||||
|
JobProcessAI(job)
|
||||||
else:
|
else:
|
||||||
print("ERROR: Requested to process unknown job type: {}".format(job.name))
|
print("ERROR: Requested to process unknown job type: {}".format(job.name))
|
||||||
# okay, we finished a job, so check for any jobs that are dependant on this and run them...
|
# okay, we finished a job, so check for any jobs that are dependant on this and run them...
|
||||||
@@ -414,6 +469,16 @@ def JobNewImportDir(job):
|
|||||||
session.commit()
|
session.commit()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def JobProcessAI(job):
|
||||||
|
path=[jex.value for jex in job.extra if jex.name == "path"][0]
|
||||||
|
path='static/photos'
|
||||||
|
print('meeeee',path)
|
||||||
|
for e in FilesInDir( path ):
|
||||||
|
ProcessFilesInDir(job, e, ProcessAI, lambda a: True)
|
||||||
|
FinishJob(job, "Finished Processesing AI")
|
||||||
|
r = session.query(Refimg).get(1)
|
||||||
|
print(r)
|
||||||
|
|
||||||
def JobImportDir(job):
|
def JobImportDir(job):
|
||||||
JobProgressState( job, "In Progress" )
|
JobProgressState( job, "In Progress" )
|
||||||
settings = session.query(Settings).first()
|
settings = session.query(Settings).first()
|
||||||
@@ -527,6 +592,65 @@ def HashAndThumbDirHasNew(dir):
|
|||||||
dir.last_hash_date = time.time()
|
dir.last_hash_date = time.time()
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
def ProcessAI(job, e):
|
||||||
|
print('AING',e)
|
||||||
|
|
||||||
|
if e.type.name != 'Image':
|
||||||
|
return
|
||||||
|
|
||||||
|
people = session.query(Person).all()
|
||||||
|
for person in people:
|
||||||
|
generateKnownEncodings(person)
|
||||||
|
|
||||||
|
file = e.in_dir[0].path_prefix + '/' + e.name
|
||||||
|
im_orig = Image.open(file)
|
||||||
|
im = ImageOps.exif_transpose(im_orig)
|
||||||
|
|
||||||
|
unknown_encodings = generateUnknownEncodings(im)
|
||||||
|
|
||||||
|
for unknown_encoding in unknown_encodings:
|
||||||
|
for person in people:
|
||||||
|
lookForPersonInImage(person, unknown_encoding, e)
|
||||||
|
return
|
||||||
|
|
||||||
|
def lookForPersonInImage(person, unknown_encoding, e):
|
||||||
|
for refimg in person.refimg:
|
||||||
|
deserialized_bytes = numpy.frombuffer(refimg.encodings, dtype=numpy.float64)
|
||||||
|
#deserialized_x = numpy.reshape(deserialized_bytes, newshape=(2,2))
|
||||||
|
|
||||||
|
results = compareAI(deserialized_bytes, unknown_encoding)
|
||||||
|
if results[0]:
|
||||||
|
print(f'Found a match between: {person.tag} and {e.name}')
|
||||||
|
fpl = File_Person_Link(person_id=person.id, file_id=e.file_details[0].eid)
|
||||||
|
session.add(fpl)
|
||||||
|
return
|
||||||
|
|
||||||
|
def generateUnknownEncodings(im):
|
||||||
|
unknown_image = numpy.array(im)
|
||||||
|
face_locations = face_recognition.face_locations(unknown_image)
|
||||||
|
unknown_encodings = face_recognition.face_encodings(unknown_image, known_face_locations=face_locations)
|
||||||
|
# should save these to the db
|
||||||
|
# file.locations = face_locations
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return unknown_encodings
|
||||||
|
|
||||||
|
|
||||||
|
def generateKnownEncodings(person):
|
||||||
|
for refimg in person.refimg:
|
||||||
|
img = face_recognition.load_image_file('reference_images/'+refimg.fname)
|
||||||
|
location = face_recognition.face_locations(img)
|
||||||
|
encodings = face_recognition.face_encodings(img, known_face_locations=location)
|
||||||
|
refimg.encodings = encodings[0].tobytes()
|
||||||
|
session.add(refimg)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
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, go_into_dir_func):
|
def ProcessFilesInDir(job, e, file_func, go_into_dir_func):
|
||||||
if DEBUG==1:
|
if DEBUG==1:
|
||||||
print("DEBUG: files in dir - process: {} {}".format(e.name, e.in_dir[0].path_prefix))
|
print("DEBUG: files in dir - process: {} {}".format(e.name, e.in_dir[0].path_prefix))
|
||||||
@@ -602,18 +726,17 @@ def isImage(file):
|
|||||||
def GenImageThumbnail(job, file):
|
def GenImageThumbnail(job, file):
|
||||||
thumbnail=None
|
thumbnail=None
|
||||||
AddLogForJob( job, "Generate Thumbnail from Image file: {}".format( file ), file )
|
AddLogForJob( job, "Generate Thumbnail from Image file: {}".format( file ), file )
|
||||||
f = open(file, 'rb')
|
|
||||||
try:
|
try:
|
||||||
tags = exifread.process_file(f)
|
im_orig = Image.open(file)
|
||||||
if '20210121_223307.jpg' in file:
|
im = ImageOps.exif_transpose(im_orig)
|
||||||
print("Tag: img orientation={}".format( tags['Image Orientation']) )
|
im.thumbnail((256,256))
|
||||||
print("Tag: GPS GPSLatitude={}".format( tags['GPS GPSLatitude']) )
|
img_bytearray = io.BytesIO()
|
||||||
thumbnail = base64.b64encode(tags['JPEGThumbnail'])
|
im.save(img_bytearray, format='JPEG')
|
||||||
thumbnail = str(thumbnail)[2:-1]
|
img_bytearray = img_bytearray.getvalue()
|
||||||
|
thumbnail = base64.b64encode(img_bytearray)
|
||||||
except:
|
except:
|
||||||
print('WARNING: NO EXIF TAGS?!?!?!?')
|
print('WARNING: NO EXIF TAGS?!?!?!?')
|
||||||
AddLogForJob(job, "WARNING: No EXIF TAF found for: {}".format(file))
|
AddLogForJob(job, "WARNING: No EXIF TAF found for: {}".format(file))
|
||||||
f.close()
|
|
||||||
|
|
||||||
return thumbnail
|
return thumbnail
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user