renamed AI_Model to AIModel for consistency, added it as a functioning drop-down select on settings page, added face_distance to db and code, put face_distance model_used into all classes ready for use

This commit is contained in:
2021-07-25 15:13:39 +10:00
parent f6f67b8a69
commit 555ce70577
5 changed files with 42 additions and 17 deletions

37
TODO
View File

@@ -1,26 +1,37 @@
## GENERAL
* face locations:
START FORM SCRATCH so all images have face_locn data
right now GenThumb is in shared, and does width, height as well --> in person.py BUT need this for pa_job_manager
-- show face locns in viewer.html [DONE]
* how hard would bootstrap 5 be, and use form-switch instead of 'badge'
* Face matching:
- upgrade to face distance per face per file
- so we dont get 2 x same face in one file, and if it could match say Cam and Mich for 1 face, take the higher match, not the first one to be over the threshold
- allow for threshold/settings to be tweaked from the GUI?
---> at least settings for default value (back to 0.6 / 0.5?)
---> with override table to do per file / per face?
- face locations:
START FORM SCRATCH so all images have face_locn data
- algo:
for each face (even known) in image
foreach refimg
get face_distance
sort by face_distance
for each face
connect lowest score with that face (for this file)
this means this face is no longer 'free' for a match
if (sorted) face distance > 0.55 stop as no further 'matches'
- use cnn model (check ftst.py) for ref images, and potentially as a setting to check images without a face?
- or always?
-- would CUDA be useful here? (which is faster say an old 730 or the AMD cpu?)
* allow for threshold/settings to be tweaked from the GUI
- it would be good to then say, just run the scanner against this image or maybe this DIR, to see how it IDs ppl
---> settings for default value
---> override table to do per file combos?
* refimg
- remove AI menu from top-level -> make a sub-of Person, and just have Match or AI
* viewer:
can we make it preload next/prev images, and only reload the image div when we jump? to make arrow-based nav much faster
* remove dirs after the duplicate cleanup removes all its content
* fix up logging in general
* could look to remove the hand fixing of json.loads of array data --> seems you can make your own datatype in the ORM, and it can do the conversion every time you use it
- https://stackoverflow.com/questions/28143557/sqlalchemy-convert-column-value-back-and-forth-between-internal-and-database-fo
* fix up logging in general
* comment your code
* more OO goodness :)

View File

@@ -2,7 +2,6 @@ from main import db, app, ma
from sqlalchemy import Sequence
from sqlalchemy.exc import SQLAlchemyError
class Face(db.Model):
__tablename__ = "face"
id = db.Column(db.Integer, db.Sequence('face_id_seq'), primary_key=True )
@@ -17,6 +16,7 @@ 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}"
@@ -25,6 +25,8 @@ 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 )
model_used = db.Column(db.Integer, db.ForeignKey("ai_model.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}"

View File

@@ -227,6 +227,14 @@ class Refimg(Base):
def __repr__(self):
return f"<id: {self.id}, fname: {self.fname}, created_on: {self.created_on}>"
class AIModel(Base):
__tablename__ = "ai_model"
id = Column(Integer, primary_key=True )
name = Column(String)
def __repr__(self):
return f"<id: {self.id}, name: {self.name}>"
class Face(Base):
__tablename__ = "face"
id = Column(Integer, Sequence('face_id_seq'), primary_key=True )
@@ -240,6 +248,7 @@ class FaceFileLink(Base):
__tablename__ = "face_file_link"
face_id = Column(Integer, ForeignKey("face.id"), primary_key=True )
file_eid = Column(Integer, ForeignKey("file.eid"), primary_key=True )
model_used = Column(Integer, ForeignKey("ai_model.id") )
def __repr__(self):
return f"<face_id: {self.face_id}, file_eid={self.file_eid}"
@@ -248,6 +257,8 @@ 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):
return f"<face_id: {self.face_id}, refimg_id={self.refimg_id}"

View File

@@ -12,7 +12,7 @@ from flask_login import login_required, current_user
################################################################################
# Class describing AI_MODEL in the database, and via sqlalchemy, connected to the DB as well
################################################################################
class AI_Model(db.Model):
class AIModel(db.Model):
__tablename__ = "ai_model"
id = db.Column(db.Integer, primary_key=True )
name = db.Column(db.String)
@@ -20,6 +20,7 @@ class AI_Model(db.Model):
def __repr__(self):
return f"<id: {self.id}, name: {self.name}>"
################################################################################
# Class describing Settings in the database, and via sqlalchemy, connected to the DB as well
################################################################################
@@ -53,7 +54,7 @@ class SettingsForm(FlaskForm):
import_path = StringField('Path(s) to import from:', [validators.DataRequired()])
storage_path = StringField('Path to store sorted images to:', [validators.DataRequired()])
recycle_bin_path = StringField('Path to temporarily store deleted images in:', [validators.DataRequired()])
default_model = SelectField( 'default_model', choices=[(c.id, c.name) for c in AI_Model.query.order_by('id')] )
default_model = SelectField( 'default_model', choices=[(c.id, c.name) for c in AIModel.query.order_by('id')] )
default_threshold = StringField('Face Distance threshold (below is a match):', [validators.DataRequired()])
submit = SubmitField('Save' )

View File

@@ -60,7 +60,7 @@ create table FACE_FILE_LINK( FACE_ID integer, FILE_EID integer, MODEL_USED integ
constraint FK_FFL_FILE_EID foreign key (FILE_EID) references FILE(EID),
constraint FK_FFL_MODEL_USED foreign key (MODEL_USED) references AI_MODEL(ID) );
create table FACE_REFIMG_LINK( FACE_ID integer, REFIMG_ID integer, MODEL_USED integer,
create table FACE_REFIMG_LINK( FACE_ID integer, REFIMG_ID integer, MODEL_USED integer, FACE_DISTANCE integer,
constraint PK_FRL_FACE_ID_REFIMG_ID primary key(FACE_ID, REFIMG_ID),
constraint FK_FRL_FACE_ID foreign key (FACE_ID) references FACE(ID) on delete cascade,
constraint FK_FRL_REFIMG_ID foreign key (REFIMG_ID) references REFIMG(ID),