with viewer, unmatched face now has img data / thumbnail, so we know what it really looks like when we choose to override - still major WIP, tables.sql also has some override types, but not convinced I have design yet

This commit is contained in:
2022-02-06 23:21:23 +11:00
parent 8625b1d217
commit e9ab49c60a
5 changed files with 66 additions and 12 deletions

1
TODO
View File

@@ -1,4 +1,5 @@
## GENERAL
* run_ai_on throws log line, for matching even if there are no faces, would be less noisy to not do that (or should say no faces?)
* on viewer:
- allow face to be used to create person, add to existing person, and allow 'ignore', mark as 'not a face', etc
-> ignore/not a face/too young --> all need to go into DB so we can remember the 'override' when we re-ai-match

24
ai.py
View File

@@ -105,3 +105,27 @@ def unmatched_faces():
face.img = str(face.img)[2:-1]
return render_template("faces.html", faces=faces)
# this is called in Ajax, when we manually override a face that is currently unmatched load
# the original full image, find the current face's coords, grab pixels 10% larger and return
# it so we can show it in the dbox, and be able to pass it around for refimg creation (if needed)
@app.route("/get_face_from_image/<face_id>", methods=["POST"])
@login_required
def get_face_from_image(face_id):
face=Face.query.get(face_id)
f = Entry.query.join(File).join(FaceFileLink).filter(FaceFileLink.face_id==face_id).first()
tmp_locn=json.loads(face.locn)
x=tmp_locn[3]*0.95
y=tmp_locn[0]*0.95
x2=tmp_locn[1]*1.05
y2=tmp_locn[2]*1.05
im = Image.open(f.FullPathOnFS())
region = im.crop((x, y, x2, y2))
img_bytearray = io.BytesIO()
region.save(img_bytearray, format='JPEG')
img_bytearray = img_bytearray.getvalue()
face_img = base64.b64encode(img_bytearray)
face_img = str(face_img)[2:-1]
return face_img

View File

@@ -204,8 +204,8 @@ $(document).ready( function()
$.contextMenu({
selector: '#canvas',
// trigger: 'left',
trigger: 'none',
trigger: 'left',
// trigger: 'none',
hideOnSecondTrigger: true,
build: function($triggerElement, e) {
@@ -226,16 +226,16 @@ $(document).ready( function()
if( x >= fx && x <= fx+fw && y >= fy && y <= fy+fh )
{
if( objs[current].faces[i].who )
item_list['match']={ 'name': objs[current].faces[i].who, 'which_face': i }
item_list['match']={ 'name': objs[current].faces[i].who, 'which_face': i, 'id': objs[current].faces[i].id }
else
{
item_list['no_match_new_person']={ 'name': 'Add as reference image to NEW person', 'which_face': i }
item_list['no_match_new_refimg']={ 'name': 'Add as reference image to EXISTING person', 'which_face': i }
item_list['no_match_override_match']={ 'name': 'Manually match to existing person', 'which_face': i }
item_list['no_match_no_face']={ 'name': 'Mark as not a face', 'which_face': i }
item_list['no_match_too_young']={ 'name': 'Mark as face too young', 'which_face': i }
item_list['no_match_ignore']={ 'name': 'Ignore this face', 'which_face': i }
item_list['remove_override']={ 'name': 'Remove override for this face', 'which_face': i }
item_list['no_match_new_person']={ 'name': 'Add as reference image to NEW person', 'which_face': i, 'id': objs[current].faces[i].id }
item_list['no_match_new_refimg']={ 'name': 'Add as reference image to EXISTING person', 'which_face': i, 'id': objs[current].faces[i].id }
item_list['no_match_override_match']={ 'name': 'Manually match to existing person', 'which_face': i, 'id': objs[current].faces[i].id }
item_list['no_match_no_face']={ 'name': 'Mark as not a face', 'which_face': i, 'id': objs[current].faces[i].id }
item_list['no_match_too_young']={ 'name': 'Mark as face too young', 'which_face': i, 'id': objs[current].faces[i].id }
item_list['no_match_ignore']={ 'name': 'Ignore this face', 'which_face': i, 'id': objs[current].faces[i].id }
item_list['remove_override']={ 'name': 'Remove override for this face', 'which_face': i, 'id': objs[current].faces[i].id }
}
delete item_list['not_a_face']
$('#canvas').prop('menu_item', item_list )
@@ -258,7 +258,13 @@ $(document).ready( function()
function FaceDBox(key, item)
{
div ='<p>'
div+='Face #' + item[key]['which_face']
div+='Face position #' + item[key]['which_face']
div+='<div id="face_img"></div>'
$.ajax({ type: 'POST', data: null, url: '/get_face_from_image/'+item[key]['id'],
success: function(img_data) {
$('#face_img').html( '<img src="data:image/jpeg;base64,' + img_data + '"></img>' )
}
} )
div+='</p>'
if ( key == 'no_match_new_person' )
{
@@ -266,11 +272,18 @@ function FaceDBox(key, item)
}
if ( key == 'no_match_new_refimg' || key == 'no_match_override_match' )
{
div+='<br>search for existing person'
div+='<h5>search for existing person:</h5>'
div+=
`
<div class="input-group mb-3"><input type="text" class="form-control" id="stext" placeholder="tag/name">
<button class="btn btn-outline-success" type="button" onClick="console.log('search for: ' + $('#stext').val());return false">Search</button>
</div>
`
}
if ( key == 'no_match_no_face' || key == 'no_match_too_young' || key == 'no_match_ignore' )
{
div+='<br>just track this against face#' + item[key]['which_face']
div+='<br>face db id: ' + item[key]['id']
}
$('#dbox-title').html(item[key]['name'])
$('#dbox-content').html(div)

View File

@@ -92,6 +92,21 @@ create table FACE_REFIMG_LINK( FACE_ID integer, REFIMG_ID integer, FACE_DISTANCE
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) );
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' );
create table FACE_NO_MATCH_OVERRIDE ( ID integer, FACE_ID integer, TYPE integer,
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) );
-- this could really suck, maybe we dont allow this???
--create table FACE_MANUAL_OVERRIDE ( ID integer, FACE_ID integer, PERSON_ID integer, TYPE integer, constraint PK_FACE_MANUAL_OVERRIDE_ID primary key(ID) );
create table PERSON_REFIMG_LINK ( PERSON_ID integer, REFIMG_ID integer,
constraint PK_PRL primary key(PERSON_ID, REFIMG_ID),
constraint FK_PRL_PERSON_ID foreign key (PERSON_ID) references PERSON(ID),

View File

@@ -40,6 +40,7 @@
e.faces=[]
{% for face in objs[id].file_details.faces %}
data = {
'id': '{{face.id}}',
'x': '{{face.locn[3]}}', 'y': '{{face.locn[0]}}',
'w': '{{face.locn[1]-face.locn[3]}}', 'h':'{{face.locn[2]-face.locn[0]}}'
}