Files
photoassistant/face.py

88 lines
5.1 KiB
Python

from main import db, app, ma
from sqlalchemy import Sequence
from sqlalchemy.exc import SQLAlchemyError
# DEL ME SOON
from flask_login import login_required
from flask import render_template
import json
# pylint: disable=no-member
################################################################################
# Class describing Face in the database and DB via sqlalchemy
# - face contains the binary version of numpy array so we dont need to recalc it
# - locn is the pixel coords of the face (top, right, bottom, left)
# - refimg_lnk and facefile_lnk are viewOnly / just for convenience in viewer
# - refimg is a real link to the refimg used for this face (its is only used in
# viewer, and is either set when there is a matched face, or None if no match
################################################################################
class Face(db.Model):
__tablename__ = "face"
id = db.Column(db.Integer, db.Sequence('face_id_seq'), primary_key=True )
face = db.Column( db.LargeBinary )
locn = db.Column( db.String )
w = db.Column( db.Integer )
h = db.Column( db.Integer )
refimg_lnk = db.relationship("FaceRefimgLink", uselist=False, viewonly=True)
facefile_lnk = db.relationship("FaceFileLink", uselist=False, viewonly=True)
refimg =db.relationship("Refimg", secondary="face_refimg_link", uselist=False)
def __repr__(self):
return f"<id: {self.id}, face={self.face}, locn={self.locn}"
################################################################################
# Class describing FaceFileLink in the database and DB via sqlalchemy
# each face comes from a file and used a model to find the face
# this is not perfect, each face in the same file is always foudn with the same
# model - so really should have ModelFileLink or something, in the long run
# this might even be better as ScanDetailsFileLink and ScanDetails
################################################################################
class FaceFileLink(db.Model):
__tablename__ = "face_file_link"
face_id = db.Column(db.Integer, db.ForeignKey("face.id"), primary_key=True )
file_eid = db.Column(db.Integer, db.ForeignKey("file.eid"), primary_key=True )
model_used = db.Column(db.Integer, db.ForeignKey("ai_model.id"), primary_key=True )
def __repr__(self):
return f"<face_id: {self.face_id}, file_eid={self.file_eid}, model_used: {self.model_used}"
################################################################################
# Class describing FaceRefimgLink in the database and DB via sqlalchemy
# connects / implies a face has matched a refimg and we keep the distance too
# distance is mainly for debugging for now and shown in viewer
################################################################################
class FaceRefimgLink(db.Model):
__tablename__ = "face_refimg_link"
face_id = db.Column(db.Integer, db.ForeignKey("face.id"), primary_key=True )
refimg_id = db.Column(db.Integer, db.ForeignKey("refimg.id"), primary_key=True )
face_distance = db.Column(db.Integer)
def __repr__(self):
return f"<face_id: {self.face_id}, refimg_id={self.refimg_id}, face_distance: {self.face_distance}"
### DDP: todo next, make these into sqlachemy classes, THEN person.py add the override in ORM, THEN draw override in blue/not green in DrawImg
### THEN find_person needs to call appropriate override func (OR pass in type?) and get it to be smarter - that sounds okay actually
# create table FACE_OVERRIDE_TYPE ( ID integer, NAME varchar unique, constraint PK_FACE_OVERRIDE_TYPE_ID primary key(ID) );
#create sequence FACE_OVERRIDE_TYPE_ID_SEQ;
#create sequence FACE_OVERRIDE_ID_SEQ;
#create table FACE_OVERRIDE_TYPE ( ID integer, NAME varchar unique, constraint PK_FACE_OVERRIDE_TYPE_ID primary key(ID) );
#insert into FACE_OVERRIDE_TYPE values ( (select nextval('FACE_OVERRIDE_TYPE_ID_SEQ')), 'Not a face' );
#insert into FACE_OVERRIDE_TYPE values ( (select nextval('FACE_OVERRIDE_TYPE_ID_SEQ')), 'Too young' );
#insert into FACE_OVERRIDE_TYPE values ( (select nextval('FACE_OVERRIDE_TYPE_ID_SEQ')), 'Ignore face' );
#insert into FACE_OVERRIDE_TYPE values ( (select nextval('FACE_OVERRIDE_TYPE_ID_SEQ')), 'Manual match' );
#
#-- keep non-redundant FACE because, when we rebuild data we may have a null FACE_ID, but still want to connect to this override
#-- from a previous AI pass... (would happen if we delete a file and then reimport/scan it), OR, more likely we change (say) a threshold, etc.
#-- any reordering of faces, generates new face_ids... (but if the face data was the same, then this override should stand)
#create table FACE_NO_MATCH_OVERRIDE ( ID integer, FACE_ID integer, TYPE integer, FACE bytea,
# constraint FK_FNMO_FACE_ID foreign key (FACE_ID) references FACE(ID),
# constraint FK_FNMO_TYPE foreign key (TYPE) references FACE_OVERRIDE_TYPE(ID),
# constraint PK_FNMO_ID primary key(ID) );
#
#-- manual match goes to person not refimg, so on search, etc. we deal with this anomaly (via sql not ORM)
#create table FACE_MANUAL_OVERRIDE ( ID integer, FACE_ID integer, PERSON_ID integer, TYPE integer, constraint PK_FACE_MANUAL_OVERRIDE_ID primary key(ID) );