From 2bad105dc8500ad667d7ff311dcf6f9d396ed1c8 Mon Sep 17 00:00:00 2001 From: torzdf <36920800+torzdf@users.noreply.github.com> Date: Fri, 19 Apr 2024 11:33:52 +0100 Subject: [PATCH] bugfix: Alignment tool, auto-detect alignments - Random linting and typing --- lib/image.py | 8 +- lib/training/augmentation.py | 313 ++++++++++-------- lib/training/generator.py | 51 +-- .../es/LC_MESSAGES/tools.alignments.cli.mo | Bin 12801 -> 12789 bytes .../es/LC_MESSAGES/tools.alignments.cli.po | 24 +- .../kr/LC_MESSAGES/tools.alignments.cli.mo | Bin 12494 -> 12482 bytes .../kr/LC_MESSAGES/tools.alignments.cli.po | 24 +- .../ru/LC_MESSAGES/tools.alignments.cli.mo | Bin 16449 -> 16437 bytes .../ru/LC_MESSAGES/tools.alignments.cli.po | 24 +- locales/tools.alignments.cli.pot | 14 +- tools/alignments/cli.py | 10 +- 11 files changed, 258 insertions(+), 210 deletions(-) diff --git a/lib/image.py b/lib/image.py index 7d41a5a..4a2b524 100644 --- a/lib/image.py +++ b/lib/image.py @@ -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 diff --git a/lib/training/augmentation.py b/lib/training/augmentation.py index f9edf2a..184b126 100644 --- a/lib/training/augmentation.py +++ b/lib/training/augmentation.py @@ -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 diff --git a/lib/training/generator.py b/lib/training/generator.py index 538941a..0624246 100644 --- a/lib/training/generator.py +++ b/lib/training/generator.py @@ -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,8 +243,9 @@ 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 - filenames, raw_faces.shape, len(detected_faces)) + 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 def _crop_to_coverage(self, @@ -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,8 +655,9 @@ 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 - images.shape, len(detected_faces)) + 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,8 +848,9 @@ 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 - side, side_feed.shape, [i.shape for i in side_targets]) + 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) diff --git a/locales/es/LC_MESSAGES/tools.alignments.cli.mo b/locales/es/LC_MESSAGES/tools.alignments.cli.mo index f6786ef695682f93b758135d47b8af8579416fc5..9499ca1e8acd6c11dc050f5bd77a732215adafc5 100644 GIT binary patch delta 458 zcmXZYKS;ts6bJC{{Y>q@nLqTjpdV2gfr&%X5L&k42P-|$mxTR=u ztKF$7YzUefgcb=B8d{_w-1}a1aD46^?>*k#dA^ssoT*L&XbNDNe$q4z8Nfa*&?tSR zHTq3AY1ILwnEOQE`vH#=m}A@>0Z#e=(*x`>@4^SPXp4ficP0?$@!k(G4Q)TFaP#oN zi$VHD583F4&NJSVzz#j7NA&sMXb@Oqd`(~I8`T5XLqLi3J=$W!;v|q^ycGtPIOHvx z9x(4U!eQyc;yQ4~$t0h-!Hb(1z&y0+5baPsV3)EF#<=y;Ipg}EvSP~11{mOW=^HMG zx)K4eexY8&-1-AX)q@DDj#yFBNV;t+dz`l-s$isDwpFyPNTX@gOn1VH#a82qMkX*T fR9U8kttxU``GONp+bXf3ER(A87Zq7k4`$^rRNF@A delta 497 zcmYMwze_?<6bJC{eOdk}E6ZQcq#k6cfrc7FK}5BMVL=oG4WhiE!QySwU=B?U7Pmj4 zXsH&bXle**X=#cGGN>k7!ojWYgRlpe&pDTK&b{|F^OeF;s5}bbRsd=GL04%|0oG}e zPSQJCrA@j(4?2JhYwzi+4e)dVA-hIlXs?gcr6c{U8B zc**k!u*tfY7|@{U_#Cj$n}ztyd2XB~0M_A)cGCtmFW91-V?Lt&4KT9EoEUNSGqQ7a zahXqrJQhAzF9UN{4;OzFcdtcQ=<-dZ72S|^k&;V_$F3V%u2|4wy401djoFUDq;{iJ z-PWX*NX{gtYOB66VbSx^xLolM%ZwVaYLS?3wDSq+R8m#rr|LR2R;VR z+^C~(w2h6v=rGqo9ayGWx)&ZV8)jR81+I5vzynXb zj{~dBb9(@T`>lxyCh}%ONnng0*3v*NJ)>TF`Rfg3KAJey;DZrVfwV+>fDL}CRD~KI zc_<Q5{WXFy3w6%W;7dCW@Sa8^A}iJ z7-^!g@KIuAV?`-bSlUdIo#&Rut#g0xd+z(5bI-Xk9*o`2LI;3r0VL@=ouwfKNYgCs zrMGm4e$i37Sp!V5_MW~t0beZ;VP2^RR&7AA5twG(RtxY*pD5US=mm6!ML)nYl>I2c z!Qg`vZu&`ExzG#6 zRLDIM@H8;s#h{LZ7sc5#5f!F<6-mX+%d+T`lZww}=EFvIIUF;ksmwT;8Q7fQkF o(8CFRC^1k<1?+;I6KaOMtFP&$ejsiJaq9qzsfooc!n{+D%EU^EH?l2Gc00s{_q|;r1-OC#5KSRJd zFZwV7oUv~$3G8$JFF6C~yvp7bu+G8-^A3txzJmB@H`OWo!9AOU4{pvwW<+0rC!(F7 zyIBKV@ZU mOW2E%w2SwM=&a delta 482 zcmX}oPbh<790&04^P2t9*v9_7vserV*=(zoQT`MMkz8Dnc@Na4rIgF&pp*l8ZX`}F zi_%iGgQk>&GC4`g4jf(Npd5VP9lZ6tpXc{`e$U^FoG9hQZZO*ppd^4eeW%mZuK+VN zMZ@%#?$B>KLN{xG3D(}xS2N(M1v(jj)dMRAz-I#{S-0H;Jke(g&OLPkQFhPV0LxHu zBMTEdA57HIPrA&7e&{IUMK6%1d3r*dRp6Z7P>rtofHBs;&^5+wejvz=_UV8fxNZR+ zIQ|;~4tdb~Uf_UrOMSow^Txy=C-Ep-{lFXt@{Fz2It1{rP-!C#QP%61`2Y00LC%X- z2X}&n&B&%-6>?8_91ZO7VXEu#p_siAT|$#@BCco|SrIWguDC2(CNQ5$26{B9DN|-f z=?sHHQOP<@(Lf}ch{OuRo>{?}$KEvmHuXrKRK8@{g0!paGVJTNRx{;dHCssf9y|U3 DwIETT diff --git a/locales/ru/LC_MESSAGES/tools.alignments.cli.po b/locales/ru/LC_MESSAGES/tools.alignments.cli.po index fe2ca62..3f68a44 100644 --- a/locales/ru/LC_MESSAGES/tools.alignments.cli.po +++ b/locales/ru/LC_MESSAGES/tools.alignments.cli.po @@ -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." diff --git a/locales/tools.alignments.cli.pot b/locales/tools.alignments.cli.pot index 64c40ff..4f1e02a 100644 --- a/locales/tools.alignments.cli.pot +++ b/locales/tools.alignments.cli.pot @@ -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 \n" "Language-Team: LANGUAGE \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 diff --git a/tools/alignments/cli.py b/tools/alignments/cli.py index 84be726..5a76443 100644 --- a/tools/alignments/cli.py +++ b/tools/alignments/cli.py @@ -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": _(