mirror of
https://github.com/iperov/DeepFaceLive
synced 2025-08-14 18:57:24 -07:00
+xlib.facemeta and refactoring
This commit is contained in:
parent
081dde23c7
commit
63adc2995e
28 changed files with 962 additions and 613 deletions
6
xlib/facemeta/ELandmarks2D.py
Normal file
6
xlib/facemeta/ELandmarks2D.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from enum import IntEnum
|
||||
|
||||
class ELandmarks2D(IntEnum):
|
||||
L5 = 0
|
||||
L68 = 1
|
||||
L468 = 2
|
4
xlib/facemeta/EMaskType.py
Normal file
4
xlib/facemeta/EMaskType.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from enum import IntEnum
|
||||
|
||||
class EMaskType(IntEnum):
|
||||
UNDEFINED = 0
|
|
@ -1,24 +1,20 @@
|
|||
from enum import IntEnum
|
||||
from typing import Tuple
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
import numpy.linalg as npla
|
||||
|
||||
from ..math import Affine2DMat, Affine2DUniMat
|
||||
from .ELandmarks2D import ELandmarks2D
|
||||
from .FRect import FRect
|
||||
|
||||
|
||||
class FaceULandmarks:
|
||||
"""
|
||||
Describes 2D face landmarks in uniform coordinates
|
||||
"""
|
||||
|
||||
class Type(IntEnum):
|
||||
LANDMARKS_5 = 0
|
||||
LANDMARKS_68 = 1
|
||||
LANDMARKS_468 = 2
|
||||
|
||||
class FLandmarks2D:
|
||||
def __init__(self):
|
||||
self._type : FaceULandmarks.Type = None
|
||||
"""
|
||||
Describes 2D face landmarks in uniform float coordinates
|
||||
"""
|
||||
self._type : ELandmarks2D = None
|
||||
self._ulmrks : np.ndarray = None
|
||||
|
||||
def __getstate__(self):
|
||||
|
@ -29,14 +25,13 @@ class FaceULandmarks:
|
|||
self.__dict__.update(d)
|
||||
|
||||
@staticmethod
|
||||
def create( type : 'FaceULandmarks.Type', ulmrks : np.ndarray):
|
||||
def create( type : ELandmarks2D, ulmrks : np.ndarray):
|
||||
"""
|
||||
|
||||
ulmrks np.ndarray (*,2|3)
|
||||
"""
|
||||
|
||||
if not isinstance(type, FaceULandmarks.Type):
|
||||
raise ValueError('type must be an FaceULandmarks.Type')
|
||||
if not isinstance(type, ELandmarks2D):
|
||||
raise ValueError('type must be ELandmarks2D')
|
||||
|
||||
ulmrks = np.float32(ulmrks)
|
||||
if len(ulmrks.shape) != 2:
|
||||
|
@ -46,22 +41,22 @@ class FaceULandmarks:
|
|||
raise ValueError('ulmrks dim must be == 2')
|
||||
|
||||
ulmrks_count = ulmrks.shape[0]
|
||||
if type == FaceULandmarks.Type.LANDMARKS_5:
|
||||
if type == ELandmarks2D.L5:
|
||||
if ulmrks_count != 5:
|
||||
raise ValueError('ulmrks_count must be == 5')
|
||||
elif type == FaceULandmarks.Type.LANDMARKS_68:
|
||||
elif type == ELandmarks2D.L68:
|
||||
if ulmrks_count != 68:
|
||||
raise ValueError('ulmrks_count must be == 68')
|
||||
elif type == FaceULandmarks.Type.LANDMARKS_468:
|
||||
elif type == ELandmarks2D.L468:
|
||||
if ulmrks_count != 468:
|
||||
raise ValueError('ulmrks_count must be == 468')
|
||||
|
||||
face_ulmrks = FaceULandmarks()
|
||||
face_ulmrks = FLandmarks2D()
|
||||
face_ulmrks._type = type
|
||||
face_ulmrks._ulmrks = ulmrks
|
||||
return face_ulmrks
|
||||
|
||||
def get_type(self) -> 'FaceULandmarks.Type': return self._type
|
||||
def get_type(self) -> ELandmarks2D: return self._type
|
||||
def get_count(self) -> int: return self._ulmrks.shape[0]
|
||||
|
||||
def as_numpy(self, w_h = None):
|
||||
|
@ -76,9 +71,9 @@ class FaceULandmarks:
|
|||
|
||||
return ulmrks
|
||||
|
||||
def transform(self, mat, invert=False) -> 'FaceULandmarks':
|
||||
def transform(self, mat, invert=False) -> 'FLandmarks2D':
|
||||
"""
|
||||
Tranforms FaceULandmarks using affine mat and returns new FaceULandmarks()
|
||||
Tranforms FLandmarks2D using affine mat and returns new FLandmarks2D()
|
||||
|
||||
mat : np.ndarray
|
||||
"""
|
||||
|
@ -93,9 +88,20 @@ class FaceULandmarks:
|
|||
ulmrks = np.expand_dims(ulmrks, axis=1)
|
||||
ulmrks = cv2.transform(ulmrks, mat, ulmrks.shape).squeeze()
|
||||
|
||||
return FaceULandmarks.create(type=self._type, ulmrks=ulmrks)
|
||||
|
||||
return FLandmarks2D.create(type=self._type, ulmrks=ulmrks)
|
||||
|
||||
def get_FRect(self, coverage=1.6) -> FRect:
|
||||
"""
|
||||
create FRect from landmarks with given coverage
|
||||
"""
|
||||
_, uni_mat = self.calc_cut( (1,1), coverage, 1, exclude_moving_parts=False)
|
||||
xlt, xlb, xrb, xrt = uni_mat.invert().transform_points([[0,0], [0,1], [1,1], [1,0]])
|
||||
l = min(xlt[0], xlb[0])
|
||||
t = min(xlt[1], xrt[1])
|
||||
r = max(xrt[0], xrb[0])
|
||||
b = max(xlb[1], xrb[1])
|
||||
return FRect.from_ltrb( (l,t,r,b) )
|
||||
|
||||
def calc_cut(self, w_h, coverage : float, output_size : int,
|
||||
exclude_moving_parts : bool,
|
||||
head_yaw : float = None,
|
||||
|
@ -112,9 +118,9 @@ class FaceULandmarks:
|
|||
lmrks = (self._ulmrks * w_h).astype(np.float32)
|
||||
|
||||
# estimate landmarks transform from global space to local aligned space with bounds [0..1]
|
||||
if type == FaceULandmarks.Type.LANDMARKS_68:
|
||||
if type == ELandmarks2D.L68:
|
||||
mat = Affine2DMat.umeyama( np.concatenate ([ lmrks[17:49] , lmrks[54:55] ]), uni_landmarks_68)
|
||||
elif type == FaceULandmarks.Type.LANDMARKS_468:
|
||||
elif type == ELandmarks2D.L468:
|
||||
src_lmrks = lmrks
|
||||
dst_lmrks = uni_landmarks_468
|
||||
if exclude_moving_parts:
|
||||
|
@ -1297,4 +1303,4 @@ uni_landmarks_468 = np.array(
|
|||
# # time.sleep(1.0)
|
||||
|
||||
# import code
|
||||
# code.interact(local=dict(globals(), **locals()))
|
||||
# code.interact(local=dict(globals(), **locals()))
|
40
xlib/facemeta/FMask.py
Normal file
40
xlib/facemeta/FMask.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
import uuid
|
||||
from typing import Union
|
||||
from enum import IntEnum
|
||||
|
||||
class FMask:
|
||||
class Type(IntEnum):
|
||||
WHOLE_FACE = 0
|
||||
|
||||
def __init__(self, _from_pickled=False):
|
||||
"""
|
||||
"""
|
||||
self._uuid : Union[bytes, None] = uuid.uuid4().bytes_le if not _from_pickled else None
|
||||
self._mask_type : Union[FMask.Type, None] = None
|
||||
self._FImage_uuid : Union[bytes, None] = None
|
||||
|
||||
def __getstate__(self):
|
||||
return self.__dict__.copy()
|
||||
|
||||
def __setstate__(self, d):
|
||||
self.__init__(_from_pickled=True)
|
||||
self.__dict__.update(d)
|
||||
|
||||
def get_uuid(self) -> Union[bytes, None]: return self._uuid
|
||||
def set_uuid(self, uuid : Union[bytes, None]):
|
||||
if uuid is not None and not isinstance(uuid, bytes):
|
||||
raise ValueError(f'uuid must be an instance of bytes or None')
|
||||
self._uuid = uuid
|
||||
|
||||
def get_mask_type(self) -> Union['FMask.Type', None]: return self._mask_type
|
||||
def set_mask_type(self, mask_type : Union['FMask.Type', None]):
|
||||
if mask_type is not None and not isinstance(mask_type, 'FMask.Type'):
|
||||
raise ValueError(f'mask_type must be an instance of FMask.Type or None')
|
||||
self._mask_type = mask_type
|
||||
|
||||
def get_FImage_uuid(self) -> Union[bytes, None]: return self._FImage_uuid
|
||||
def set_FImage_uuid(self, FImage_uuid : Union[bytes, None]):
|
||||
if FImage_uuid is not None and not isinstance(FImage_uuid, bytes):
|
||||
raise ValueError(f'FImage_uuid must be an instance of bytes or None')
|
||||
self._FImage_uuid = FImage_uuid
|
||||
|
|
@ -3,7 +3,7 @@ import numpy as np
|
|||
from .. import math as lib_math
|
||||
|
||||
|
||||
class FacePose:
|
||||
class FPose:
|
||||
"""
|
||||
Describes face pitch/yaw/roll
|
||||
"""
|
||||
|
@ -33,7 +33,7 @@ class FacePose:
|
|||
def from_radians(pitch, yaw, roll):
|
||||
"""
|
||||
"""
|
||||
face_rect = FacePose()
|
||||
face_rect = FPose()
|
||||
face_rect._pyr = np.array([pitch, yaw, roll], np.float32)
|
||||
return face_rect
|
||||
|
||||
|
@ -47,4 +47,4 @@ class FacePose:
|
|||
mat[2,:] = np.cross(mat[0, :], mat[1, :])
|
||||
pitch, yaw, roll = lib_math.rotation_matrix_to_euler(mat)
|
||||
|
||||
return FacePose.from_radians(pitch, yaw, roll)
|
||||
return FPose.from_radians(pitch, yaw, roll)
|
|
@ -8,8 +8,7 @@ import numpy.linalg as npla
|
|||
from .. import math as lib_math
|
||||
from ..math import Affine2DMat, Affine2DUniMat
|
||||
|
||||
|
||||
class FaceURect:
|
||||
class FRect:
|
||||
"""
|
||||
Describes face rectangle in uniform float coordinates
|
||||
"""
|
||||
|
@ -24,9 +23,9 @@ class FaceURect:
|
|||
self.__dict__.update(d)
|
||||
|
||||
@staticmethod
|
||||
def sort_by_area_size(rects : List['FaceURect']):
|
||||
def sort_by_area_size(rects : List['FRect']):
|
||||
"""
|
||||
sort list of FaceURect by largest area descend
|
||||
sort list of FRect by largest area descend
|
||||
"""
|
||||
rects = [ (rect, rect.get_area()) for rect in rects ]
|
||||
rects = sorted(rects, key=operator.itemgetter(1), reverse=True )
|
||||
|
@ -34,9 +33,9 @@ class FaceURect:
|
|||
return rects
|
||||
|
||||
@staticmethod
|
||||
def sort_by_dist_from_center(rects : List['FaceURect']):
|
||||
def sort_by_dist_from_center(rects : List['FRect']):
|
||||
"""
|
||||
sort list of FaceURect by nearest distance from center to center of rects descent
|
||||
sort list of FRect by nearest distance from center to center of rects descent
|
||||
"""
|
||||
c = np.float32([0.5,0.5])
|
||||
|
||||
|
@ -48,7 +47,7 @@ class FaceURect:
|
|||
@staticmethod
|
||||
def from_4pts(pts : Iterable):
|
||||
"""
|
||||
Construct FaceURect from 4 pts
|
||||
Construct FRect from 4 pts
|
||||
0--3
|
||||
| |
|
||||
1--2
|
||||
|
@ -60,14 +59,14 @@ class FaceURect:
|
|||
if pts.shape != (4,2):
|
||||
raise ValueError('pts must have (4,2) shape')
|
||||
|
||||
face_rect = FaceURect()
|
||||
face_rect = FRect()
|
||||
face_rect._pts = pts
|
||||
return face_rect
|
||||
|
||||
@staticmethod
|
||||
def from_ltrb(ltrb : Iterable):
|
||||
"""
|
||||
Construct FaceURect from l,t,r,b list of float values
|
||||
Construct FRect from l,t,r,b list of float values
|
||||
t
|
||||
l-|-r
|
||||
b
|
||||
|
@ -76,7 +75,7 @@ class FaceURect:
|
|||
raise ValueError('ltrb must be Iterable')
|
||||
|
||||
l,t,r,b = ltrb
|
||||
return FaceURect.from_4pts([ [l,t], [l,b], [r,b], [r,t] ])
|
||||
return FRect.from_4pts([ [l,t], [l,b], [r,b], [r,t] ])
|
||||
|
||||
|
||||
def get_area(self, w_h = None) -> float:
|
||||
|
@ -124,9 +123,9 @@ class FaceURect:
|
|||
return self._pts * w_h
|
||||
return self._pts.copy()
|
||||
|
||||
def transform(self, mat, invert=False) -> 'FaceURect':
|
||||
def transform(self, mat, invert=False) -> 'FRect':
|
||||
"""
|
||||
Tranforms FaceURect using affine mat and returns new FaceURect()
|
||||
Tranforms FRect using affine mat and returns new FRect()
|
||||
|
||||
mat : np.ndarray should be uniform affine mat
|
||||
"""
|
||||
|
@ -141,7 +140,7 @@ class FaceURect:
|
|||
pts = np.expand_dims(pts, axis=1)
|
||||
pts = cv2.transform(pts, mat, pts.shape).squeeze()
|
||||
|
||||
return FaceURect.from_4pts(pts)
|
||||
return FRect.from_4pts(pts)
|
||||
|
||||
def cut(self, img : np.ndarray, coverage : float, output_size : int) -> Tuple[Affine2DMat, Affine2DUniMat]:
|
||||
"""
|
|
@ -1,95 +1,237 @@
|
|||
import pickle
|
||||
import sqlite3
|
||||
from pathlib import Path
|
||||
from typing import Tuple
|
||||
from typing import Generator, List, Union
|
||||
|
||||
import cv2
|
||||
from .. import cv as lib_cv
|
||||
from .. import path as lib_path
|
||||
from ..io import FormattedFileIO
|
||||
import numpy as np
|
||||
|
||||
from .face import FaceMark
|
||||
from .FMask import FMask
|
||||
from .UFaceMark import UFaceMark
|
||||
from .UImage import UImage
|
||||
from .UPerson import UPerson
|
||||
|
||||
|
||||
class Faceset:
|
||||
"""
|
||||
Faceset is a class to store and manage multiple FaceMark()'s
|
||||
|
||||
|
||||
arguments:
|
||||
|
||||
path path to directory
|
||||
|
||||
raises
|
||||
|
||||
Exception, ValueError
|
||||
"""
|
||||
|
||||
def __init__(self, path):
|
||||
"""
|
||||
Faceset is a class to store and manage face related data.
|
||||
|
||||
arguments:
|
||||
|
||||
path path to faceset .dfs file
|
||||
"""
|
||||
|
||||
self._path = path = Path(path)
|
||||
if not path.is_dir():
|
||||
raise ValueError('Path must be a directory.')
|
||||
|
||||
self.reload()
|
||||
if path.suffix != '.dfs':
|
||||
raise ValueError('Path must be a .dfs file')
|
||||
|
||||
def reload(self):
|
||||
self._conn = conn = sqlite3.connect(path, isolation_level=None)
|
||||
self._cur = cur = conn.cursor()
|
||||
|
||||
cur.execute('BEGIN IMMEDIATE')
|
||||
if not self._is_table_exists('FacesetInfo'):
|
||||
self.clear_db(transaction=False)
|
||||
cur.execute('COMMIT')
|
||||
|
||||
def close(self):
|
||||
self._cur.close()
|
||||
self._cur = None
|
||||
self._conn.close()
|
||||
self._conn = None
|
||||
|
||||
def _is_table_exists(self, name):
|
||||
return self._cur.execute(f"SELECT count(*) FROM sqlite_master WHERE type='table' AND name=?", [name]).fetchone()[0] != 0
|
||||
|
||||
def shrink(self):
|
||||
self._cur.execute('VACUUM')
|
||||
|
||||
def clear_db(self, transaction=True):
|
||||
"""
|
||||
reload the faceset
|
||||
|
||||
raises
|
||||
|
||||
Exception
|
||||
delete all data and recreate DB
|
||||
"""
|
||||
self._is_packed = False
|
||||
cur = self._cur
|
||||
|
||||
filepaths = lib_path.get_files_paths(self._path)
|
||||
if transaction:
|
||||
cur.execute('BEGIN IMMEDIATE')
|
||||
|
||||
face_filepaths = self._face_filepaths = set()
|
||||
for table_name, in cur.execute("SELECT name from sqlite_master where type = 'table';").fetchall():
|
||||
cur.execute(f'DROP TABLE {table_name}')
|
||||
|
||||
for filepath in filepaths:
|
||||
suffix = filepath.suffix
|
||||
if suffix == '.face':
|
||||
if self._is_packed:
|
||||
raise Exception(f'{self._path} contains .faceset and .face but only one type is allowed.')
|
||||
(cur.execute('CREATE TABLE FacesetInfo (version INT)')
|
||||
.execute('INSERT INTO FacesetInfo VALUES (1)')
|
||||
|
||||
face_filepaths.add(filepath.name)
|
||||
elif suffix == '.faceset':
|
||||
if self._is_packed:
|
||||
raise Exception(f'{self._path} contains more than one .faceset.')
|
||||
.execute('CREATE TABLE UImage (uuid BLOB, name TEXT, format TEXT, data BLOB)')
|
||||
.execute('CREATE TABLE UPerson (uuid BLOB, name TEXT, age NUMERIC)')
|
||||
.execute('CREATE TABLE UFaceMark (uuid BLOB, UImage_uuid BLOB, UPerson_uuid BLOB, pickled_bytes BLOB)')
|
||||
)
|
||||
|
||||
if len(face_filepaths) != 0:
|
||||
raise Exception(f'{self._path} contains .faceset and .face but only one type is allowed.')
|
||||
self._is_packed = True
|
||||
|
||||
def pack(self):
|
||||
if transaction:
|
||||
cur.execute('COMMIT')
|
||||
|
||||
###################
|
||||
### UFaceMark
|
||||
###################
|
||||
def _UFaceMark_from_db_row(self, db_row) -> UFaceMark:
|
||||
uuid, UImage_uuid, UPerson_uuid, pickled_bytes = db_row
|
||||
return pickle.loads(pickled_bytes)
|
||||
|
||||
def add_UFaceMark(self, fm : UFaceMark):
|
||||
"""
|
||||
Pack faceset.
|
||||
add or update UFaceMark in DB
|
||||
"""
|
||||
pickled_bytes = pickle.dumps(fm)
|
||||
uuid = fm.get_uuid()
|
||||
UImage_uuid = fm.get_UImage_uuid()
|
||||
UPerson_uuid = fm.get_UPerson_uuid()
|
||||
|
||||
def unpack(self):
|
||||
"""
|
||||
unpack faceset.
|
||||
"""
|
||||
|
||||
def is_packed(self) -> bool: return self._is_packed
|
||||
|
||||
def get_face_count(self): return len(self._face_filepaths)
|
||||
|
||||
def get_faces(self) -> Tuple[FaceMark]:
|
||||
"""
|
||||
returns a tuple of FaceMark()'s
|
||||
"""
|
||||
|
||||
def save_face(self, face : FaceMark):
|
||||
filepath = self._path / (face.get_name() + '.face')
|
||||
|
||||
with FormattedFileIO(filepath, 'w+') as f:
|
||||
f.write_pickled(face)
|
||||
|
||||
self._face_filepaths.add(filepath.name)
|
||||
|
||||
def save_image(self, name, img, type='jpg'):
|
||||
filepath = self._path / (name + f'.{type}')
|
||||
|
||||
if type == 'jpg':
|
||||
lib_cv.imwrite(filepath, img, [int(cv2.IMWRITE_JPEG_QUALITY), 100] )
|
||||
cur = self._cur
|
||||
cur.execute('BEGIN IMMEDIATE')
|
||||
if cur.execute('SELECT COUNT(*) from UFaceMark where uuid=?', [uuid] ).fetchone()[0] != 0:
|
||||
cur.execute('UPDATE UFaceMark SET UImage_uuid=?, UPerson_uuid=?, pickled_bytes=? WHERE uuid=?',
|
||||
[UImage_uuid, UPerson_uuid, pickled_bytes, uuid])
|
||||
else:
|
||||
raise ValueError(f'Unknown type {type}')
|
||||
cur.execute('INSERT INTO UFaceMark VALUES (?, ?, ?, ?)', [uuid, UImage_uuid, UPerson_uuid, pickled_bytes])
|
||||
cur.execute('COMMIT')
|
||||
|
||||
def get_UFaceMark_count(self) -> int:
|
||||
return self._cur.execute('SELECT COUNT(*) FROM UFaceMark').fetchone()[0]
|
||||
|
||||
def get_all_UFaceMark(self) -> List[UFaceMark]:
|
||||
return [ pickle.loads(pickled_bytes) for pickled_bytes, in self._cur.execute('SELECT pickled_bytes FROM UFaceMark').fetchall() ]
|
||||
|
||||
def iter_UFaceMark(self) -> Generator[UFaceMark, None, None]:
|
||||
"""
|
||||
returns Generator of UFaceMark
|
||||
"""
|
||||
for db_row in self._cur.execute('SELECT * FROM UFaceMark').fetchall():
|
||||
yield self._UFaceMark_from_db_row(db_row)
|
||||
|
||||
def delete_all_UFaceMark(self):
|
||||
"""
|
||||
deletes all UFaceMark from DB
|
||||
"""
|
||||
(self._cur.execute('BEGIN IMMEDIATE')
|
||||
.execute('DELETE FROM UFaceMark')
|
||||
.execute('COMMIT') )
|
||||
|
||||
###################
|
||||
### UPerson
|
||||
###################
|
||||
def add_UPerson(self, uperson : UPerson):
|
||||
"""
|
||||
add or update UPerson in DB
|
||||
"""
|
||||
uuid = uperson.get_uuid()
|
||||
name = uperson.get_name()
|
||||
age = uperson.get_age()
|
||||
|
||||
cur = self._conn.cursor()
|
||||
cur.execute('BEGIN IMMEDIATE')
|
||||
if cur.execute('SELECT COUNT(*) from UPerson where uuid=?', [uuid]).fetchone()[0] != 0:
|
||||
cur.execute('UPDATE UPerson SET name=?, age=? WHERE uuid=?', [name, age, uuid])
|
||||
else:
|
||||
cur.execute('INSERT INTO UPerson VALUES (?, ?, ?)', [uuid, name, age])
|
||||
cur.execute('COMMIT')
|
||||
cur.close()
|
||||
|
||||
def iter_UPerson(self) -> Generator[UPerson, None, None]:
|
||||
"""
|
||||
iterator of all UPerson's
|
||||
"""
|
||||
for uuid, name, age in self._cur.execute('SELECT * FROM UPerson').fetchall():
|
||||
uperson = UPerson()
|
||||
uperson.set_uuid(uuid)
|
||||
uperson.set_name(name)
|
||||
uperson.set_age(age)
|
||||
yield uperson
|
||||
|
||||
def delete_all_UPerson(self):
|
||||
"""
|
||||
deletes all UPerson from DB
|
||||
"""
|
||||
(self._cur.execute('BEGIN IMMEDIATE')
|
||||
.execute('DELETE FROM UPerson')
|
||||
.execute('COMMIT') )
|
||||
|
||||
###################
|
||||
### UImage
|
||||
###################
|
||||
def _UImage_from_db_row(self, db_row) -> UImage:
|
||||
uuid, name, format, data_bytes = db_row
|
||||
img = cv2.imdecode(np.frombuffer(data_bytes, dtype=np.uint8), flags=cv2.IMREAD_UNCHANGED)
|
||||
|
||||
uimg = UImage()
|
||||
uimg.set_uuid(uuid)
|
||||
uimg.set_name(name)
|
||||
uimg.assign_image(img)
|
||||
return uimg
|
||||
|
||||
def add_UImage(self, uimage : UImage, format : str = 'webp', quality : int = 100):
|
||||
"""
|
||||
add or update UImage in DB
|
||||
|
||||
uimage UImage object
|
||||
|
||||
format('png') webp ( does not support lossless on 100 quality ! )
|
||||
png ( lossless )
|
||||
jpg
|
||||
jp2 ( jpeg2000 )
|
||||
|
||||
quality(100) 0-100 for formats jpg,jp2,webp
|
||||
"""
|
||||
if format not in ['webp','png', 'jpg', 'jp2']:
|
||||
raise ValueError(f'format {format} is unsupported')
|
||||
|
||||
if format in ['jpg','jp2'] and quality < 0 or quality > 100:
|
||||
raise ValueError('quality must be in range [0..100]')
|
||||
|
||||
img = uimage.get_image()
|
||||
uuid = uimage.get_uuid()
|
||||
|
||||
if format == 'webp':
|
||||
imencode_args = [int(cv2.IMWRITE_WEBP_QUALITY), quality]
|
||||
elif format == 'jpg':
|
||||
imencode_args = [int(cv2.IMWRITE_JPEG_QUALITY), quality]
|
||||
elif format == 'jp2':
|
||||
imencode_args = [int(cv2.IMWRITE_JPEG2000_COMPRESSION_X1000), quality*10]
|
||||
else:
|
||||
imencode_args = []
|
||||
|
||||
ret, data_bytes = cv2.imencode( f'.{format}', img, imencode_args)
|
||||
if not ret:
|
||||
raise Exception(f'Unable to encode image format {format}')
|
||||
|
||||
cur = self._cur
|
||||
cur.execute('BEGIN IMMEDIATE')
|
||||
if cur.execute('SELECT COUNT(*) from UImage where uuid=?', [uuid] ).fetchone()[0] != 0:
|
||||
cur.execute('UPDATE UImage SET name=?, format=?, data=? WHERE uuid=?', [uimage.get_name(), format, data_bytes.data, uuid])
|
||||
else:
|
||||
cur.execute('INSERT INTO UImage VALUES (?, ?, ?, ?)', [uuid, uimage.get_name(), format, data_bytes.data])
|
||||
cur.execute('COMMIT')
|
||||
|
||||
def get_UImage_count(self) -> int: return self._cur.execute('SELECT COUNT(*) FROM UImage').fetchone()[0]
|
||||
def get_UImage_by_uuid(self, uuid : bytes) -> Union[UImage, None]:
|
||||
"""
|
||||
"""
|
||||
db_row = self._cur.execute('SELECT * FROM UImage where uuid=?', [uuid]).fetchone()
|
||||
if db_row is None:
|
||||
return None
|
||||
return self._UImage_from_db_row(db_row)
|
||||
|
||||
def iter_UImage(self) -> Generator[UImage, None, None]:
|
||||
"""
|
||||
iterator of all UImage's
|
||||
"""
|
||||
for db_row in self._cur.execute('SELECT * FROM UImage').fetchall():
|
||||
yield self._UImage_from_db_row(db_row)
|
||||
|
||||
def delete_all_UImage(self):
|
||||
"""
|
||||
deletes all UImage from DB
|
||||
"""
|
||||
(self._cur.execute('BEGIN IMMEDIATE')
|
||||
.execute('DELETE FROM UImage')
|
||||
.execute('COMMIT') )
|
||||
|
|
99
xlib/facemeta/UFaceMark.py
Normal file
99
xlib/facemeta/UFaceMark.py
Normal file
|
@ -0,0 +1,99 @@
|
|||
import uuid
|
||||
from typing import List, Tuple, Union
|
||||
|
||||
from ..math import Affine2DMat
|
||||
from .ELandmarks2D import ELandmarks2D
|
||||
from .EMaskType import EMaskType
|
||||
from .FLandmarks2D import FLandmarks2D
|
||||
from .FPose import FPose
|
||||
from .FRect import FRect
|
||||
|
||||
|
||||
class UFaceMark:
|
||||
def __init__(self, _from_pickled=False):
|
||||
"""
|
||||
Describes single face in the image.
|
||||
"""
|
||||
self._uuid : Union[bytes, None] = uuid.uuid4().bytes_le if not _from_pickled else None
|
||||
self._UImage_uuid : Union[bytes, None] = None
|
||||
self._UPerson_uuid : Union[bytes, None] = None
|
||||
self._FRect : Union[FRect, None] = None
|
||||
self._FLandmarks2D_list : List[FLandmarks2D] = []
|
||||
self._FPose : Union[FPose, None] = None
|
||||
self._mask_info_list : List = []
|
||||
|
||||
def __getstate__(self):
|
||||
return self.__dict__.copy()
|
||||
|
||||
def __setstate__(self, d):
|
||||
self.__init__(_from_pickled=True)
|
||||
self.__dict__.update(d)
|
||||
|
||||
def __str__(self):
|
||||
s = "Masks: "
|
||||
return f"UFaceMark UUID:[...{self._uuid[-4:].hex()}]"
|
||||
|
||||
def __repr__(self): return self.__str__()
|
||||
|
||||
def get_uuid(self) -> Union[bytes, None]: return self._uuid
|
||||
def set_uuid(self, uuid : Union[bytes, None]):
|
||||
if uuid is not None and not isinstance(uuid, bytes):
|
||||
raise ValueError(f'uuid must be an instance of bytes or None')
|
||||
self._uuid = uuid
|
||||
|
||||
def get_UImage_uuid(self) -> Union[bytes, None]: return self._UImage_uuid
|
||||
def set_UImage_uuid(self, UImage_uuid : Union[bytes, None]):
|
||||
if UImage_uuid is not None and not isinstance(UImage_uuid, bytes):
|
||||
raise ValueError(f'UImage_uuid must be an instance of bytes or None')
|
||||
self._UImage_uuid = UImage_uuid
|
||||
|
||||
def get_UPerson_uuid(self) -> Union[bytes, None]: return self._UPerson_uuid
|
||||
def set_UPerson_uuid(self, UPerson_uuid : Union[bytes, None]):
|
||||
if UPerson_uuid is not None and not isinstance(UPerson_uuid, bytes):
|
||||
raise ValueError(f'UPerson_uuid must be an instance of bytes or None')
|
||||
self._UPerson_uuid = UPerson_uuid
|
||||
|
||||
def get_FRect(self) -> Union['FRect', None]: return self._FRect
|
||||
def set_FRect(self, face_urect : Union['FRect', None]):
|
||||
if face_urect is not None and not isinstance(face_urect, FRect):
|
||||
raise ValueError(f'face_urect must be an instance of FRect or None')
|
||||
self._FRect = face_urect
|
||||
|
||||
def get_all_FLandmarks2D(self) -> List[FLandmarks2D]: return self._FLandmarks2D_list
|
||||
def get_FLandmarks2D_by_type(self, type : ELandmarks2D) -> Union[FLandmarks2D, None]:
|
||||
"""get FLandmarks2D from list by type"""
|
||||
if not isinstance(type, ELandmarks2D):
|
||||
raise ValueError(f'type must be an instance of ELandmarks2D')
|
||||
|
||||
for ulmrks in self._FLandmarks2D_list:
|
||||
if ulmrks.get_type() == type:
|
||||
return ulmrks
|
||||
return None
|
||||
|
||||
def add_FLandmarks2D(self, flmrks : FLandmarks2D):
|
||||
if not isinstance(flmrks, FLandmarks2D):
|
||||
raise ValueError('flmrks must be an instance of FLandmarks2D')
|
||||
|
||||
if self.get_FLandmarks2D_by_type(flmrks.get_type()) is not None:
|
||||
raise Exception(f'_FLandmarks2D_list already contains type {flmrks.get_type()}.')
|
||||
|
||||
self._FLandmarks2D_list.append(flmrks)
|
||||
|
||||
def get_FPose(self) -> Union[FPose, None]: return self._FPose
|
||||
def set_FPose(self, face_pose : FPose):
|
||||
if not isinstance(face_pose, FPose):
|
||||
raise ValueError('face_pose must be an instance of FPose')
|
||||
self._FPose = face_pose
|
||||
|
||||
def get_mask_info_list(self) -> List[Tuple[EMaskType, bytes, Affine2DMat]]:
|
||||
return self._mask_info_list
|
||||
|
||||
def add_mask_info(self, mask_type : EMaskType, UImage_uuid : bytes, mask_to_mark_uni_mat : Affine2DMat):
|
||||
if not isinstance(mask_type, EMaskType):
|
||||
raise ValueError('mask_type must be an instance of EMaskType')
|
||||
if not isinstance(UImage_uuid, bytes):
|
||||
raise ValueError('UImage_uuid must be an instance of bytes')
|
||||
if not isinstance(mask_to_mark_uni_mat, Affine2DMat):
|
||||
raise ValueError('mask_to_mark_uni_mat must be an instance of Affine2DMat')
|
||||
|
||||
self._mask_info_list.append( (mask_type, UImage_uuid, mask_to_mark_uni_mat) )
|
59
xlib/facemeta/UImage.py
Normal file
59
xlib/facemeta/UImage.py
Normal file
|
@ -0,0 +1,59 @@
|
|||
import uuid
|
||||
from typing import Union
|
||||
|
||||
import numpy as np
|
||||
|
||||
class UImage:
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
represents uncompressed image uint8 HWC ( 1/3/4 channels )
|
||||
"""
|
||||
self._uuid : Union[bytes, None] = uuid.uuid4().bytes_le
|
||||
self._name : Union[str, None] = None
|
||||
self._image : np.ndarray = None
|
||||
|
||||
def __getstate__(self):
|
||||
return self.__dict__.copy()
|
||||
|
||||
def __setstate__(self, d):
|
||||
self.__init__()
|
||||
self.__dict__.update(d)
|
||||
|
||||
def __str__(self): return f"UImage UUID:[...{self._uuid[-4:].hex()}] name:[{self._name}] image:[{ (self._image.shape, self._image.dtype) if self._image is not None else None}]"
|
||||
def __repr__(self): return self.__str__()
|
||||
|
||||
def get_uuid(self) -> Union[bytes, None]: return self._uuid
|
||||
def set_uuid(self, uuid : Union[bytes, None]):
|
||||
if uuid is not None and not isinstance(uuid, bytes):
|
||||
raise ValueError(f'uuid must be an instance of bytes or None')
|
||||
self._uuid = uuid
|
||||
|
||||
def get_name(self) -> Union[str, None]: return self._name
|
||||
def set_name(self, name : Union[str, None]):
|
||||
if name is not None and not isinstance(name, str):
|
||||
raise ValueError(f'name must be an instance of str or None')
|
||||
self._name = name
|
||||
|
||||
def get_image(self) -> Union[np.ndarray, None]: return self._image
|
||||
def assign_image(self, image : Union[np.ndarray, None]):
|
||||
"""
|
||||
assign np.ndarray image , or remove(None)
|
||||
|
||||
It's mean you should not to change provided image nd.array after assigning, or do the copy before.
|
||||
|
||||
Image must be uint8 and HWC 1/3/4 channels.
|
||||
"""
|
||||
if image is not None:
|
||||
if image.ndim == 2:
|
||||
image = image[...,None]
|
||||
|
||||
if image.ndim != 3:
|
||||
raise ValueError('image must have ndim == 3')
|
||||
_,_,C = image.shape
|
||||
if C not in [1,3,4]:
|
||||
raise ValueError('image channels must be 1,3,4')
|
||||
if image.dtype != np.uint8:
|
||||
raise ValueError('image dtype must be uint8')
|
||||
self._image = image
|
||||
|
39
xlib/facemeta/UPerson.py
Normal file
39
xlib/facemeta/UPerson.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
import uuid
|
||||
from typing import Union
|
||||
|
||||
|
||||
class UPerson:
|
||||
def __init__(self, _from_pickled=False):
|
||||
"""
|
||||
"""
|
||||
self._uuid : Union[bytes, None] = uuid.uuid4().bytes_le if not _from_pickled else None
|
||||
self._name : Union[str, None] = None
|
||||
self._age : Union[int, None] = None
|
||||
|
||||
def __getstate__(self):
|
||||
return self.__dict__.copy()
|
||||
|
||||
def __setstate__(self, d):
|
||||
self.__init__(_from_pickled=True)
|
||||
self.__dict__.update(d)
|
||||
|
||||
def __str__(self): return f"UPerson UUID:[...{self._uuid[-4:].hex()}] name:[{self._name}] age:[{self._age}]"
|
||||
def __repr__(self): return self.__str__()
|
||||
|
||||
def get_uuid(self) -> Union[bytes, None]: return self._uuid
|
||||
def set_uuid(self, uuid : Union[bytes, None]):
|
||||
if uuid is not None and not isinstance(uuid, bytes):
|
||||
raise ValueError(f'uuid must be an instance of bytes or None')
|
||||
self._uuid = uuid
|
||||
|
||||
def get_name(self) -> Union[str, None]: return self._name
|
||||
def set_name(self, name : Union[str, None]):
|
||||
if name is not None and not isinstance(name, str):
|
||||
raise ValueError(f'name must be an instance of str or None')
|
||||
self._name = name
|
||||
|
||||
def get_age(self) -> Union[str, None]: return self._age
|
||||
def set_age(self, age : Union[int, None]):
|
||||
if age is not None and not isinstance(age, int):
|
||||
raise ValueError(f'age must be an instance of int or None')
|
||||
self._age = age
|
|
@ -1,48 +1,61 @@
|
|||
"""
|
||||
facemeta
|
||||
facemeta library
|
||||
|
||||
Trying to standartize face description.
|
||||
Contains classes for effectively storing, manage, and transfering all face related data.
|
||||
|
||||
It is not perfect structure, but enough for current tasks.
|
||||
All classes are picklable and expandable.
|
||||
All classes have noneable members accessed via get/set. No properties.
|
||||
|
||||
FaceURect and FaceULandmarks mean uniform coordinates in order to apply them to any resolution.
|
||||
E-classes are enums.
|
||||
U-classes are unique, have uuid and can be saved in Faceset.
|
||||
|
||||
Overall structure:
|
||||
ELandmarks2D L5
|
||||
L68
|
||||
L468
|
||||
|
||||
EMaskType UNDEFINED, ..., ...
|
||||
|
||||
FaceMark - (mean single face data referencing any image)
|
||||
.image_name - image reference
|
||||
.person_name - optional name of person
|
||||
.FaceURect - a rectangle of the face in source image space
|
||||
.list[FaceULandmarks] - a list of unique types of landmarks of the face in source image space
|
||||
types:
|
||||
LANDMARKS_5
|
||||
LANDMARKS_68
|
||||
LANDMARKS_468
|
||||
|
||||
.FaceAlign - an aligned face from FaceMark
|
||||
|
||||
.image_name - image reference
|
||||
.person_name - optional name of person
|
||||
.coverage - coverage value used to align
|
||||
|
||||
.source_source_face_ulandmarks_type - type of FaceULandmarks from which this FaceAlign was produced
|
||||
.source_to_aligned_uni_mat - uniform AffineMat to FaceMark image space to FaceAlign image space
|
||||
|
||||
.FaceURect - a rectangle of the face in aligned image space
|
||||
.list[FaceULandmarks] - a list of unique types of landmarks of the face in aligned image space
|
||||
|
||||
.FaceMask - grayscale image to mask the face in FaceAlign image space
|
||||
.image_name - image reference
|
||||
|
||||
.FaceSwap - face image of other person in the same as FaceAlign image space
|
||||
.image_name - image reference
|
||||
.person_name - optional name of person
|
||||
|
||||
.FaceMask - grayscale image to mask the swapped face in FaceSwap image space
|
||||
.image_name
|
||||
FRect rectangle of the face in uniform float coordinates
|
||||
|
||||
FLandmarks2D 2D landmarks of the face in uniform float coordinates
|
||||
|
||||
FPose pitch/yaw/roll values
|
||||
|
||||
UPerson - person info
|
||||
.uuid
|
||||
.name
|
||||
.age
|
||||
|
||||
UImage - image
|
||||
.uuid
|
||||
.name
|
||||
.data (H,W,C 1/3/4 ) of uint8[0..255]
|
||||
|
||||
|
||||
UFaceMark - face mark info referencing UImage from which the face was detected
|
||||
.uuid
|
||||
.UImage_uuid - reference to FImage
|
||||
.UPerson_uuid - reference to FPerson
|
||||
.FRect
|
||||
.List[FLandmarks2D]
|
||||
.FPose
|
||||
|
||||
.List[ (EMaskType, FImage_uuid, uni_mat) ] - list of FMask and AffineMat to transform mask image space to UFaceMark image space
|
||||
|
||||
|
||||
Faceset
|
||||
.List[UImage]
|
||||
.List[UFaceMark]
|
||||
.List[UPerson]
|
||||
"""
|
||||
|
||||
from .face import FaceMark, FaceAlign, FaceSwap, FaceMask, FaceURect, FaceULandmarks, FacePose
|
||||
from .ELandmarks2D import ELandmarks2D
|
||||
from .EMaskType import EMaskType
|
||||
from .Faceset import Faceset
|
||||
from .UImage import UImage
|
||||
from .FLandmarks2D import FLandmarks2D
|
||||
from .UFaceMark import UFaceMark
|
||||
from .FMask import FMask
|
||||
from .UPerson import UPerson
|
||||
from .FPose import FPose
|
||||
from .FRect import FRect
|
||||
|
|
|
@ -1,211 +0,0 @@
|
|||
from typing import List, Union
|
||||
|
||||
from .. import math as lib_math
|
||||
|
||||
from .FaceULandmarks import FaceULandmarks
|
||||
from .FaceURect import FaceURect
|
||||
from .FacePose import FacePose
|
||||
|
||||
class _part_picklable_expandable:
|
||||
def __getstate__(self):
|
||||
return self.__dict__.copy()
|
||||
|
||||
def __setstate__(self, d):
|
||||
self.__init__()
|
||||
self.__dict__.update(d)
|
||||
|
||||
class _part_image_name:
|
||||
def __init__(self):
|
||||
self._image_name : Union[str, None] = None
|
||||
|
||||
def get_image_name(self) -> Union[str, None]: return self._image_name
|
||||
def set_image_name(self, image_name : Union[str, None]):
|
||||
if image_name is not None and not isinstance(image_name, str):
|
||||
raise ValueError(f'image_name must be an instance of str or None')
|
||||
self._image_name = image_name
|
||||
|
||||
class _part_person_name:
|
||||
def __init__(self):
|
||||
self._person_name : Union[str, None] = None
|
||||
|
||||
def get_person_name(self) -> Union[str, None]: return self._person_name
|
||||
def set_person_name(self, person_name : Union[str, None]):
|
||||
if person_name is not None and not isinstance(person_name, str):
|
||||
raise ValueError(f'person_name must be an instance of str or None')
|
||||
self._person_name = person_name
|
||||
|
||||
class _part_face_align:
|
||||
def __init__(self):
|
||||
self._face_align : Union['FaceAlign', None] = None
|
||||
|
||||
def get_face_align(self) -> Union['FaceAlign', None]: return self._face_align
|
||||
def set_face_align(self, face_align : 'FaceAlign'):
|
||||
"""add FaceAlign"""
|
||||
if not isinstance(face_align, FaceAlign):
|
||||
raise ValueError('face_align must be an instance of FaceAlign')
|
||||
self._face_align = face_align
|
||||
|
||||
class _part_face_urect:
|
||||
def __init__(self):
|
||||
self._face_urect : Union[FaceURect, None] = None
|
||||
|
||||
def get_face_urect(self) -> Union['FaceURect', None]:
|
||||
"""get uniform FaceURect"""
|
||||
return self._face_urect
|
||||
|
||||
def set_face_urect(self, face_urect : Union['FaceURect', None]):
|
||||
if face_urect is not None and not isinstance(face_urect, FaceURect):
|
||||
raise ValueError(f'face_urect must be an instance of FaceURect or None')
|
||||
self._face_urect = face_urect
|
||||
|
||||
class _part_face_ulandmarks_list:
|
||||
def __init__(self):
|
||||
self._face_ulmrks_list : List[FaceULandmarks] = []
|
||||
|
||||
def get_face_ulandmarks_list(self) -> List['FaceULandmarks']: return self._face_ulmrks_list
|
||||
def get_face_ulandmarks_by_type(self, type : 'FaceULandmarks.Type') -> Union['FaceULandmarks', None]:
|
||||
"""get FaceULandmarks from list by type"""
|
||||
if not isinstance(type, FaceULandmarks.Type):
|
||||
raise ValueError(f'type must be an instance of FaceULandmarks.Type')
|
||||
|
||||
for ulmrks in self._face_ulmrks_list:
|
||||
if ulmrks.get_type() == type:
|
||||
return ulmrks
|
||||
return None
|
||||
|
||||
|
||||
def add_face_ulandmarks(self, face_ulmrks : 'FaceULandmarks'):
|
||||
if not isinstance(face_ulmrks, FaceULandmarks):
|
||||
raise ValueError('face_ulmrks must be an instance of FaceULandmarks')
|
||||
|
||||
if self.get_face_ulandmarks_by_type(face_ulmrks.get_type()) is not None:
|
||||
raise Exception(f'_face_ulmrks_list already contains type {face_ulmrks.get_type()}.')
|
||||
|
||||
self._face_ulmrks_list.append(face_ulmrks)
|
||||
|
||||
class _part_source_source_face_ulandmarks_type:
|
||||
def __init__(self):
|
||||
self._source_face_ulandmarks_type : Union[FaceULandmarks.Type, None] = None
|
||||
|
||||
def get_source_face_ulandmarks_type(self) -> Union[FaceULandmarks.Type, None]: return self._source_face_ulandmarks_type
|
||||
def set_source_face_ulandmarks_type(self, source_face_ulandmarks_type : Union[FaceULandmarks.Type, None]):
|
||||
if source_face_ulandmarks_type is not None and not isinstance(source_face_ulandmarks_type, FaceULandmarks.Type):
|
||||
raise ValueError('source_face_ulandmarks_type must be an instance of FaceULandmarks.Type')
|
||||
self._source_face_ulandmarks_type = source_face_ulandmarks_type
|
||||
|
||||
|
||||
class _part_coverage:
|
||||
def __init__(self):
|
||||
self._coverage : Union[float, None] = None
|
||||
|
||||
def get_coverage(self) -> Union[float, None]: return self._coverage
|
||||
def set_coverage(self, coverage : Union[float, None]):
|
||||
if coverage is not None and not isinstance(coverage, float):
|
||||
raise ValueError('coverage must be an instance of float')
|
||||
self._coverage = coverage
|
||||
|
||||
class _part_source_to_aligned_uni_mat:
|
||||
def __init__(self):
|
||||
self._source_to_aligned_uni_mat : Union[lib_math.Affine2DUniMat, None] = None
|
||||
|
||||
def get_source_to_aligned_uni_mat(self) -> Union[lib_math.Affine2DUniMat, None]: return self._source_to_aligned_uni_mat
|
||||
def set_source_to_aligned_uni_mat(self, source_to_aligned_uni_mat : Union[lib_math.Affine2DUniMat, None]):
|
||||
if source_to_aligned_uni_mat is not None and not isinstance(source_to_aligned_uni_mat, lib_math.Affine2DUniMat):
|
||||
raise ValueError('source_to_aligned_uni_mat must be an instance of lib_math.Affine2DUniMat')
|
||||
self._source_to_aligned_uni_mat = source_to_aligned_uni_mat
|
||||
|
||||
|
||||
class _part_face_mask:
|
||||
def __init__(self):
|
||||
self._face_mask : Union['FaceMask', None] = None
|
||||
|
||||
def get_face_mask(self) -> Union['FaceMask', None]: return self._face_mask
|
||||
def set_face_mask(self, face_mask : 'FaceMask'):
|
||||
if not isinstance(face_mask, FaceMask):
|
||||
raise ValueError('face_mask must be an instance of FaceMask')
|
||||
self._face_mask = face_mask
|
||||
|
||||
class _part_face_swap:
|
||||
def __init__(self):
|
||||
self._face_swap : Union['FaceSwap', None] = None
|
||||
|
||||
def get_face_swap(self) -> Union['FaceSwap', None]: return self._face_swap
|
||||
def set_face_swap(self, face_swap : 'FaceSwap'):
|
||||
if not isinstance(face_swap, FaceSwap):
|
||||
raise ValueError('face_swap must be an instance of FaceSwap')
|
||||
self._face_swap = face_swap
|
||||
|
||||
class _part_face_pose:
|
||||
def __init__(self):
|
||||
self._face_pose : Union['FacePose', None] = None
|
||||
|
||||
def get_face_pose(self) -> Union['FacePose', None]: return self._face_pose
|
||||
def set_face_pose(self, face_pose : 'FacePose'):
|
||||
if not isinstance(face_pose, FacePose):
|
||||
raise ValueError('face_pose must be an instance of FacePose')
|
||||
self._face_pose = face_pose
|
||||
|
||||
|
||||
class FaceMark(_part_picklable_expandable,
|
||||
_part_image_name,
|
||||
_part_person_name,
|
||||
_part_face_urect,
|
||||
_part_face_ulandmarks_list,
|
||||
_part_face_align,
|
||||
_part_face_pose,
|
||||
):
|
||||
"""
|
||||
Describes meta data of single face.
|
||||
|
||||
must not contain any images or large buffers, only references or filenames of them.
|
||||
"""
|
||||
def __init__(self):
|
||||
_part_image_name.__init__(self)
|
||||
_part_person_name.__init__(self)
|
||||
_part_face_urect.__init__(self)
|
||||
_part_face_ulandmarks_list.__init__(self)
|
||||
_part_face_align.__init__(self)
|
||||
_part_face_pose.__init__(self)
|
||||
|
||||
class FaceAlign(_part_picklable_expandable,
|
||||
_part_image_name,
|
||||
_part_person_name,
|
||||
_part_face_urect,
|
||||
_part_face_ulandmarks_list,
|
||||
_part_coverage,
|
||||
_part_source_source_face_ulandmarks_type,
|
||||
_part_source_to_aligned_uni_mat,
|
||||
_part_face_mask,
|
||||
_part_face_swap,
|
||||
):
|
||||
def __init__(self):
|
||||
_part_image_name.__init__(self)
|
||||
_part_person_name.__init__(self)
|
||||
_part_coverage.__init__(self)
|
||||
_part_source_source_face_ulandmarks_type.__init__(self)
|
||||
_part_source_to_aligned_uni_mat.__init__(self)
|
||||
_part_face_urect.__init__(self)
|
||||
_part_face_ulandmarks_list.__init__(self)
|
||||
_part_face_mask.__init__(self)
|
||||
_part_face_swap.__init__(self)
|
||||
|
||||
|
||||
class FaceSwap(_part_picklable_expandable,
|
||||
_part_image_name,
|
||||
_part_person_name,
|
||||
_part_face_mask,
|
||||
):
|
||||
|
||||
def __init__(self):
|
||||
_part_image_name.__init__(self)
|
||||
_part_person_name.__init__(self)
|
||||
_part_face_mask.__init__(self)
|
||||
|
||||
|
||||
class FaceMask(_part_picklable_expandable,
|
||||
_part_image_name,
|
||||
):
|
||||
def __init__(self):
|
||||
_part_image_name.__init__(self)
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue