diff --git a/apps/DeepFaceLive/backend/FaceDetector.py b/apps/DeepFaceLive/backend/FaceDetector.py index 9dc4378..2bd5dde 100644 --- a/apps/DeepFaceLive/backend/FaceDetector.py +++ b/apps/DeepFaceLive/backend/FaceDetector.py @@ -24,8 +24,14 @@ DetectorTypeNames = ['CenterFace', 'S3FD', 'YoloV5'] class FaceSortBy(IntEnum): LARGEST = 0 DIST_FROM_CENTER = 1 + LEFT_RIGHT = 2 + RIGHT_LEFT = 3 + TOP_BOTTOM = 4 + BOTTOM_TOP = 5 -FaceSortByNames = ['@FaceDetector.largest', '@FaceDetector.dist_from_center'] +FaceSortByNames = ['@FaceDetector.LARGEST', '@FaceDetector.DIST_FROM_CENTER', + '@FaceDetector.LEFT_RIGHT', '@FaceDetector.RIGHT_LEFT', + '@FaceDetector.TOP_BOTTOM', '@FaceDetector.BOTTOM_TOP' ] class FaceDetector(BackendHost): def __init__(self, weak_heap : BackendWeakHeap, @@ -234,7 +240,15 @@ class FaceDetectorWorker(BackendWorker): if detector_state.sort_by == FaceSortBy.LARGEST: rects = FRect.sort_by_area_size(rects) elif detector_state.sort_by == FaceSortBy.DIST_FROM_CENTER: - rects = FRect.sort_by_dist_from_center(rects) + rects = FRect.sort_by_dist_from_2D_point(rects, 0.5, 0.5) + elif detector_state.sort_by == FaceSortBy.LEFT_RIGHT: + rects = FRect.sort_by_dist_from_horizontal_point(rects, 0) + elif detector_state.sort_by == FaceSortBy.RIGHT_LEFT: + rects = FRect.sort_by_dist_from_horizontal_point(rects, 1) + elif detector_state.sort_by == FaceSortBy.TOP_BOTTOM: + rects = FRect.sort_by_dist_from_vertical_point(rects, 0) + elif detector_state.sort_by == FaceSortBy.BOTTOM_TOP: + rects = FRect.sort_by_dist_from_vertical_point(rects, 1) if len(rects) != 0: max_faces = detector_state.max_faces diff --git a/localization/localization.py b/localization/localization.py index 5200419..2b40a47 100644 --- a/localization/localization.py +++ b/localization/localization.py @@ -283,9 +283,9 @@ class Localization: 'zh-CN' : '排序'}, 'QFaceDetector.help.sort_by':{ - 'en-US' : 'Sort faces by method.', - 'ru-RU' : 'Сортировать лица по выбранному методу.', - 'zh-CN' : '人脸排序方法'}, + 'en-US' : 'Sort faces by method. For example, for "RIGHT TO LEFT" the Face ID 0 will be at the rightmost part of the screen.', + 'ru-RU' : 'Сортировать лица по выбранному методу. Например, для "СПРАВА НАЛЕВО" лица с идентификатором 0 будет находиться в самой правой части экрана.', + 'zh-CN' : '人脸排序方法 例如,对于 "从右到左",Face ID 0将在屏幕的最右边'}, 'QFaceDetector.temporal_smoothing':{ 'en-US' : 'Temporal smoothing', @@ -426,12 +426,12 @@ class Localization: 'en-US' : 'Adjust the combination of module devices to achieve higher fps or lower CPU usage.', 'ru-RU' : 'Настройте комбинации устройств модулей для достижения высоких кадр/сек либо снижения нагрузки на процессор.', 'zh-CN' : '调整模块设备的组合以实现更高的fps或更低的CPU使用率'}, - + 'QFaceSwapper.swap_all_faces':{ 'en-US' : 'Swap all faces', 'ru-RU' : 'Заменить все лица', 'zh-CN' : '改变所有面孔'}, - + 'QFaceSwapper.face_id':{ 'en-US' : 'Face ID', 'ru-RU' : 'Номер лица', @@ -672,16 +672,36 @@ class Localization: 'ru-RU' : 'Видео файл', 'zh-CN' : '视频文件'}, - 'FaceDetector.largest':{ + 'FaceDetector.LARGEST':{ 'en-US' : 'Largest', 'ru-RU' : 'Наибольшему', 'zh-CN' : '最大'}, - 'FaceDetector.dist_from_center':{ + 'FaceDetector.DIST_FROM_CENTER':{ 'en-US' : 'Dist from center', 'ru-RU' : 'Расстоянию от центра', 'zh-CN' : '离中心的距离'}, + 'FaceDetector.LEFT_RIGHT':{ + 'en-US' : 'From left to right', + 'ru-RU' : 'Слева направо', + 'zh-CN' : '从左至右'}, + + 'FaceDetector.RIGHT_LEFT':{ + 'en-US' : 'From right to left', + 'ru-RU' : 'Справа налево', + 'zh-CN' : '从右到左'}, + + 'FaceDetector.TOP_BOTTOM':{ + 'en-US' : 'From top to bottom', + 'ru-RU' : 'Сверху вниз', + 'zh-CN' : '从左至右'}, + + 'FaceDetector.BOTTOM_TOP':{ + 'en-US' : 'From bottom to top', + 'ru-RU' : 'Снизу вверх', + 'zh-CN' : '从下到上'}, + 'FaceSwapper.model_information':{ 'en-US' : 'Model information', 'ru-RU' : 'Информация о модели', diff --git a/xlib/face/FRect.py b/xlib/face/FRect.py index d4457f8..1dfa203 100644 --- a/xlib/face/FRect.py +++ b/xlib/face/FRect.py @@ -18,6 +18,10 @@ class FRect(IState): def __init__(self): self._pts : np.ndarray = None + def __repr__(self): return self.__str__() + def __str__(self): + return f'FRect: {self._pts}' + def restore_state(self, state : dict): self._pts = IState._restore_np_array( state.get('_pts', None) ) @@ -35,17 +39,43 @@ class FRect(IState): return rects @staticmethod - def sort_by_dist_from_center(rects : List['FRect']): + def sort_by_dist_from_2D_point(rects : List['FRect'], x, y): """ sort list of FRect by nearest distance from center to center of rects descent + + x,y in [0 .. 1.0] """ - c = np.float32([0.5,0.5]) + c = np.float32([x,y]) rects = [ (rect, npla.norm( rect.get_center_point()-c )) for rect in rects ] rects = sorted(rects, key=operator.itemgetter(1) ) rects = [ x[0] for x in rects] return rects + @staticmethod + def sort_by_dist_from_horizontal_point(rects : List['FRect'], x): + """ + sort list of FRect by nearest distance from center to center of rects descent + + x in [0 .. 1.0] + """ + rects = [ (rect, abs(rect.get_center_point()[0]-x) ) for rect in rects ] + rects = sorted(rects, key=operator.itemgetter(1) ) + rects = [ x[0] for x in rects] + return rects + + @staticmethod + def sort_by_dist_from_vertical_point(rects : List['FRect'], y): + """ + sort list of FRect by nearest distance from center to center of rects descent + + y in [0 .. 1.0] + """ + rects = [ (rect, abs(rect.get_center_point()[1]-y) ) for rect in rects ] + rects = sorted(rects, key=operator.itemgetter(1) ) + rects = [ x[0] for x in rects] + return rects + @staticmethod def from_4pts(pts : Iterable): """