removing default yaw_value from DFLIMG files,

added better pitch/yaw estimator from 68 landmarks,
improving face yaw accuracy for sorting and trainers,
added sort by face-pitch
This commit is contained in:
iperov 2019-02-12 21:31:37 +04:00
parent 535041f7bb
commit 06fe1314d8
13 changed files with 182 additions and 37 deletions

View file

@ -16,23 +16,25 @@ class SampleType(IntEnum):
QTY = 5
class Sample(object):
def __init__(self, sample_type=None, filename=None, face_type=None, shape=None, landmarks=None, yaw=None, mirror=None, close_target_list=None):
def __init__(self, sample_type=None, filename=None, face_type=None, shape=None, landmarks=None, pitch=None, yaw=None, mirror=None, close_target_list=None):
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
self.pitch = pitch
self.yaw = yaw
self.mirror = mirror
self.close_target_list = close_target_list
def copy_and_set(self, sample_type=None, filename=None, face_type=None, shape=None, landmarks=None, yaw=None, mirror=None, close_target_list=None):
def copy_and_set(self, sample_type=None, filename=None, face_type=None, shape=None, landmarks=None, pitch=None, yaw=None, mirror=None, close_target_list=None):
return Sample(
sample_type=sample_type if sample_type is not None else self.sample_type,
filename=filename if filename is not None else self.filename,
face_type=face_type if face_type is not None else self.face_type,
shape=shape if shape is not None else self.shape,
landmarks=landmarks if landmarks is not None else self.landmarks.copy(),
pitch=pitch if pitch is not None else self.pitch,
yaw=yaw if yaw is not None else self.yaw,
mirror=mirror if mirror is not None else self.mirror,
close_target_list=close_target_list if close_target_list is not None else self.close_target_list)

View file

@ -4,6 +4,7 @@ import random
import cv2
import multiprocessing
from utils import iter_utils
from facelib import LandmarksProcessor
from samples import SampleType
from samples import SampleProcessor
@ -18,11 +19,13 @@ output_sample_types = [
]
'''
class SampleGeneratorFace(SampleGeneratorBase):
def __init__ (self, samples_path, debug, batch_size, sort_by_yaw=False, sort_by_yaw_target_samples_path=None, with_close_to_self=False, sample_process_options=SampleProcessor.Options(), output_sample_types=[], add_sample_idx=False, generators_count=2, **kwargs):
def __init__ (self, samples_path, debug, batch_size, sort_by_yaw=False, sort_by_yaw_target_samples_path=None, with_close_to_self=False, sample_process_options=SampleProcessor.Options(), output_sample_types=[], add_sample_idx=False, add_pitch=False, add_yaw=False, generators_count=2, **kwargs):
super().__init__(samples_path, debug, batch_size)
self.sample_process_options = sample_process_options
self.output_sample_types = output_sample_types
self.add_sample_idx = add_sample_idx
self.add_pitch = add_pitch
self.add_yaw = add_yaw
if sort_by_yaw_target_samples_path is not None:
self.sample_type = SampleType.FACE_YAW_SORTED_AS_TARGET
@ -131,17 +134,33 @@ class SampleGeneratorFace(SampleGeneratorBase):
if type(x) != tuple and type(x) != list:
raise Exception('SampleProcessor.process returns NOT tuple/list')
if batches is None:
batches = [ [] for _ in range(len(x)) ]
if self.add_sample_idx:
batches += [ [] ]
i_sample_idx = len(batches)-1
if self.add_pitch:
batches += [ [] ]
i_pitch = len(batches)-1
if self.add_yaw:
batches += [ [] ]
i_yaw = len(batches)-1
for i in range(len(x)):
batches[i].append ( x[i] )
if self.add_sample_idx:
batches[-1].append (idx)
batches[i_sample_idx].append (idx)
if self.add_pitch or self.add_yaw:
pitch, yaw = LandmarksProcessor.estimate_pitch_yaw (sample.landmarks)
if self.add_pitch:
batches[i_pitch].append (pitch)
if self.add_yaw:
batches[i_yaw].append (yaw)
break
yield [ np.array(batch) for batch in batches]

View file

@ -67,12 +67,15 @@ class SampleLoader:
else:
print ("%s is not a dfl image file required for training" % (s_filename_path.name) )
continue
pitch, yaw = LandmarksProcessor.estimate_pitch_yaw ( dflimg.get_landmarks() )
sample_list.append( s.copy_and_set(sample_type=SampleType.FACE,
face_type=FaceType.fromString (dflimg.get_face_type()),
shape=dflimg.get_shape(),
landmarks=dflimg.get_landmarks(),
yaw=dflimg.get_yaw_value()) )
pitch=pitch,
yaw=yaw) )
except:
print ("Unable to load %s , error: %s" % (str(s_filename_path), traceback.format_exc() ) )
@ -114,7 +117,7 @@ class SampleLoader:
@staticmethod
def upgradeToFaceYawSortedSamples( samples ):
lowest_yaw, highest_yaw = -256, +256
lowest_yaw, highest_yaw = -1.0, 1.0
gradations = 64
diff_rot_per_grad = abs(highest_yaw-lowest_yaw) / gradations