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

4
TODO
View File

@@ -1,9 +1,5 @@
## GENERAL ## GENERAL
* allow for and implement: default_refimg_model and default_scan_model
- cnn for refimgs should be defaul, for scan use hog
- research upsample val...
* viewer needs to allow toggle to scan_model (and prob. right-click on file... AI (with CNN) AI (with hog) * viewer needs to allow toggle to scan_model (and prob. right-click on file... AI (with CNN) AI (with hog)
- I think go to html5 toggles for: face, distance (only shows if you toggle face on), drop-down for model (allow change to cnn and reprocess) - I think go to html5 toggles for: face, distance (only shows if you toggle face on), drop-down for model (allow change to cnn and reprocess)
- show matching face distance in viewer - show matching face distance in viewer

View File

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

View File

@@ -2,6 +2,7 @@ from wtforms import SubmitField, StringField, HiddenField, validators, Form
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask import request, render_template, redirect, url_for from flask import request, render_template, redirect, url_for
from main import db, app, ma from main import db, app, ma
from settings import Settings, AIModel
from sqlalchemy import Sequence from sqlalchemy import Sequence
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from status import st, Status from status import st, Status
@@ -27,6 +28,7 @@ class Refimg(db.Model):
face_locn = db.Column(db.String) face_locn = db.Column(db.String)
thumbnail = db.Column(db.String, unique=True, nullable=False) thumbnail = db.Column(db.String, unique=True, nullable=False)
created_on = db.Column(db.Float) created_on = db.Column(db.Float)
model_used = db.Column(db.Integer, db.ForeignKey("ai_model.id") )
person = db.relationship( 'Person', secondary="person_refimg_link", uselist=False, viewonly=True ) person = db.relationship( 'Person', secondary="person_refimg_link", uselist=False, viewonly=True )
def __repr__(self): def __repr__(self):
@@ -123,7 +125,7 @@ def person(id):
# do the linkage tables by hand # do the linkage tables by hand
db.session.execute( f"delete from face_refimg_link frl where refimg_id in ( select refimg_id from person_refimg_link where person_id = {id} )" ) db.session.execute( f"delete from face_refimg_link frl where refimg_id in ( select refimg_id from person_refimg_link where person_id = {id} )" )
db.session.execute( f"delete from person_refimg_link where person_id = {id}" ) db.session.execute( f"delete from person_refimg_link where person_id = {id}" )
person = Person.query.filter(Person.id==id).delete() Person.query.filter(Person.id==id).delete()
db.session.commit() db.session.commit()
return redirect( f'/persons' ) return redirect( f'/persons' )
elif request.form and form.validate(): elif request.form and form.validate():
@@ -132,9 +134,11 @@ def person(id):
if "ref-img-id-{}".format(ref_img.id) in request.form: if "ref-img-id-{}".format(ref_img.id) in request.form:
new_refs.append(ref_img) new_refs.append(ref_img)
if new_refs != person.refimg: if new_refs != person.refimg:
deld = list(set(person.refimg) - set(new_refs)) deld = list(set(person.refimg) - set(new_refs));
st.SetMessage( f"Successfully Updated Person: removed reference image {deld[0].fname}" ) print(deld)
person.refimg = new_refs person.refimg = new_refs
Refimg.query.filter(Refimg.id==deld[0].id).delete()
st.SetMessage( f"Successfully Updated Person: removed reference image {deld[0].fname}" )
else: else:
st.SetMessage("Successfully Updated Person: (From: {}, {}, {})".format(person.tag, person.firstname, person.surname) ) st.SetMessage("Successfully Updated Person: (From: {}, {}, {})".format(person.tag, person.firstname, person.surname) )
person.tag = request.form['tag'] person.tag = request.form['tag']
@@ -176,8 +180,11 @@ def add_refimg():
fname = f"/tmp/{fname}" fname = f"/tmp/{fname}"
f.save( fname ) f.save( fname )
refimg.thumbnail, refimg.orig_w, refimg.orig_h = GenThumb( fname ) refimg.thumbnail, refimg.orig_w, refimg.orig_h = GenThumb( fname )
refimg.face, face_locn = GenFace( fname ) settings = Settings.query.first()
model=AIModel.query.get(settings.default_refimg_model)
refimg.face, face_locn = GenFace( fname, model=model.name )
refimg.face_locn = json.dumps(face_locn) refimg.face_locn = json.dumps(face_locn)
refimg.model_used = settings.default_refimg_model
os.remove(fname) os.remove(fname)
person.refimg.append(refimg) person.refimg.append(refimg)
db.session.add(person) db.session.add(person)

View File

@@ -29,11 +29,12 @@ class Settings(db.Model):
import_path = db.Column(db.String) import_path = db.Column(db.String)
storage_path = db.Column(db.String) storage_path = db.Column(db.String)
recycle_bin_path = db.Column(db.String) recycle_bin_path = db.Column(db.String)
default_model = db.Column(db.Integer,db.ForeignKey('ai_model.id'), unique=True, nullable=False) default_refimg_model = db.Column(db.Integer,db.ForeignKey('ai_model.id'), unique=True, nullable=False)
default_scan_model = db.Column(db.Integer,db.ForeignKey('ai_model.id'), unique=True, nullable=False)
default_threshold = db.Column(db.Integer) default_threshold = db.Column(db.Integer)
def __repr__(self): def __repr__(self):
return f"<id: {self.id}, import_path: {self.import_path}, storage_path: {self.storage_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}, storage_path: {self.storage_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}>"
################################################################################ ################################################################################
# Helper class that inherits a .dump() method to turn class Settings into json / useful in jinja2 # Helper class that inherits a .dump() method to turn class Settings into json / useful in jinja2
@@ -54,7 +55,8 @@ class SettingsForm(FlaskForm):
import_path = StringField('Path(s) to import from:', [validators.DataRequired()]) import_path = StringField('Path(s) to import from:', [validators.DataRequired()])
storage_path = StringField('Path to store sorted images to:', [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()]) 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 AIModel.query.order_by('id')] ) default_refimg_model = SelectField( 'default_refimg_model', choices=[(c.id, c.name) for c in AIModel.query.order_by('id')] )
default_scan_model = SelectField( 'default_scan_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()]) default_threshold = StringField('Face Distance threshold (below is a match):', [validators.DataRequired()])
submit = SubmitField('Save' ) submit = SubmitField('Save' )
@@ -78,7 +80,8 @@ def settings():
s.import_path = request.form['import_path'] s.import_path = request.form['import_path']
s.storage_path = request.form['storage_path'] s.storage_path = request.form['storage_path']
s.recycle_bin_path = request.form['recycle_bin_path'] s.recycle_bin_path = request.form['recycle_bin_path']
s.default_model = request.form['default_model'] s.default_refimg_model = request.form['default_refimg_model']
s.default_scan_model = request.form['default_scan_model']
s.default_threshold = request.form['default_threshold'] s.default_threshold = request.form['default_threshold']
db.session.commit() db.session.commit()
return redirect( '/settings' ) return redirect( '/settings' )

View File

@@ -96,9 +96,10 @@ def GenThumb(fname):
print( f"GenThumb failed: {e}") print( f"GenThumb failed: {e}")
return None, None, None return None, None, None
def GenFace(fname): def GenFace(fname, model):
img = face_recognition.load_image_file(fname) img = face_recognition.load_image_file(fname)
location = face_recognition.face_locations(img) # TODO: change face_locations call basedon model
location = face_recognition.face_locations(img, model=model)
encodings = face_recognition.face_encodings(img, known_face_locations=location) encodings = face_recognition.face_encodings(img, known_face_locations=location)
if len(encodings): if len(encodings):
return encodings[0].tobytes(), location return encodings[0].tobytes(), location

View File

@@ -1,15 +1,16 @@
alter database PA set timezone to 'Australia/Victoria'; alter database PA set timezone to 'Australia/Victoria';
-- these are hard-coded at present, not sure I can reflexively find models from API? -- these are hard-coded at present, not sure I can reflexively find models from API?
create table AI_MODEL ( ID integer, NAME varchar(24), constraint PK_AI_MODEL primary key(ID) ); create table AI_MODEL ( ID integer, NAME varchar(24), DESCRIPTION varchar(80), constraint PK_AI_MODEL primary key(ID) );
insert into AI_MODEL values ( 1, 'hog' ); insert into AI_MODEL values ( 1, 'hog', 'normal' );
insert into AI_MODEL values ( 2, 'cnn' ); insert into AI_MODEL values ( 2, 'cnn', 'slower but more accurate' );
create table SETTINGS( create table SETTINGS(
ID integer, IMPORT_PATH varchar, STORAGE_PATH varchar, RECYCLE_BIN_PATH varchar, ID integer, IMPORT_PATH varchar, STORAGE_PATH varchar, RECYCLE_BIN_PATH varchar,
DEFAULT_MODEL integer, DEFAULT_THRESHOLD float, DEFAULT_REFIMG_MODEL integer, DEFAULT_SCAN_MODEL integer, DEFAULT_THRESHOLD float,
constraint PK_SETTINGS_ID primary key(ID), constraint PK_SETTINGS_ID primary key(ID),
constraint FK_DEFAULT_MODEL foreign key (DEFAULT_MODEL) references AI_MODEL(ID) ); constraint FK_DEFAULT_REFIMG_MODEL foreign key (DEFAULT_REFIMG_MODEL) references AI_MODEL(ID),
constraint FK_DEFAULT_SCAN_MODEL foreign key (DEFAULT_SCAN_MODEL) references AI_MODEL(ID) );
create table PA_USER( ID integer, dn varchar, constraint PK_PA_USER_ID primary key(ID) ); create table PA_USER( ID integer, dn varchar, constraint PK_PA_USER_ID primary key(ID) );
@@ -49,8 +50,9 @@ create table ENTRY_DIR_LINK ( entry_id integer, dir_eid integer,
create table PERSON ( ID integer, TAG varchar(48), FIRSTNAME varchar(48), SURNAME varchar(48), create table PERSON ( ID integer, TAG varchar(48), FIRSTNAME varchar(48), SURNAME varchar(48),
constraint PK_PERSON_ID primary key(ID) ); constraint PK_PERSON_ID primary key(ID) );
create table REFIMG ( ID integer, FNAME varchar(128), FACE bytea, ORIG_W integer, ORIG_H integer, FACE_LOCN varchar(32), CREATED_ON float, THUMBNAIL varchar, create table REFIMG ( ID integer, FNAME varchar(128), FACE bytea, ORIG_W integer, ORIG_H integer, FACE_LOCN varchar(32), CREATED_ON float, THUMBNAIL varchar, MODEL_USED integer,
constraint PK_REFIMG_ID primary key(ID) ); constraint PK_REFIMG_ID primary key(ID),
constraint FK_REFIMG_MODEL_USED foreign key (MODEL_USED) references AI_MODEL(ID) );
create table FACE( ID integer, FACE bytea, LOCN varchar(32), constraint PK_FACE_ID primary key(ID) ); create table FACE( ID integer, FACE bytea, LOCN varchar(32), constraint PK_FACE_ID primary key(ID) );
@@ -60,11 +62,10 @@ 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_FILE_EID foreign key (FILE_EID) references FILE(EID),
constraint FK_FFL_MODEL_USED foreign key (MODEL_USED) references AI_MODEL(ID) ); 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, FACE_DISTANCE integer, create table FACE_REFIMG_LINK( FACE_ID integer, REFIMG_ID integer, FACE_DISTANCE integer,
constraint PK_FRL_FACE_ID_REFIMG_ID primary key(FACE_ID, REFIMG_ID), 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_FACE_ID foreign key (FACE_ID) references FACE(ID) on delete cascade,
constraint FK_FRL_REFIMG_ID foreign key (REFIMG_ID) references REFIMG(ID), constraint FK_FRL_REFIMG_ID foreign key (REFIMG_ID) references REFIMG(ID) );
constraint FK_FRL_MODEL_USED foreign key (MODEL_USED) references AI_MODEL(ID) );
create table PERSON_REFIMG_LINK ( PERSON_ID integer, REFIMG_ID integer, create table PERSON_REFIMG_LINK ( PERSON_ID integer, REFIMG_ID integer,
constraint PK_PRL primary key(PERSON_ID, REFIMG_ID), constraint PK_PRL primary key(PERSON_ID, REFIMG_ID),
@@ -120,6 +121,6 @@ insert into PERSON values ( (select nextval('PERSON_ID_SEQ')), 'mum', 'Mandy', '
insert into PERSON values ( (select nextval('PERSON_ID_SEQ')), 'cam', 'Cameron', 'De Paoli' ); insert into PERSON values ( (select nextval('PERSON_ID_SEQ')), 'cam', 'Cameron', 'De Paoli' );
insert into PERSON values ( (select nextval('PERSON_ID_SEQ')), 'mich', 'Michelle', 'De Paoli' ); insert into PERSON values ( (select nextval('PERSON_ID_SEQ')), 'mich', 'Michelle', 'De Paoli' );
-- DEV: -- DEV:
insert into SETTINGS ( id, import_path, storage_path, recycle_bin_path, default_model, default_threshold ) values ( (select nextval('SETTINGS_ID_SEQ')), '/home/ddp/src/photoassistant/images_to_process/#c:/Users/cam/Desktop/code/python/photoassistant/photos/#/home/ddp/src/photoassistant/new_img_dir/', '/home/ddp/src/photoassistant/storage/#c:/Users/cam/Desktop/code/python/photoassistant/storage/', '/home/ddp/src/photoassistant/.pa_bin/#c:/Users/cam/Desktop/code/python/photoassistant/.pa_bin/', 1, '0.55' ); insert into SETTINGS ( id, import_path, storage_path, recycle_bin_path, default_refimg_model, default_scan_model, default_threshold ) values ( (select nextval('SETTINGS_ID_SEQ')), '/home/ddp/src/photoassistant/images_to_process/#c:/Users/cam/Desktop/code/python/photoassistant/photos/#/home/ddp/src/photoassistant/new_img_dir/', '/home/ddp/src/photoassistant/storage/#c:/Users/cam/Desktop/code/python/photoassistant/storage/', '/home/ddp/src/photoassistant/.pa_bin/#c:/Users/cam/Desktop/code/python/photoassistant/.pa_bin/', 2, 1, '0.55' );
-- PROD: -- PROD:
--insert into SETTINGS ( id, import_path, storage_path, recycle_bin_path, default_model, default_threshold ) values ( (select nextval('SETTINGS_ID_SEQ')), '/export/docker/storage/Camera_uploads/', '/export/docker/storage/photos/', '/export/docker/storage/.pa_bin/', 1, '0.55' ); --insert into SETTINGS ( id, import_path, storage_path, recycle_bin_path, default_refimg_model, default_scan_model, default_threshold ) values ( (select nextval('SETTINGS_ID_SEQ')), '/export/docker/storage/Camera_uploads/', '/export/docker/storage/photos/', '/export/docker/storage/.pa_bin/', 2, 1, '0.55' );

View File

@@ -83,6 +83,9 @@
</figure> </figure>
</div id="/RI*"> </div id="/RI*">
{% endfor %} {% endfor %}
<div id="throb" style="display:none" class="col-1 px-0 {{offset}}">
<img height="64px" src="{{url_for('static', filename='throbber.gif')}}"></img>
</div>
</div class="row col-12"> </div class="row col-12">
<div class="row col-12"> <div class="row col-12">
<br> <br>
@@ -100,7 +103,7 @@
<div class="row col-12"> <div class="row col-12">
<label class="btn btn-success offset-3 col-2"> <label class="btn btn-success offset-3 col-2">
Add reference image Add reference image
<input name="refimg_file" type="file" onChange="$('#new_ri').submit()" style="display:none;" id="new_file_chooser"> <input name="refimg_file" type="file" onChange="$('#throb').attr('style','show'); $('#new_ri').submit()" style="display:none;" id="new_file_chooser">
</label> </label>
</div class="row col-12"> </div class="row col-12">
</form> </form>