Refactored person processing to enable implementation of #181

This commit is contained in:
Rhet Turnbull
2020-07-06 00:10:22 -07:00
parent dfcbfa725a
commit fcff8ec5f8
9 changed files with 197 additions and 59 deletions

View File

@@ -520,10 +520,14 @@ def debug_dump(ctx, cli_obj, db, photos_library, dump, uuid):
print("_dbkeywords_uuid:")
pprint.pprint(photosdb._dbkeywords_uuid)
elif attr == "persons":
print("_dbfaces_person:")
pprint.pprint(photosdb._dbfaces_person)
print("_dbfaces_uuid:")
pprint.pprint(photosdb._dbfaces_uuid)
print("_dbfaces_pk:")
pprint.pprint(photosdb._dbfaces_pk)
print("_dbpersons_pk:")
pprint.pprint(photosdb._dbpersons_pk)
print("_dbpersons_fullname:")
pprint.pprint(photosdb._dbpersons_fullname)
elif attr == "photos":
if uuid:
for uuid_ in uuid:

View File

@@ -1,3 +1,3 @@
""" version info """
__version__ = "0.30.7"
__version__ = "0.30.8"

View File

@@ -339,7 +339,7 @@ class PhotoInfo:
@property
def persons(self):
""" list of persons in picture """
return self._info["persons"]
return [self._db._dbpersons_pk[k]["fullname"] for k in self._info["persons"]]
@property
def albums(self):

View File

@@ -122,17 +122,28 @@ class PhotosDB:
# currently used to get information on RAW images
self._dbphotos_master = {}
# Dict with information about all persons by person PK
# key is person PK, value is dict with info about each person
# e.g. {3: {"pk": 3, "fullname": "Maria Smith"...}}
self._dbpersons_pk = {}
# Dict with information about all persons by person fullname
# key is person PK, value is list of person PKs with fullname
# there may be more than one person PK with the same fullname
# e.g. {"Maria Smith": [1, 2]}
self._dbpersons_fullname = {}
# Dict with information about all persons/photos by uuid
# key is photo UUID, value is list of face names in that photo
# key is photo UUID, value is list of person primary keys of persons in the photo
# Note: Photos 5 identifies faces even if not given a name
# and those are labeled by process_database as _UNKNOWN_
# e.g. {'1EB2B765-0765-43BA-A90C-0D0580E6172C': ['Katie', '_UNKNOWN_', 'Suzy']}
# e.g. {'1EB2B765-0765-43BA-A90C-0D0580E6172C': [1, 3, 5]}
self._dbfaces_uuid = {}
# Dict with information about all persons/photos by person
# key is person name, value is list of photo UUIDs
# e.g. {'Maria': ['E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51']}
self._dbfaces_person = {}
# Dict with information about detected faces by person primary key
# key is person pk, value is list of photo UUIDs
# e.g. {3: ['E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51']}
self._dbfaces_pk = {}
# Dict with information about all keywords/photos by uuid
# key is photo uuid and value is list of keywords
@@ -303,7 +314,13 @@ class PhotosDB:
@property
def persons_as_dict(self):
""" return persons as dict of person, count in reverse sorted order (descending) """
persons = {k: len(self._dbfaces_person[k]) for k in self._dbfaces_person.keys()}
persons = {}
for pk in self._dbfaces_pk:
fullname = self._dbpersons_pk[pk]["fullname"]
try:
persons[fullname] += len(self._dbfaces_pk[pk])
except KeyError:
persons[fullname] = len(self._dbfaces_pk[pk])
persons = dict(sorted(persons.items(), key=lambda kv: kv[1], reverse=True))
return persons
@@ -352,7 +369,7 @@ class PhotosDB:
@property
def persons(self):
""" return list of persons found in photos database """
persons = self._dbfaces_person.keys()
persons = {self._dbpersons_pk[k]["fullname"] for k in self._dbfaces_pk}
return list(persons)
@property
@@ -536,22 +553,77 @@ class PhotosDB:
(conn, c) = _open_sql_file(self._tmp_db)
# Look for all combinations of persons and pictures
# get info to associate persons with photos
# then get detected faces in each photo and link to persons
c.execute(
""" select RKPerson.name, RKVersion.uuid from RKFace, RKPerson, RKVersion, RKMaster
where RKFace.personID = RKperson.modelID and RKVersion.modelId = RKFace.ImageModelId
and RKVersion.masterUuid = RKMaster.uuid
""" SELECT
RKPerson.modelID,
RKPerson.uuid,
RKPerson.name,
RKPerson.faceCount,
RKPerson.displayName
FROM RKPerson
"""
)
# 0 RKPerson.modelID,
# 1 RKPerson.uuid,
# 2 RKPerson.name,
# 3 RKPerson.faceCount,
# 4 RKPerson.displayName
for person in c:
if person[0] is None:
continue
if not person[1] in self._dbfaces_uuid:
self._dbfaces_uuid[person[1]] = []
if not person[0] in self._dbfaces_person:
self._dbfaces_person[person[0]] = []
self._dbfaces_uuid[person[1]].append(person[0])
self._dbfaces_person[person[0]].append(person[1])
pk = person[0]
fullname = person[2] if person[2] is not None else _UNKNOWN_PERSON
self._dbpersons_pk[pk] = {
"pk": pk,
"uuid": person[1],
"fullname": fullname,
"facecount": person[3],
"keyface": None,
"displayname": person[4],
}
try:
self._dbpersons_fullname[fullname].append(pk)
except KeyError:
self._dbpersons_fullname[fullname] = [pk]
# get information on detected faces
c.execute(
""" SELECT
RKPerson.modelID,
RKVersion.uuid
FROM
RKFace, RKPerson, RKVersion, RKMaster
WHERE
RKFace.personID = RKperson.modelID AND
RKVersion.modelId = RKFace.ImageModelId AND
RKVersion.masterUuid = RKMaster.uuid
"""
)
# 0 RKPerson.modelID
# 1 RKVersion.uuid
for face in c:
pk = face[0]
uuid = face[1]
try:
self._dbfaces_uuid[uuid].append(pk)
except KeyError:
self._dbfaces_uuid[uuid] = [pk]
try:
self._dbfaces_pk[pk].append(uuid)
except KeyError:
self._dbfaces_pk[pk] = [uuid]
if _debug():
logging.debug(f"Finished walking through persons")
logging.debug(pformat(self._dbpersons_pk))
logging.debug(pformat(self._dbpersons_fullname))
logging.debug(pformat(self._dbfaces_pk))
logging.debug(pformat(self._dbfaces_uuid))
# Get info on albums
c.execute(
@@ -1233,8 +1305,8 @@ class PhotosDB:
logging.debug("Faces (_dbfaces_uuid):")
logging.debug(pformat(self._dbfaces_uuid))
logging.debug("Faces by person (_dbfaces_person):")
logging.debug(pformat(self._dbfaces_person))
logging.debug("Persons (_dbpersons_pk):")
logging.debug(pformat(self._dbpersons_pk))
logging.debug("Keywords by uuid (_dbkeywords_uuid):")
logging.debug(pformat(self._dbkeywords_uuid))
@@ -1295,8 +1367,12 @@ class PhotosDB:
return folders
def _process_database5(self):
""" process the Photos database to extract info """
""" works on Photos version >= 5.0 """
""" process the Photos database to extract info
works on Photos version >= 5.0
This is a big hairy 700 line function that should probably be refactored
but it works so don't touch it.
"""
if _debug():
logging.debug(f"_process_database5")
@@ -1310,26 +1386,76 @@ class PhotosDB:
if _debug():
logging.debug(f"Getting information about persons")
# get info to associate persons with photos
# then get detected faces in each photo and link to persons
c.execute(
"SELECT ZPERSON.ZFULLNAME, ZGENERICASSET.ZUUID "
"FROM ZPERSON, ZDETECTEDFACE, ZGENERICASSET "
"WHERE ZDETECTEDFACE.ZPERSON = ZPERSON.Z_PK AND ZDETECTEDFACE.ZASSET = ZGENERICASSET.Z_PK "
""" SELECT
ZPERSON.Z_PK,
ZPERSON.ZPERSONUUID,
ZPERSON.ZFULLNAME,
ZPERSON.ZFACECOUNT,
ZPERSON.ZKEYFACE,
ZPERSON.ZDISPLAYNAME
FROM ZPERSON
"""
)
# 0 ZPERSON.Z_PK,
# 1 ZPERSON.ZPERSONUUID,
# 2 ZPERSON.ZFULLNAME,
# 3 ZPERSON.ZFACECOUNT,
# 4 ZPERSON.ZKEYFACE,
# 5 ZPERSON.ZDISPLAYNAME,
for person in c:
if person[0] is None:
continue
person_name = person[0] if person[0] != "" else _UNKNOWN_PERSON
if not person[1] in self._dbfaces_uuid:
self._dbfaces_uuid[person[1]] = []
if not person_name in self._dbfaces_person:
self._dbfaces_person[person_name] = []
self._dbfaces_uuid[person[1]].append(person_name)
self._dbfaces_person[person_name].append(person[1])
pk = person[0]
fullname = person[2] if person[2] != "" else _UNKNOWN_PERSON
self._dbpersons_pk[pk] = {
"pk": pk,
"uuid": person[1],
"fullname": fullname,
"facecount": person[3],
"keyface": person[4],
"displayname": person[5],
}
try:
self._dbpersons_fullname[fullname].append(pk)
except KeyError:
self._dbpersons_fullname[fullname] = [pk]
# get information on detected faces
c.execute(
""" SELECT
ZPERSON.Z_PK,
ZGENERICASSET.ZUUID
FROM ZPERSON, ZDETECTEDFACE, ZGENERICASSET
WHERE ZDETECTEDFACE.ZPERSON = ZPERSON.Z_PK AND
ZDETECTEDFACE.ZASSET = ZGENERICASSET.Z_PK;
"""
)
# 0 ZPERSON.Z_PK,
# 1 ZGENERICASSET.ZUUID,
for face in c:
pk = face[0]
uuid = face[1]
try:
self._dbfaces_uuid[uuid].append(pk)
except KeyError:
self._dbfaces_uuid[uuid] = [pk]
try:
self._dbfaces_pk[pk].append(uuid)
except KeyError:
self._dbfaces_pk[pk] = [uuid]
if _debug():
logging.debug(f"Finished walking through persons")
logging.debug(pformat(self._dbfaces_person))
logging.debug(self._dbfaces_uuid)
logging.debug(pformat(self._dbpersons_pk))
logging.debug(pformat(self._dbpersons_fullname))
logging.debug(pformat(self._dbfaces_pk))
logging.debug(pformat(self._dbfaces_uuid))
# get details about albums
c.execute(
@@ -1921,8 +2047,8 @@ class PhotosDB:
logging.debug("Faces (_dbfaces_uuid):")
logging.debug(pformat(self._dbfaces_uuid))
logging.debug("Faces by person (_dbfaces_person):")
logging.debug(pformat(self._dbfaces_person))
logging.debug("Persons (_dbpersons_pk):")
logging.debug(pformat(self._dbpersons_pk))
logging.debug("Keywords by uuid (_dbkeywords_uuid):")
logging.debug(pformat(self._dbkeywords_uuid))
@@ -2283,8 +2409,9 @@ class PhotosDB:
if persons:
person_set = set()
for person in persons:
if person in self._dbfaces_person:
person_set.update(self._dbfaces_person[person])
if person in self._dbpersons_fullname:
for pk in self._dbpersons_fullname[person]:
person_set.update(self._dbfaces_pk[pk])
else:
logging.debug(f"Could not find person '{person}' in database")
photos_sets.append(person_set)