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:
1
TODO
1
TODO
@@ -1,4 +1,5 @@
|
|||||||
## GENERAL
|
## 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:
|
* on viewer:
|
||||||
- allow face to be used to create person, add to existing person, and allow 'ignore', mark as 'not a face', etc
|
- 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
|
-> 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
24
ai.py
@@ -105,3 +105,27 @@ def unmatched_faces():
|
|||||||
face.img = str(face.img)[2:-1]
|
face.img = str(face.img)[2:-1]
|
||||||
|
|
||||||
return render_template("faces.html", faces=faces)
|
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
|
||||||
|
|||||||
@@ -204,8 +204,8 @@ $(document).ready( function()
|
|||||||
|
|
||||||
$.contextMenu({
|
$.contextMenu({
|
||||||
selector: '#canvas',
|
selector: '#canvas',
|
||||||
// trigger: 'left',
|
trigger: 'left',
|
||||||
trigger: 'none',
|
// trigger: 'none',
|
||||||
hideOnSecondTrigger: true,
|
hideOnSecondTrigger: true,
|
||||||
|
|
||||||
build: function($triggerElement, e) {
|
build: function($triggerElement, e) {
|
||||||
@@ -226,16 +226,16 @@ $(document).ready( function()
|
|||||||
if( x >= fx && x <= fx+fw && y >= fy && y <= fy+fh )
|
if( x >= fx && x <= fx+fw && y >= fy && y <= fy+fh )
|
||||||
{
|
{
|
||||||
if( objs[current].faces[i].who )
|
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
|
else
|
||||||
{
|
{
|
||||||
item_list['no_match_new_person']={ 'name': 'Add as reference image to NEW person', '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 }
|
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 }
|
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 }
|
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 }
|
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 }
|
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 }
|
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']
|
delete item_list['not_a_face']
|
||||||
$('#canvas').prop('menu_item', item_list )
|
$('#canvas').prop('menu_item', item_list )
|
||||||
@@ -258,7 +258,13 @@ $(document).ready( function()
|
|||||||
function FaceDBox(key, item)
|
function FaceDBox(key, item)
|
||||||
{
|
{
|
||||||
div ='<p>'
|
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>'
|
div+='</p>'
|
||||||
if ( key == 'no_match_new_person' )
|
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' )
|
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' )
|
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>just track this against face#' + item[key]['which_face']
|
||||||
|
div+='<br>face db id: ' + item[key]['id']
|
||||||
}
|
}
|
||||||
$('#dbox-title').html(item[key]['name'])
|
$('#dbox-title').html(item[key]['name'])
|
||||||
$('#dbox-content').html(div)
|
$('#dbox-content').html(div)
|
||||||
|
|||||||
15
tables.sql
15
tables.sql
@@ -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_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) );
|
||||||
|
|
||||||
|
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,
|
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),
|
||||||
constraint FK_PRL_PERSON_ID foreign key (PERSON_ID) references PERSON(ID),
|
constraint FK_PRL_PERSON_ID foreign key (PERSON_ID) references PERSON(ID),
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
e.faces=[]
|
e.faces=[]
|
||||||
{% for face in objs[id].file_details.faces %}
|
{% for face in objs[id].file_details.faces %}
|
||||||
data = {
|
data = {
|
||||||
|
'id': '{{face.id}}',
|
||||||
'x': '{{face.locn[3]}}', 'y': '{{face.locn[0]}}',
|
'x': '{{face.locn[3]}}', 'y': '{{face.locn[0]}}',
|
||||||
'w': '{{face.locn[1]-face.locn[3]}}', 'h':'{{face.locn[2]-face.locn[0]}}'
|
'w': '{{face.locn[1]-face.locn[3]}}', 'h':'{{face.locn[2]-face.locn[0]}}'
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user