sort tool: Add sort by roll

This commit is contained in:
torzdf 2022-09-23 14:18:48 +01:00
parent 1c8eb24b38
commit a7d0898f64
8 changed files with 124 additions and 76 deletions

View File

@ -5,7 +5,7 @@ from dataclasses import dataclass, field
import logging
import sys
from threading import Lock
from typing import Dict, Optional, Tuple
from typing import cast, Dict, Optional, Tuple
import cv2
@ -674,7 +674,7 @@ class PoseEstimate():
self._camera_matrix = self._get_camera_matrix()
self._rotation, self._translation = self._solve_pnp(landmarks)
self._offset = self._get_offset()
self._pitch_yaw: Tuple[int, int] = (0, 0)
self._pitch_yaw_roll: Tuple[float, float, float] = (0, 0, 0)
@property
def xyz_2d(self) -> np.ndarray:
@ -701,24 +701,31 @@ class PoseEstimate():
@property
def pitch(self) -> float:
""" float: The pitch of the aligned face in eular angles """
if not any(self._pitch_yaw):
self._get_pitch_yaw()
return self._pitch_yaw[0]
if not any(self._pitch_yaw_roll):
self._get_pitch_yaw_roll()
return self._pitch_yaw_roll[0]
@property
def yaw(self) -> float:
""" float: The yaw of the aligned face in eular angles """
if not any(self._pitch_yaw):
self._get_pitch_yaw()
return self._pitch_yaw[1]
if not any(self._pitch_yaw_roll):
self._get_pitch_yaw_roll()
return self._pitch_yaw_roll[1]
def _get_pitch_yaw(self) -> None:
""" Obtain the yaw and pitch from the :attr:`_rotation` in eular angles. """
@property
def roll(self) -> float:
""" float: The roll of the aligned face in eular angles """
if not any(self._pitch_yaw_roll):
self._get_pitch_yaw_roll()
return self._pitch_yaw_roll[2]
def _get_pitch_yaw_roll(self) -> None:
""" Obtain the yaw, roll and pitch from the :attr:`_rotation` in eular angles. """
proj_matrix = np.zeros((3, 4), dtype="float32")
proj_matrix[:3, :3] = cv2.Rodrigues(self._rotation)[0]
euler = cv2.decomposeProjectionMatrix(proj_matrix)[-1]
self._pitch_yaw = (euler[0][0], euler[1][0])
logger.trace("yaw_pitch: %s", self._pitch_yaw) # type: ignore
self._pitch_yaw_roll = cast(Tuple[float, float, float], tuple(euler.squeeze()))
logger.trace("yaw_pitch: %s", self._pitch_yaw_roll) # type: ignore
@classmethod
def _get_camera_matrix(cls) -> np.ndarray:

View File

@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: faceswap.spanish\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-09-21 00:58+0100\n"
"PO-Revision-Date: 2022-09-21 00:59+0100\n"
"POT-Creation-Date: 2022-09-23 14:16+0100\n"
"PO-Revision-Date: 2022-09-23 14:16+0100\n"
"Last-Translator: \n"
"Language-Team: tokafondo\n"
"Language: es_ES\n"
@ -107,21 +107,31 @@ msgid "faces by Pitch (rotation up and down)."
msgstr "caras por Pitch (rotación arriba y abajo)."
#: tools/sort/cli.py:43
msgid ""
"faces by Roll (rotation). Aligned faces should have a roll value close to "
"zero. The further the Roll value from zero the higher liklihood the face is "
"misaligned."
msgstr ""
"caras por Roll (rotación). Las caras alineadas deben tener un valor de "
"balanceo cercano a cero. Cuanto más lejos esté el valor de Roll de cero, "
"mayor será la probabilidad de que la cara esté desalineada."
#: tools/sort/cli.py:45
msgid "faces by their color histogram."
msgstr "caras por su histograma de color."
#: tools/sort/cli.py:44
#: tools/sort/cli.py:46
msgid "Like 'hist' but sorts by dissimilarity."
msgstr "Como 'hist' pero ordenada por la disimilitud."
#: tools/sort/cli.py:45
#: tools/sort/cli.py:47
msgid ""
"images by the average intensity of the converted grayscale color channel."
msgstr ""
"imágenes por la intensidad media del canal de color en escala de grises "
"convertido."
#: tools/sort/cli.py:46
#: tools/sort/cli.py:48
msgid ""
"images by their number of black pixels. Useful when faces are near borders "
"and a large part of the image is black."
@ -129,7 +139,7 @@ msgstr ""
"imágenes por su número de píxeles negros. Útil cuando las caras están cerca "
"de los bordes y una gran parte de la imagen es negra."
#: tools/sort/cli.py:48
#: tools/sort/cli.py:50
msgid ""
"images by the average intensity of the converted Y color channel. Bright "
"lighting and oversaturated images will be ranked first."
@ -138,7 +148,7 @@ msgstr ""
"iluminación brillante y las imágenes sobresaturadas se clasificarán en "
"primer lugar."
#: tools/sort/cli.py:50
#: tools/sort/cli.py:52
msgid ""
"images by the average intensity of the converted Cg color channel. Green "
"images will be ranked first and red images will be last."
@ -147,7 +157,7 @@ msgstr ""
"imágenes verdes se clasificarán primero y las imágenes rojas serán las "
"últimas."
#: tools/sort/cli.py:52
#: tools/sort/cli.py:54
msgid ""
"images by the average intensity of the converted Co color channel. Orange "
"images will be ranked first and blue images will be last."
@ -156,7 +166,7 @@ msgstr ""
"imágenes naranjas se clasificarán en primer lugar y las imágenes azules en "
"último lugar."
#: tools/sort/cli.py:54
#: tools/sort/cli.py:56
msgid ""
"images by their size in the original frame. Faces further from the camera "
"and from lower resolution sources will be sorted first, whilst faces closer "
@ -167,28 +177,28 @@ msgstr ""
"las caras más cercanas a la cámara y de fuentes de mayor resolución se "
"ordenarán en último lugar."
#: tools/sort/cli.py:57
#: tools/sort/cli.py:59
msgid " option is deprecated. Use 'yaw'"
msgstr " la opción está en desuso. Usa 'yaw'"
#: tools/sort/cli.py:58
#: tools/sort/cli.py:60
msgid " option is deprecated. Use 'color-black'"
msgstr " la opción está en desuso. Usa 'color-black'"
#: tools/sort/cli.py:80
#: tools/sort/cli.py:82
msgid "Sort faces using a number of different techniques"
msgstr "Clasificar los rostros mediante diferentes técnicas"
#: tools/sort/cli.py:90 tools/sort/cli.py:97 tools/sort/cli.py:108
#: tools/sort/cli.py:146
#: tools/sort/cli.py:92 tools/sort/cli.py:99 tools/sort/cli.py:110
#: tools/sort/cli.py:148
msgid "data"
msgstr "datos"
#: tools/sort/cli.py:91
#: tools/sort/cli.py:93
msgid "Input directory of aligned faces."
msgstr "Directorio de entrada de caras alineadas."
#: tools/sort/cli.py:98
#: tools/sort/cli.py:100
msgid ""
"Output directory for sorted aligned faces. If not provided and 'keep' is "
"selected then a new folder called 'sorted' will be created within the input "
@ -202,7 +212,7 @@ msgstr ""
"selecciona 'keep', las imágenes se ordenarán en el lugar, sobrescribiendo el "
"contenido original de 'input_dir'"
#: tools/sort/cli.py:109
#: tools/sort/cli.py:111
msgid ""
"R|If selected then the input_dir should be a parent folder containing "
"multiple folders of faces you wish to sort. The faces will be output to "
@ -212,11 +222,11 @@ msgstr ""
"varias carpetas de caras que desea ordenar. Las caras se enviarán a "
"subcarpetas separadas en output_dir"
#: tools/sort/cli.py:118
#: tools/sort/cli.py:120
msgid "sort settings"
msgstr "ajustes de ordenación"
#: tools/sort/cli.py:120
#: tools/sort/cli.py:122
msgid ""
"R|Choose how images are sorted. Selecting a sort method gives the images a "
"new filename based on the order the image appears within the given method.\n"
@ -234,11 +244,11 @@ msgstr ""
"nombres de archivo originales. Seleccionar 'none' para 'sort-by' y 'group-"
"by' no hará nada"
#: tools/sort/cli.py:133 tools/sort/cli.py:160 tools/sort/cli.py:189
#: tools/sort/cli.py:135 tools/sort/cli.py:162 tools/sort/cli.py:191
msgid "group settings"
msgstr "ajustes de grupo"
#: tools/sort/cli.py:135
#: tools/sort/cli.py:137
msgid ""
"R|Selecting a group by method will move/copy files into numbered bins based "
"on the selected method.\n"
@ -252,7 +262,7 @@ msgstr ""
"by' seleccionado, pero no se agruparán, sino que se ordenarán en una sola "
"carpeta. Seleccionar 'none' para 'sort-by' y 'group-by' no hará nada"
#: tools/sort/cli.py:147
#: tools/sort/cli.py:149
msgid ""
"Whether to keep the original files in their original location. Choosing a "
"'sort-by' method means that the files have to be renamed. Selecting 'keep' "
@ -269,7 +279,7 @@ msgstr ""
"moverán y cambiarán de nombre en función de los criterios de clasificación/"
"grupo seleccionados."
#: tools/sort/cli.py:162
#: tools/sort/cli.py:164
msgid ""
"R|Float value. Minimum threshold to use for grouping comparison with 'face-"
"cnn' 'hist' and 'face' methods.\n"
@ -296,11 +306,11 @@ msgstr ""
"de muchas carpetas. Valores predeterminados: face-cnn 7.2, hist 0.3, face "
"0.25"
#: tools/sort/cli.py:179
#: tools/sort/cli.py:181
msgid "output"
msgstr "salida"
#: tools/sort/cli.py:180
#: tools/sort/cli.py:182
msgid ""
"Deprecated and no longer used. The final processing will be dictated by the "
"sort/group by methods and whether 'keep_original' is selected."
@ -308,7 +318,7 @@ msgstr ""
"En desuso y ya no se usa. El procesamiento final será dictado por los "
"métodos de ordenación/agrupación y si se selecciona 'keepl'."
#: tools/sort/cli.py:191
#: tools/sort/cli.py:193
#, python-format
msgid ""
"R|Integer value. Used to control the number of bins created for grouping by: "
@ -354,11 +364,11 @@ msgstr ""
"pueden estar vacíos si las caras no se ajustan a los criterios.\n"
"Valor predeterminado: 5"
#: tools/sort/cli.py:213 tools/sort/cli.py:223
#: tools/sort/cli.py:215 tools/sort/cli.py:225
msgid "settings"
msgstr "ajustes"
#: tools/sort/cli.py:215
#: tools/sort/cli.py:217
msgid ""
"Logs file renaming changes if grouping by renaming, or it logs the file "
"copying/movement if grouping by folders. If no log file is specified with "
@ -370,7 +380,7 @@ msgstr ""
"se especifica ningún archivo de registro con '--log-file', se creará un "
"archivo 'sort_log.json' en el directorio de entrada."
#: tools/sort/cli.py:226
#: tools/sort/cli.py:228
msgid ""
"Specify a log file to use for saving the renaming or grouping information. "
"If specified extension isn't 'json' or 'yaml', then json will be used as the "

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-09-21 00:58+0100\n"
"POT-Creation-Date: 2022-09-23 14:16+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -87,71 +87,78 @@ msgid "faces by Pitch (rotation up and down)."
msgstr ""
#: tools/sort/cli.py:43
msgid "faces by their color histogram."
msgstr ""
#: tools/sort/cli.py:44
msgid "Like 'hist' but sorts by dissimilarity."
msgid ""
"faces by Roll (rotation). Aligned faces should have a roll value close to "
"zero. The further the Roll value from zero the higher liklihood the face is "
"misaligned."
msgstr ""
#: tools/sort/cli.py:45
msgid "faces by their color histogram."
msgstr ""
#: tools/sort/cli.py:46
msgid "Like 'hist' but sorts by dissimilarity."
msgstr ""
#: tools/sort/cli.py:47
msgid ""
"images by the average intensity of the converted grayscale color channel."
msgstr ""
#: tools/sort/cli.py:46
#: tools/sort/cli.py:48
msgid ""
"images by their number of black pixels. Useful when faces are near borders "
"and a large part of the image is black."
msgstr ""
#: tools/sort/cli.py:48
#: tools/sort/cli.py:50
msgid ""
"images by the average intensity of the converted Y color channel. Bright "
"lighting and oversaturated images will be ranked first."
msgstr ""
#: tools/sort/cli.py:50
#: tools/sort/cli.py:52
msgid ""
"images by the average intensity of the converted Cg color channel. Green "
"images will be ranked first and red images will be last."
msgstr ""
#: tools/sort/cli.py:52
#: tools/sort/cli.py:54
msgid ""
"images by the average intensity of the converted Co color channel. Orange "
"images will be ranked first and blue images will be last."
msgstr ""
#: tools/sort/cli.py:54
#: tools/sort/cli.py:56
msgid ""
"images by their size in the original frame. Faces further from the camera "
"and from lower resolution sources will be sorted first, whilst faces closer "
"to the camera and from higher resolution sources will be sorted last."
msgstr ""
#: tools/sort/cli.py:57
#: tools/sort/cli.py:59
msgid " option is deprecated. Use 'yaw'"
msgstr ""
#: tools/sort/cli.py:58
#: tools/sort/cli.py:60
msgid " option is deprecated. Use 'color-black'"
msgstr ""
#: tools/sort/cli.py:80
#: tools/sort/cli.py:82
msgid "Sort faces using a number of different techniques"
msgstr ""
#: tools/sort/cli.py:90 tools/sort/cli.py:97 tools/sort/cli.py:108
#: tools/sort/cli.py:146
#: tools/sort/cli.py:92 tools/sort/cli.py:99 tools/sort/cli.py:110
#: tools/sort/cli.py:148
msgid "data"
msgstr ""
#: tools/sort/cli.py:91
#: tools/sort/cli.py:93
msgid "Input directory of aligned faces."
msgstr ""
#: tools/sort/cli.py:98
#: tools/sort/cli.py:100
msgid ""
"Output directory for sorted aligned faces. If not provided and 'keep' is "
"selected then a new folder called 'sorted' will be created within the input "
@ -160,18 +167,18 @@ msgid ""
"'input_dir'"
msgstr ""
#: tools/sort/cli.py:109
#: tools/sort/cli.py:111
msgid ""
"R|If selected then the input_dir should be a parent folder containing "
"multiple folders of faces you wish to sort. The faces will be output to "
"separate sub-folders in the output_dir"
msgstr ""
#: tools/sort/cli.py:118
#: tools/sort/cli.py:120
msgid "sort settings"
msgstr ""
#: tools/sort/cli.py:120
#: tools/sort/cli.py:122
msgid ""
"R|Choose how images are sorted. Selecting a sort method gives the images a "
"new filename based on the order the image appears within the given method.\n"
@ -181,11 +188,11 @@ msgid ""
"'none' for both 'sort-by' and 'group-by' will do nothing"
msgstr ""
#: tools/sort/cli.py:133 tools/sort/cli.py:160 tools/sort/cli.py:189
#: tools/sort/cli.py:135 tools/sort/cli.py:162 tools/sort/cli.py:191
msgid "group settings"
msgstr ""
#: tools/sort/cli.py:135
#: tools/sort/cli.py:137
msgid ""
"R|Selecting a group by method will move/copy files into numbered bins based "
"on the selected method.\n"
@ -194,7 +201,7 @@ msgid ""
"folder. Selecting 'none' for both 'sort-by' and 'group-by' will do nothing"
msgstr ""
#: tools/sort/cli.py:147
#: tools/sort/cli.py:149
msgid ""
"Whether to keep the original files in their original location. Choosing a "
"'sort-by' method means that the files have to be renamed. Selecting 'keep' "
@ -204,7 +211,7 @@ msgid ""
"criteria."
msgstr ""
#: tools/sort/cli.py:162
#: tools/sort/cli.py:164
msgid ""
"R|Float value. Minimum threshold to use for grouping comparison with 'face-"
"cnn' 'hist' and 'face' methods.\n"
@ -219,17 +226,17 @@ msgid ""
"face-cnn 7.2, hist 0.3, face 0.25"
msgstr ""
#: tools/sort/cli.py:179
#: tools/sort/cli.py:181
msgid "output"
msgstr ""
#: tools/sort/cli.py:180
#: tools/sort/cli.py:182
msgid ""
"Deprecated and no longer used. The final processing will be dictated by the "
"sort/group by methods and whether 'keep_original' is selected."
msgstr ""
#: tools/sort/cli.py:191
#: tools/sort/cli.py:193
#, python-format
msgid ""
"R|Integer value. Used to control the number of bins created for grouping by: "
@ -253,11 +260,11 @@ msgid ""
"Default value: 5"
msgstr ""
#: tools/sort/cli.py:213 tools/sort/cli.py:223
#: tools/sort/cli.py:215 tools/sort/cli.py:225
msgid "settings"
msgstr ""
#: tools/sort/cli.py:215
#: tools/sort/cli.py:217
msgid ""
"Logs file renaming changes if grouping by renaming, or it logs the file "
"copying/movement if grouping by folders. If no log file is specified with "
@ -265,7 +272,7 @@ msgid ""
"directory."
msgstr ""
#: tools/sort/cli.py:226
#: tools/sort/cli.py:228
msgid ""
"Specify a log file to use for saving the renaming or grouping information. "
"If specified extension isn't 'json' or 'yaml', then json will be used as the "

View File

@ -34,6 +34,8 @@ ignore_missing_imports = True
ignore_missing_imports = True
[mypy-scipy.*]
ignore_missing_imports = True
[mypy-sklearn.*]
ignore_missing_imports = True
[mypy-tensorflow.*]
ignore_missing_imports = True
[mypy-tensorflow_probability.*]

View File

@ -14,7 +14,7 @@ _ = _LANG.gettext
_HELPTEXT = _("This command lets you sort images using various methods.")
_SORT_METHODS = (
"none", "blur", "blur-fft", "distance", "face", "face-cnn", "face-cnn-dissim",
"yaw", "pitch", "hist", "hist-dissim", "color-black", "color-gray", "color-luma",
"yaw", "pitch", "roll", "hist", "hist-dissim", "color-black", "color-gray", "color-luma",
"color-green", "color-orange", "size", "face-yaw", "black-pixels")
_GPTHRESHOLD = _(" Adjust the '-t' ('--threshold') parameter to control the strength of grouping.")
@ -40,6 +40,8 @@ _METHOD_TEXT = {
"face-cnn-dissim": _("Like 'face-cnn' but sorts by dissimilarity."),
"yaw": _("faces by Yaw (rotation left to right)."),
"pitch": _("faces by Pitch (rotation up and down)."),
"roll": _("faces by Roll (rotation). Aligned faces should have a roll value close to zero. "
"The further the Roll value from zero the higher liklihood the face is misaligned."),
"hist": _("faces by their color histogram."),
"hist-dissim": _("Like 'hist' but sorts by dissimilarity."),
"color-gray": _("images by the average intensity of the converted grayscale color channel."),
@ -60,7 +62,7 @@ _METHOD_TEXT = {
_BIN_TYPES = [
(("face", "face-cnn", "face-cnn-dissim", "hist", "hist-dissim"), _GPTHRESHOLD),
(("color-black", "color-gray", "color-luma", "color-green", "color-orange"), _GPCOLOR),
(("yaw", "pitch"), _GPDEGREES),
(("yaw", "pitch", "roll"), _GPDEGREES),
(("blur", "blur-fft", "distance", "size"), _GPLINEAR)]
_SORT_HELP = ""
_GROUP_HELP = ""

View File

@ -18,7 +18,7 @@ from lib.serializer import Serializer, get_serializer_from_filename
from lib.utils import deprecation_warning
from .sort_methods import SortBlur, SortColor, SortFace, SortHistogram, SortMultiMethod
from .sort_methods_aligned import SortDistance, SortFaceCNN, SortPitch, SortSize, SortYaw
from .sort_methods_aligned import SortDistance, SortFaceCNN, SortPitch, SortSize, SortYaw, SortRoll
if TYPE_CHECKING:
from .sort_methods import SortMethod
@ -132,6 +132,7 @@ class _Sort(): # pylint:disable=too-few-public-methods
distance=SortDistance,
yaw=SortYaw,
pitch=SortPitch,
roll=SortRoll,
size=SortSize,
face=SortFace,
face_cnn=SortFaceCNN,

View File

@ -172,7 +172,7 @@ class SortPitch(SortAlignedMetric):
class SortYaw(SortPitch):
""" Sorting mechansim for sorting a face by yaw (left to right). Same logic as sort yaw, but
""" Sorting mechansim for sorting a face by yaw (left to right). Same logic as sort pitch, but
with different metric """
def _get_metric(self, aligned_face: AlignedFace) -> float:
""" Obtain the yaw metric for the given face
@ -190,6 +190,25 @@ class SortYaw(SortPitch):
return aligned_face.pose.yaw
class SortRoll(SortPitch):
""" Sorting mechansim for sorting a face by roll (rotation). Same logic as sort pitch, but
with different metric """
def _get_metric(self, aligned_face: AlignedFace) -> float:
""" Obtain the roll metric for the given face
Parameters
----------
aligned_face: :class:`lib.align.AlignedFace`
The aligned face to extract the metric from
Returns
-------
float
The yaw metric for the current face
"""
return aligned_face.pose.roll
class SortSize(SortAlignedMetric):
""" Sorting mechanism for sorting faces from small to large """
def _get_metric(self, aligned_face: AlignedFace) -> float: