bugfix: Alignment tool, auto-detect alignments

- Random linting and typing
This commit is contained in:
torzdf 2024-04-19 11:33:52 +01:00
parent d75898f718
commit 2bad105dc8
11 changed files with 258 additions and 210 deletions

View File

@ -579,7 +579,7 @@ def encode_image(image: np.ndarray,
Returns
-------
encoded_image: bytes
The image encoded into the correct file format
The image encoded into the correct file format as bytes
Example
-------
@ -591,10 +591,10 @@ def encode_image(image: np.ndarray,
raise ValueError("Metadata is only supported for .png and .tif images")
args = tuple() if encoding_args is None else encoding_args
retval = cv2.imencode(extension, image, args)[1]
retval = cv2.imencode(extension, image, args)[1].tobytes()
if metadata:
func = {".png": png_write_meta, ".tif": tiff_write_meta}[extension]
retval = func(retval.tobytes(), metadata) # type:ignore[arg-type]
retval = func(retval, metadata)
return retval
@ -624,7 +624,7 @@ def png_write_meta(image: bytes, data: PNGHeaderDict | dict[str, T.Any] | bytes)
return retval
def tiff_write_meta(image: bytes, data: dict[str, T.Any] | bytes) -> bytes:
def tiff_write_meta(image: bytes, data: PNGHeaderDict | dict[str, T.Any] | bytes) -> bytes:
""" Write Faceswap information to a tiff's image_description field.
Parameters

View File

@ -1,7 +1,6 @@
#!/usr/bin/env python3
""" Processes the augmentation of images for feeding into a Faceswap model. """
from __future__ import annotations
from dataclasses import dataclass
import logging
import typing as T
@ -11,6 +10,7 @@ import numpy as np
from scipy.interpolate import griddata
from lib.image import batch_convert_color
from lib.logger import parse_class_init
if T.TYPE_CHECKING:
from lib.config import ConfigValueType
@ -18,49 +18,152 @@ if T.TYPE_CHECKING:
logger = logging.getLogger(__name__)
@dataclass
class AugConstants:
class AugConstants: # pylint:disable=too-many-instance-attributes,too-few-public-methods
""" Dataclass for holding constants for Image Augmentation.
Parameters
----------
clahe_base_contrast: int
The base number for Contrast Limited Adaptive Histogram Equalization
clahe_chance: float
Probability to perform Contrast Limited Adaptive Histogram Equilization
clahe_max_size: int
Maximum clahe window size
lab_adjust: np.ndarray
Adjustment amounts for L*A*B augmentation
transform_rotation: int
Rotation range for transformations
transform_zoom: float
Zoom range for transformations
transform_shift: float
Shift range for transformations
warp_maps: :class:`numpy.ndarray`
The stacked (x, y) mappings for image warping
warp_pads: tuple
The padding to apply for image warping
warp_slices: slice
The slices for extracting a warped image
warp_lm_edge_anchors: :class:`numpy.ndarray`
The edge anchors for landmark based warping
warp_lm_grids: :class:`numpy.ndarray`
The grids for landmark based warping
config: dict[str, ConfigValueType]
The user training configuration options
pricessing_size: int:
The size of image to augment the data for
batch_size: int
The batch size that augmented data is being prepared for
"""
clahe_base_contrast: int
clahe_chance: float
clahe_max_size: int
lab_adjust: np.ndarray
transform_rotation: int
transform_zoom: float
transform_shift: float
warp_maps: np.ndarray
warp_pad: tuple[int, int]
warp_slices: slice
warp_lm_edge_anchors: np.ndarray
warp_lm_grids: np.ndarray
def __init__(self,
config: dict[str, ConfigValueType],
processing_size: int,
batch_size: int) -> None:
logger.debug(parse_class_init(locals()))
self.clahe_base_contrast: int = 0
"""int: The base number for Contrast Limited Adaptive Histogram Equalization"""
self.clahe_chance: float = 0.0
"""float: Probability to perform Contrast Limited Adaptive Histogram Equilization"""
self.clahe_max_size: int = 0
"""int: Maximum clahe window size"""
self.lab_adjust: np.ndarray
""":class:`numpy.ndarray`: Adjustment amounts for L*A*B augmentation"""
self.transform_rotation: int = 0
"""int: Rotation range for transformations"""
self.transform_zoom: float = 0.0
"""float: Zoom range for transformations"""
self.transform_shift: float = 0.0
"""float: Shift range for transformations"""
self.warp_maps: np.ndarray
""":class:`numpy.ndarray`The stacked (x, y) mappings for image warping"""
self.warp_pad: tuple[int, int] = (0, 0)
""":tuple[int, int]: The padding to apply for image warping"""
self.warp_slices: slice
""":slice: The slices for extracting a warped image"""
self.warp_lm_edge_anchors: np.ndarray
"""::class:`numpy.ndarray`: The edge anchors for landmark based warping"""
self.warp_lm_grids: np.ndarray
"""::class:`numpy.ndarray`: The grids for landmark based warping"""
self._config = config
self._size = processing_size
self._load_config(batch_size)
logger.debug("Initialized: %s", self.__class__.__name__)
def _load_clahe(self) -> None:
""" Load the CLAHE constants from user config """
color_clahe_chance = self._config.get("color_clahe_chance", 50)
color_clahe_max_size = self._config.get("color_clahe_max_size", 4)
assert isinstance(color_clahe_chance, int)
assert isinstance(color_clahe_max_size, int)
self.clahe_base_contrast = max(2, self._size // 128)
self.clahe_chance = color_clahe_chance / 100
self.clahe_max_size = color_clahe_max_size
logger.debug("clahe_base_contrast: %s, clahe_chance: %s, clahe_max_size: %s",
self.clahe_base_contrast, self.clahe_chance, self.clahe_max_size)
def _load_lab(self) -> None:
""" Load the random L*A*B augmentation constants """
color_lightness = self._config.get("color_lightness", 30)
color_ab = self._config.get("color_ab", 8)
assert isinstance(color_lightness, int)
assert isinstance(color_ab, int)
amount_l = int(color_lightness) / 100
amount_ab = int(color_ab) / 100
self.lab_adjust = np.array([amount_l, amount_ab, amount_ab], dtype="float32")
logger.debug("lab_adjust: %s", self.lab_adjust)
def _load_transform(self) -> None:
""" Load the random transform constants """
shift_range = self._config.get("shift_range", 5)
rotation_range = self._config.get("rotation_range", 10)
zoom_amount = self._config.get("zoom_amount", 5)
assert isinstance(shift_range, int)
assert isinstance(rotation_range, int)
assert isinstance(zoom_amount, int)
self.transform_shift = (shift_range / 100) * self._size
self.transform_rotation = rotation_range
self.transform_zoom = zoom_amount / 100
logger.debug("transform_shift: %s, transform_rotation: %s, transform_zoom: %s",
self.transform_shift, self.transform_rotation, self.transform_zoom)
def _load_warp(self, batch_size: int) -> None:
""" Load the warp augmentation constants
Parameters
----------
batch_size: int
The batch size that augmented data is being prepared for
"""
warp_range = np.linspace(0, self._size, 5, dtype='float32')
warp_mapx = np.broadcast_to(warp_range, (batch_size, 5, 5)).astype("float32")
warp_mapy = np.broadcast_to(warp_mapx[0].T, (batch_size, 5, 5)).astype("float32")
warp_pad = int(1.25 * self._size)
self.warp_maps = np.stack((warp_mapx, warp_mapy), axis=1)
self.warp_pad = (warp_pad, warp_pad)
self.warp_slices = slice(warp_pad // 10, -warp_pad // 10)
logger.debug("warp_maps: (%s, %s), warp_pad: %s, warp_slices: %s",
self.warp_maps.shape, self.warp_maps.dtype,
self.warp_pad, self.warp_slices)
def _load_warp_to_landmarks(self, batch_size: int) -> None:
""" Load the warp-to-landmarks augmentation constants
Parameters
----------
batch_size: int
The batch size that augmented data is being prepared for
"""
p_mx = self._size - 1
p_hf = (self._size // 2) - 1
edge_anchors = np.array([(0, 0), (0, p_mx), (p_mx, p_mx), (p_mx, 0),
(p_hf, 0), (p_hf, p_mx), (p_mx, p_hf), (0, p_hf)]).astype("int32")
edge_anchors = np.broadcast_to(edge_anchors, (batch_size, 8, 2))
grids = np.mgrid[0: p_mx: complex(self._size), # type:ignore[misc]
0: p_mx: complex(self._size)] # type:ignore[misc]
self.warp_lm_edge_anchors = edge_anchors
self.warp_lm_grids = grids
logger.debug("warp_lm_edge_anchors: (%s, %s), warp_lm_grids: (%s, %s)",
self.warp_lm_edge_anchors.shape, self.warp_lm_edge_anchors.dtype,
self.warp_lm_grids.shape, self.warp_lm_grids.dtype)
def _load_config(self, batch_size: int) -> None:
""" Load the constants into the class from user config
Parameters
----------
batch_size: int
The batch size that augmented data is being prepared for
"""
logger.debug("Loading augmentation constants")
self._load_clahe()
self._load_lab()
self._load_transform()
self._load_warp(batch_size)
self._load_warp_to_landmarks(batch_size)
logger.debug("Loaded augmentation constants")
class ImageAugmentation():
@ -68,7 +171,7 @@ class ImageAugmentation():
Parameters
----------
batchsize: int
batch_size: int
The number of images that will be fed through the augmentation functions at once.
processing_size: int
The largest input or output size of the model. This is the size that images are processed
@ -78,88 +181,25 @@ class ImageAugmentation():
plugin configuration options.
"""
def __init__(self,
batchsize: int,
batch_size: int,
processing_size: int,
config: dict[str, ConfigValueType]) -> None:
logger.debug("Initializing %s: (batchsize: %s, processing_size: %s, "
"config: %s)",
self.__class__.__name__, batchsize, processing_size, config)
logger.debug(parse_class_init(locals()))
self._processing_size = processing_size
self._batchsize = batchsize
self._config = config
self._batch_size = batch_size
# flip_args
flip_chance = config.get("random_flip", 50)
assert isinstance(flip_chance, int)
self._flip_chance = flip_chance
# Warp args
self._warp_scale = 5 / 256 * self._processing_size # Normal random variable scale
self._warp_lm_scale = 2 / 256 * self._processing_size # Normal random variable scale
self._constants = self._get_constants()
self._constants = AugConstants(config, processing_size, batch_size)
logger.debug("Initialized %s", self.__class__.__name__)
def _get_constants(self) -> AugConstants:
""" Initializes the caching of constants for use in various image augmentations.
Returns
-------
dict
Cached constants that are used for various augmentations
"""
logger.debug("Initializing constants.")
# Config variables typing check
shift_range = self._config.get("shift_range", 5)
color_lightness = self._config.get("color_lightness", 30)
color_ab = self._config.get("color_ab", 8)
color_clahe_chance = self._config.get("color_clahe_chance", 50)
color_clahe_max_size = self._config.get("color_clahe_max_size", 4)
rotation_range = self._config.get("rotation_range", 10)
zoom_amount = self._config.get("zoom_amount", 5)
assert isinstance(shift_range, int)
assert isinstance(color_lightness, int)
assert isinstance(color_ab, int)
assert isinstance(color_clahe_chance, int)
assert isinstance(color_clahe_max_size, int)
assert isinstance(rotation_range, int)
assert isinstance(zoom_amount, int)
# Transform
tform_shift = (shift_range / 100) * self._processing_size
# Color Aug
amount_l = int(color_lightness) / 100
amount_ab = int(color_ab) / 100
lab_adjust = np.array([amount_l, amount_ab, amount_ab], dtype="float32")
# Random Warp
warp_range = np.linspace(0, self._processing_size, 5, dtype='float32')
warp_mapx = np.broadcast_to(warp_range, (self._batchsize, 5, 5)).astype("float32")
warp_mapy = np.broadcast_to(warp_mapx[0].T, (self._batchsize, 5, 5)).astype("float32")
warp_pad = int(1.25 * self._processing_size)
# Random Warp Landmarks
p_mx = self._processing_size - 1
p_hf = (self._processing_size // 2) - 1
edge_anchors = np.array([(0, 0), (0, p_mx), (p_mx, p_mx), (p_mx, 0),
(p_hf, 0), (p_hf, p_mx), (p_mx, p_hf), (0, p_hf)]).astype("int32")
edge_anchors = np.broadcast_to(edge_anchors, (self._batchsize, 8, 2))
grids = np.mgrid[0: p_mx: complex(self._processing_size), # type: ignore
0: p_mx: complex(self._processing_size)] # type: ignore
retval = AugConstants(clahe_base_contrast=max(2, self._processing_size // 128),
clahe_chance=color_clahe_chance / 100,
clahe_max_size=color_clahe_max_size,
lab_adjust=lab_adjust,
transform_rotation=rotation_range,
transform_zoom=zoom_amount / 100,
transform_shift=tform_shift,
warp_maps=np.stack((warp_mapx, warp_mapy), axis=1),
warp_pad=(warp_pad, warp_pad),
warp_slices=slice(warp_pad // 10, -warp_pad // 10),
warp_lm_edge_anchors=edge_anchors,
warp_lm_grids=grids)
logger.debug("Initialized constants: %s", retval)
return retval
# <<< COLOR AUGMENTATION >>> #
def color_adjust(self, batch: np.ndarray) -> np.ndarray:
""" Perform color augmentation on the passed in batch.
@ -178,7 +218,7 @@ class ImageAugmentation():
A 4-dimensional array of the same shape as :attr:`batch` with color augmentation
applied.
"""
logger.trace("Augmenting color") # type: ignore
logger.trace("Augmenting color") # type:ignore[attr-defined]
batch = batch_convert_color(batch, "BGR2LAB")
self._random_lab(batch)
self._random_clahe(batch)
@ -190,7 +230,7 @@ class ImageAugmentation():
a batch of images """
base_contrast = self._constants.clahe_base_contrast
batch_random = np.random.rand(self._batchsize)
batch_random = np.random.rand(self._batch_size)
indices = np.where(batch_random < self._constants.clahe_chance)[0]
if not np.any(indices):
return
@ -198,9 +238,9 @@ class ImageAugmentation():
size=indices.shape[0],
dtype="uint8")
grid_sizes = (grid_bases * (base_contrast // 2)) + base_contrast
logger.trace("Adjusting Contrast. Grid Sizes: %s", grid_sizes) # type: ignore
logger.trace("Adjusting Contrast. Grid Sizes: %s", grid_sizes) # type:ignore[attr-defined]
clahes = [cv2.createCLAHE(clipLimit=2.0, # pylint:disable=no-member
clahes = [cv2.createCLAHE(clipLimit=2.0,
tileGridSize=(grid_size, grid_size))
for grid_size in grid_sizes]
@ -212,8 +252,8 @@ class ImageAugmentation():
images """
randoms = np.random.uniform(-self._constants.lab_adjust,
self._constants.lab_adjust,
size=(self._batchsize, 1, 1, 3)).astype("float32")
logger.trace("Random LAB adjustments: %s", randoms) # type: ignore
size=(self._batch_size, 1, 1, 3)).astype("float32")
logger.trace("Random LAB adjustments: %s", randoms) # type:ignore[attr-defined]
# Iterating through the images and channels is much faster than numpy.where and slightly
# faster than numexpr.where.
for image, rand in zip(batch, randoms):
@ -236,18 +276,18 @@ class ImageAugmentation():
The batch should be a 4-dimensional array of shape (`batchsize`, `height`, `width`,
`channels`) and in `BGR` format.
"""
logger.trace("Randomly transforming image") # type: ignore
logger.trace("Randomly transforming image") # type:ignore[attr-defined]
rotation = np.random.uniform(-self._constants.transform_rotation,
self._constants.transform_rotation,
size=self._batchsize).astype("float32")
size=self._batch_size).astype("float32")
scale = np.random.uniform(1 - self._constants.transform_zoom,
1 + self._constants.transform_zoom,
size=self._batchsize).astype("float32")
size=self._batch_size).astype("float32")
tform = np.random.uniform(-self._constants.transform_shift,
self._constants.transform_shift,
size=(self._batchsize, 2)).astype("float32")
size=(self._batch_size, 2)).astype("float32")
mats = np.array(
[cv2.getRotationMatrix2D((self._processing_size // 2, self._processing_size // 2),
rot,
@ -262,7 +302,7 @@ class ImageAugmentation():
dst=image,
borderMode=cv2.BORDER_REPLICATE)
logger.trace("Randomly transformed image") # type: ignore
logger.trace("Randomly transformed image") # type:ignore[attr-defined]
def random_flip(self, batch: np.ndarray):
""" Perform random horizontal flipping on the passed in batch.
@ -275,14 +315,12 @@ class ImageAugmentation():
The batch should be a 4-dimensional array of shape (`batchsize`, `height`, `width`,
`channels`) and in `BGR` format.
"""
logger.trace("Randomly flipping image") # type: ignore
randoms = np.random.rand(self._batchsize)
flip_chance = self._config.get("random_flip", 50)
assert isinstance(flip_chance, int)
indices = np.where(randoms > flip_chance / 100)[0]
logger.trace("Randomly flipping image") # type:ignore[attr-defined]
randoms = np.random.rand(self._batch_size)
indices = np.where(randoms <= self._flip_chance / 100)[0]
batch[indices] = batch[indices, :, ::-1]
logger.trace("Randomly flipped %s images of %s", # type: ignore
len(indices), self._batchsize)
logger.trace("Randomly flipped %s images of %s", # type:ignore[attr-defined]
len(indices), self._batch_size)
def warp(self, batch: np.ndarray, to_landmarks: bool = False, **kwargs) -> np.ndarray:
""" Perform random warping on the passed in batch by one of two methods.
@ -329,9 +367,9 @@ class ImageAugmentation():
:class:`numpy.ndarray`
A 4-dimensional array of the same shape as :attr:`batch` with warping applied.
"""
logger.trace("Randomly warping batch") # type: ignore
logger.trace("Randomly warping batch") # type:ignore[attr-defined]
slices = self._constants.warp_slices
rands = np.random.normal(size=(self._batchsize, 2, 5, 5),
rands = np.random.normal(size=(self._batch_size, 2, 5, 5),
scale=self._warp_scale).astype("float32")
batch_maps = ne.evaluate("m + r", local_dict={"m": self._constants.warp_maps, "r": rands})
batch_interp = np.array([[cv2.resize(map_, self._constants.warp_pad)[slices, slices]
@ -340,7 +378,7 @@ class ImageAugmentation():
warped_batch = np.array([cv2.remap(image, interp[0], interp[1], cv2.INTER_LINEAR)
for image, interp in zip(batch, batch_interp)])
logger.trace("Warped image shape: %s", warped_batch.shape) # type: ignore
logger.trace("Warped image shape: %s", warped_batch.shape) # type:ignore[attr-defined]
return warped_batch
def _random_warp_landmarks(self,
@ -364,7 +402,7 @@ class ImageAugmentation():
:class:`numpy.ndarray`
A 4-dimensional array of the same shape as :attr:`batch` with warping applied.
"""
logger.trace("Randomly warping landmarks") # type: ignore
logger.trace("Randomly warping landmarks") # type:ignore[attr-defined]
edge_anchors = self._constants.warp_lm_edge_anchors
grids = self._constants.warp_lm_grids
@ -389,15 +427,16 @@ class ImageAugmentation():
grid_z = np.array([griddata(dst, src, (grids[0], grids[1]), method="linear")
for src, dst in zip(lbatch_src, lbatch_dst)])
maps = grid_z.reshape((self._batchsize,
maps = grid_z.reshape((self._batch_size,
self._processing_size,
self._processing_size,
2)).astype("float32")
warped_batch = np.array([cv2.remap(image,
map_[..., 1],
map_[..., 0],
cv2.INTER_LINEAR,
cv2.BORDER_TRANSPARENT)
borderMode=cv2.BORDER_TRANSPARENT)
for image, map_ in zip(batch, maps)])
logger.trace("Warped batch shape: %s", warped_batch.shape) # type: ignore
logger.trace("Warped batch shape: %s", warped_batch.shape) # type:ignore[attr-defined]
return warped_batch

View File

@ -57,7 +57,7 @@ class DataGenerator():
side: T.Literal["a", "b"],
images: list[str],
batch_size: int) -> None:
logger.debug("Initializing %s: (model: %s, side: %s, images: %s , " # type: ignore
logger.debug("Initializing %s: (model: %s, side: %s, images: %s , "
"batch_size: %s, config: %s)", self.__class__.__name__, model.name, side,
len(images), batch_size, config)
self._config = config
@ -243,7 +243,8 @@ class DataGenerator():
raw_faces = read_image_batch(filenames)
detected_faces = self._face_cache.get_items(filenames)
logger.trace("filenames: %s, raw_faces: '%s', detected_faces: %s", # type: ignore
logger.trace( # type:ignore[attr-defined]
"filenames: %s, raw_faces: '%s', detected_faces: %s",
filenames, raw_faces.shape, len(detected_faces))
return raw_faces, detected_faces
@ -271,8 +272,8 @@ class DataGenerator():
batch: :class:`np.ndarray`
The pre-allocated array to hold this batch
"""
logger.trace("Cropping training images info: (filenames: %s, side: '%s')", # type: ignore
filenames, self._side)
logger.trace( # type:ignore[attr-defined]
"Cropping training images info: (filenames: %s, side: '%s')", filenames, self._side)
with futures.ThreadPoolExecutor() as executor:
proc = {executor.submit(face.aligned.extract_face, img): idx
@ -304,7 +305,7 @@ class DataGenerator():
masks = np.array([face.get_training_masks() for face in detected_faces])
batch[..., 3:] = masks
logger.trace("side: %s, masks: %s, batch: %s", # type: ignore
logger.trace("side: %s, masks: %s, batch: %s", # type:ignore[attr-defined]
self._side, masks.shape, batch.shape)
def _process_batch(self, filenames: list[str]) -> BatchType:
@ -333,9 +334,9 @@ class DataGenerator():
self._apply_mask(detected_faces, batch)
feed, targets = self.process_batch(filenames, raw_faces, detected_faces, batch)
logger.trace("Processed %s batch side %s. (filenames: %s, feed: %s, " # type: ignore
"targets: %s)", self.__class__.__name__, self._side, filenames,
feed.shape, [t.shape for t in targets])
logger.trace( # type:ignore[attr-defined]
"Processed %s batch side %s. (filenames: %s, feed: %s, targets: %s)",
self.__class__.__name__, self._side, filenames, feed.shape, [t.shape for t in targets])
return feed, targets
@ -450,15 +451,19 @@ class TrainingDataGenerator(DataGenerator):
List of 4-dimensional target images, at all model output sizes, with masks compiled
into channels 4+ for each output size
"""
logger.trace("Compiling targets: batch shape: %s", batch.shape) # type: ignore
logger.trace("Compiling targets: batch shape: %s", # type:ignore[attr-defined]
batch.shape)
if len(self._output_sizes) == 1 and self._output_sizes[0] == self._process_size:
# Rolling buffer here makes next to no difference, so just create array on the fly
retval = [self._to_float32(batch)]
else:
retval = [self._to_float32(np.array([cv2.resize(image, (size, size), cv2.INTER_AREA)
retval = [self._to_float32(np.array([cv2.resize(image,
(size, size),
interpolation=cv2.INTER_AREA)
for image in batch]))
for size in self._output_sizes]
logger.trace("Processed targets: %s", [t.shape for t in retval]) # type: ignore
logger.trace("Processed targets: %s", # type:ignore[attr-defined]
[t.shape for t in retval])
return retval
def process_batch(self,
@ -533,7 +538,7 @@ class TrainingDataGenerator(DataGenerator):
feed = self._to_float32(np.array([cv2.resize(image,
(self._model_input_size,
self._model_input_size),
cv2.INTER_AREA)
interpolation=cv2.INTER_AREA)
for image in warped]))
else:
feed = self._to_float32(warped)
@ -556,8 +561,9 @@ class TrainingDataGenerator(DataGenerator):
:class:`np.ndarray`
Randomly selected closest matches from the other side's landmarks
"""
logger.trace("Retrieving closest matched landmarks: (filenames: '%s', " # type: ignore
"src_points: '%s')", filenames, batch_src_points)
logger.trace( # type:ignore[attr-defined]
"Retrieving closest matched landmarks: (filenames: '%s', src_points: '%s')",
filenames, batch_src_points)
lm_side: T.Literal["a", "b"] = "a" if self._side == "b" else "b"
other_cache = get_cache(lm_side)
landmarks = other_cache.aligned_landmarks
@ -575,7 +581,8 @@ class TrainingDataGenerator(DataGenerator):
closest_matches = self._cache_closest_matches(filenames, batch_src_points, landmarks)
batch_dst_points = np.array([landmarks[choice(fname)] for fname in closest_matches])
logger.trace("Returning: (batch_dst_points: %s)", batch_dst_points.shape) # type: ignore
logger.trace("Returning: (batch_dst_points: %s)", # type:ignore[attr-defined]
batch_dst_points.shape)
return batch_dst_points
def _cache_closest_matches(self,
@ -648,7 +655,8 @@ class PreviewDataGenerator(DataGenerator):
list
List of 4-dimensional target images, at final model output size
"""
logger.trace("Compiling samples: images shape: %s, detected_faces: %s ", # type: ignore
logger.trace( # type:ignore[attr-defined]
"Compiling samples: images shape: %s, detected_faces: %s ",
images.shape, len(detected_faces))
output_size = self._output_sizes[-1]
full_size = 2 * int(np.rint((output_size / self._coverage_ratio) / 2))
@ -665,7 +673,7 @@ class PreviewDataGenerator(DataGenerator):
is_aligned=True).face
for idx, face in enumerate(detected_faces)]))
logger.trace("Processed samples: %s", retval.shape) # type: ignore
logger.trace("Processed samples: %s", retval.shape) # type:ignore[attr-defined]
return [retval]
def process_batch(self,
@ -840,7 +848,8 @@ class Feeder():
side_feed, side_targets = next(self._feeds[side])
if self._model.config["learn_mask"]: # Add the face mask as it's own target
side_targets += [side_targets[-1][..., 3][..., None]]
logger.trace("side: %s, input_shapes: %s, target_shapes: %s", # type: ignore
logger.trace( # type:ignore[attr-defined]
"side: %s, input_shapes: %s, target_shapes: %s",
side, side_feed.shape, [i.shape for i in side_targets])
model_inputs.append([side_feed])
model_targets.append(side_targets)

View File

@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: faceswap.spanish\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-12 12:10+0100\n"
"PO-Revision-Date: 2024-04-12 12:14+0100\n"
"POT-Creation-Date: 2024-04-19 11:28+0100\n"
"PO-Revision-Date: 2024-04-19 11:29+0100\n"
"Last-Translator: \n"
"Language-Team: tokafondo\n"
"Language: es_ES\n"
@ -37,29 +37,29 @@ msgstr ""
"archivo de alineación."
#: tools/alignments/cli.py:43
msgid " Must Pass in a frames folder/source video file (-fr)."
msgid " Must Pass in a frames folder/source video file (-r)."
msgstr ""
" Debe indicar una carpeta de fotogramas o archivo de vídeo de origen (-fr)."
" Debe indicar una carpeta de fotogramas o archivo de vídeo de origen (-r)."
#: tools/alignments/cli.py:44
msgid " Must Pass in a faces folder (-fc)."
msgstr " Debe indicar una carpeta de caras (-fc)."
msgid " Must Pass in a faces folder (-c)."
msgstr " Debe indicar una carpeta de caras (-c)."
#: tools/alignments/cli.py:45
msgid ""
" Must Pass in either a frames folder/source video file OR a faces folder (-"
"fr or -fc)."
" Must Pass in either a frames folder/source video file OR a faces folder (-r "
"or -c)."
msgstr ""
" Debe indicar una carpeta de fotogramas o archivo de vídeo de origen, o una "
"carpeta de caras (-fr o -fc)."
"carpeta de caras (-r o -c)."
#: tools/alignments/cli.py:47
msgid ""
" Must Pass in a frames folder/source video file AND a faces folder (-fr and -"
"fc)."
" Must Pass in a frames folder/source video file AND a faces folder (-r and -"
"c)."
msgstr ""
" Debe indicar una carpeta de fotogramas o archivo de vídeo de origen, y una "
"carpeta de caras (-fr y -fc)."
"carpeta de caras (-r y -c)."
#: tools/alignments/cli.py:49
msgid " Use the output option (-o) to process results."

View File

@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-12 12:10+0100\n"
"PO-Revision-Date: 2024-04-12 12:17+0100\n"
"POT-Creation-Date: 2024-04-19 11:28+0100\n"
"PO-Revision-Date: 2024-04-19 11:30+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: ko_KR\n"
@ -35,29 +35,29 @@ msgstr ""
"용하거나 여러 작업을 수행할 수 있습니다."
#: tools/alignments/cli.py:43
msgid " Must Pass in a frames folder/source video file (-fr)."
msgid " Must Pass in a frames folder/source video file (-r)."
msgstr ""
" 프레임들이 저장된 폴더나 원본 비디오 파일을 무조건 전달해야 합니다 (-fr)."
" 프레임들이 저장된 폴더나 원본 비디오 파일을 무조건 전달해야 합니다 (-r)."
#: tools/alignments/cli.py:44
msgid " Must Pass in a faces folder (-fc)."
msgstr " 얼굴 폴더를 무조건 전달해야 합니다 (-fc)."
msgid " Must Pass in a faces folder (-c)."
msgstr " 얼굴 폴더를 무조건 전달해야 합니다 (-c)."
#: tools/alignments/cli.py:45
msgid ""
" Must Pass in either a frames folder/source video file OR a faces folder (-"
"fr or -fc)."
" Must Pass in either a frames folder/source video file OR a faces folder (-r "
"or -c)."
msgstr ""
" 프레임 폴더나 원본 비디오 파일 또는 얼굴 폴더중 하나를 무조건 전달해야 합니"
"다 (-fr and -fc)."
"다 (-r and -c)."
#: tools/alignments/cli.py:47
msgid ""
" Must Pass in a frames folder/source video file AND a faces folder (-fr and -"
"fc)."
" Must Pass in a frames folder/source video file AND a faces folder (-r and -"
"c)."
msgstr ""
" 프레임 폴더나 원본 비디오 파일 그리고 얼굴 폴더를 무조건 전달해야 합니다 (-"
"fr and -fc)."
"r and -c)."
#: tools/alignments/cli.py:49
msgid " Use the output option (-o) to process results."

View File

@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-12 12:10+0100\n"
"PO-Revision-Date: 2024-04-12 12:13+0100\n"
"POT-Creation-Date: 2024-04-19 11:28+0100\n"
"PO-Revision-Date: 2024-04-19 11:31+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: ru\n"
@ -38,28 +38,28 @@ msgstr ""
"кадров."
#: tools/alignments/cli.py:43
msgid " Must Pass in a frames folder/source video file (-fr)."
msgstr " Должен проходить в папке с кадрами/исходным видеофайлом (-fr)."
msgid " Must Pass in a frames folder/source video file (-r)."
msgstr " Должен проходить в папке с кадрами/исходным видеофайлом (-r)."
#: tools/alignments/cli.py:44
msgid " Must Pass in a faces folder (-fc)."
msgstr " Должен проходить в папке с лицами (-fc)."
msgid " Must Pass in a faces folder (-c)."
msgstr " Должен проходить в папке с лицами (-c)."
#: tools/alignments/cli.py:45
msgid ""
" Must Pass in either a frames folder/source video file OR a faces folder (-"
"fr or -fc)."
" Must Pass in either a frames folder/source video file OR a faces folder (-r "
"or -c)."
msgstr ""
" Должно передаваться либо в папку с кадрами/исходным видеофайлом, либо в "
"папку с лицами (-fr или -fc)."
"папку с лицами (-r или -c)."
#: tools/alignments/cli.py:47
msgid ""
" Must Pass in a frames folder/source video file AND a faces folder (-fr and -"
"fc)."
" Must Pass in a frames folder/source video file AND a faces folder (-r and -"
"c)."
msgstr ""
" Должно передаваться либо в папку с кадрами/исходным видеофайлом И в папку с "
"лицами (-fr и -fc)."
"лицами (-r и -c)."
#: tools/alignments/cli.py:49
msgid " Use the output option (-o) to process results."

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-12 12:10+0100\n"
"POT-Creation-Date: 2024-04-19 11:28+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"
@ -30,23 +30,23 @@ msgid ""
msgstr ""
#: tools/alignments/cli.py:43
msgid " Must Pass in a frames folder/source video file (-fr)."
msgid " Must Pass in a frames folder/source video file (-r)."
msgstr ""
#: tools/alignments/cli.py:44
msgid " Must Pass in a faces folder (-fc)."
msgid " Must Pass in a faces folder (-c)."
msgstr ""
#: tools/alignments/cli.py:45
msgid ""
" Must Pass in either a frames folder/source video file OR a faces folder (-"
"fr or -fc)."
" Must Pass in either a frames folder/source video file OR a faces folder (-r "
"or -c)."
msgstr ""
#: tools/alignments/cli.py:47
msgid ""
" Must Pass in a frames folder/source video file AND a faces folder (-fr and -"
"fc)."
" Must Pass in a frames folder/source video file AND a faces folder (-r and -"
"c)."
msgstr ""
#: tools/alignments/cli.py:49

View File

@ -40,12 +40,12 @@ class AlignmentsArgs(FaceSwapArgs):
dict
The argparse command line options for processing by argparse
"""
frames_dir = _(" Must Pass in a frames folder/source video file (-fr).")
faces_dir = _(" Must Pass in a faces folder (-fc).")
frames_dir = _(" Must Pass in a frames folder/source video file (-r).")
faces_dir = _(" Must Pass in a faces folder (-c).")
frames_or_faces_dir = _(" Must Pass in either a frames folder/source video file OR a "
"faces folder (-fr or -fc).")
"faces folder (-r or -c).")
frames_and_faces_dir = _(" Must Pass in a frames folder/source video file AND a faces "
"folder (-fr and -fc).")
"folder (-r and -c).")
output_opts = _(" Use the output option (-o) to process results.")
argument_list = []
argument_list.append({
@ -118,7 +118,7 @@ class AlignmentsArgs(FaceSwapArgs):
"group": _("data"),
# hacky solution to not require alignments file if creating alignments from faces:
"required": not any(val in sys.argv for val in ["from-faces",
"-fr",
"-r",
"-frames_folder"]),
"filetypes": "alignments",
"help": _(