|
from enum import IntEnum |
|
from pathlib import Path |
|
|
|
import cv2 |
|
import numpy as np |
|
|
|
from core.cv2ex import * |
|
from facelib import LandmarksProcessor |
|
from core import imagelib |
|
from core.imagelib import SegIEPolys |
|
|
|
class SampleType(IntEnum): |
|
IMAGE = 0 |
|
|
|
FACE_BEGIN = 1 |
|
FACE = 1 |
|
FACE_PERSON = 2 |
|
FACE_TEMPORAL_SORTED = 3 |
|
FACE_END = 3 |
|
|
|
QTY = 4 |
|
|
|
class Sample(object): |
|
__slots__ = ['sample_type', |
|
'filename', |
|
'face_type', |
|
'shape', |
|
'landmarks', |
|
'seg_ie_polys', |
|
'xseg_mask', |
|
'xseg_mask_compressed', |
|
'eyebrows_expand_mod', |
|
'source_filename', |
|
'person_name', |
|
'pitch_yaw_roll', |
|
'_filename_offset_size', |
|
] |
|
|
|
def __init__(self, sample_type=None, |
|
filename=None, |
|
face_type=None, |
|
shape=None, |
|
landmarks=None, |
|
seg_ie_polys=None, |
|
xseg_mask=None, |
|
xseg_mask_compressed=None, |
|
eyebrows_expand_mod=None, |
|
source_filename=None, |
|
person_name=None, |
|
pitch_yaw_roll=None, |
|
**kwargs): |
|
|
|
self.sample_type = sample_type if sample_type is not None else SampleType.IMAGE |
|
self.filename = filename |
|
self.face_type = face_type |
|
self.shape = shape |
|
self.landmarks = np.array(landmarks) if landmarks is not None else None |
|
|
|
if isinstance(seg_ie_polys, SegIEPolys): |
|
self.seg_ie_polys = seg_ie_polys |
|
else: |
|
self.seg_ie_polys = SegIEPolys.load(seg_ie_polys) |
|
|
|
self.xseg_mask = xseg_mask |
|
self.xseg_mask_compressed = xseg_mask_compressed |
|
|
|
if self.xseg_mask_compressed is None and self.xseg_mask is not None: |
|
xseg_mask = np.clip( imagelib.normalize_channels(xseg_mask, 1)*255, 0, 255 ).astype(np.uint8) |
|
ret, xseg_mask_compressed = cv2.imencode('.png', xseg_mask) |
|
if not ret: |
|
raise Exception("Sample(): unable to generate xseg_mask_compressed") |
|
self.xseg_mask_compressed = xseg_mask_compressed |
|
self.xseg_mask = None |
|
|
|
self.eyebrows_expand_mod = eyebrows_expand_mod if eyebrows_expand_mod is not None else 1.0 |
|
self.source_filename = source_filename |
|
self.person_name = person_name |
|
self.pitch_yaw_roll = pitch_yaw_roll |
|
|
|
self._filename_offset_size = None |
|
|
|
def has_xseg_mask(self): |
|
return self.xseg_mask is not None or self.xseg_mask_compressed is not None |
|
|
|
def get_xseg_mask(self): |
|
if self.xseg_mask_compressed is not None: |
|
xseg_mask = cv2.imdecode(self.xseg_mask_compressed, cv2.IMREAD_UNCHANGED) |
|
if len(xseg_mask.shape) == 2: |
|
xseg_mask = xseg_mask[...,None] |
|
return xseg_mask.astype(np.float32) / 255.0 |
|
return self.xseg_mask |
|
|
|
def get_pitch_yaw_roll(self): |
|
if self.pitch_yaw_roll is None: |
|
self.pitch_yaw_roll = LandmarksProcessor.estimate_pitch_yaw_roll(self.landmarks, size=self.shape[1]) |
|
return self.pitch_yaw_roll |
|
|
|
def set_filename_offset_size(self, filename, offset, size): |
|
self._filename_offset_size = (filename, offset, size) |
|
|
|
def read_raw_file(self, filename=None): |
|
if self._filename_offset_size is not None: |
|
filename, offset, size = self._filename_offset_size |
|
with open(filename, "rb") as f: |
|
f.seek( offset, 0) |
|
return f.read (size) |
|
else: |
|
with open(filename, "rb") as f: |
|
return f.read() |
|
|
|
def load_bgr(self): |
|
img = cv2_imread (self.filename, loader_func=self.read_raw_file).astype(np.float32) / 255.0 |
|
return img |
|
|
|
def get_config(self): |
|
return {'sample_type': self.sample_type, |
|
'filename': self.filename, |
|
'face_type': self.face_type, |
|
'shape': self.shape, |
|
'landmarks': self.landmarks.tolist(), |
|
'seg_ie_polys': self.seg_ie_polys.dump(), |
|
'xseg_mask' : self.xseg_mask, |
|
'xseg_mask_compressed' : self.xseg_mask_compressed, |
|
'eyebrows_expand_mod': self.eyebrows_expand_mod, |
|
'source_filename': self.source_filename, |
|
'person_name': self.person_name |
|
} |
|
|