diff --git a/lib/face_filter.py b/lib/face_filter.py index 5c11e71f71..aca13b6a36 100644 --- a/lib/face_filter.py +++ b/lib/face_filter.py @@ -164,6 +164,9 @@ def check(self, detected_face): msg = ("Rejecting face as k-nearest neighbors classification is less than " "0.5: {}".format(round(ratio, 2))) retval = False + else: + msg = None + retval = True else: msg = None retval = True diff --git a/lib/model/masks.py b/lib/model/masks.py index e9989086d7..ae8a2d6f67 100644 --- a/lib/model/masks.py +++ b/lib/model/masks.py @@ -127,5 +127,5 @@ def build_mask(self): mask = np.zeros(self.face.shape[0:2] + (1, ), dtype=np.float32) hull = cv2.convexHull( # pylint: disable=no-member np.array(self.landmarks).reshape((-1, 2))) - cv2.fillConvexPoly(mask, hull, 1.0, lineType=cv2.LINE_AA) # pylint: disable=no-member + cv2.fillConvexPoly(mask, hull, 255.0, lineType=cv2.LINE_AA) # pylint: disable=no-member return mask diff --git a/plugins/convert/_config.py b/plugins/convert/_config.py index 1661d18c19..59b89aabb3 100644 --- a/plugins/convert/_config.py +++ b/plugins/convert/_config.py @@ -118,6 +118,55 @@ def set_defaults(self): "scaling factor proposed in the paper. This method seems to produce more " "consistently aesthetically pleasing results") + section = "color.manual_balance" + self.add_section(title=section, + info="Options for manually altering the balance of colors of the swapped " + "face") + self.add_item( + section=section, title="colorspace", datatype=str, default="HSV", gui_radio=True, + choices=["RGB", "HSV", "LAB", "YCrCb"], + info="The colorspace to use for adjustment: The three adjustment sliders will effect " + "the image differently depending on which colorspace is selected:" + "\n\t RGB: Red, Green, Blue. An additive colorspace where colors are obtained by " + "a linear combination of Red, Green, and Blue values. The three channels are " + "correlated by the amount of light hitting the surface. In RGB color space the " + "color information is separated into three channels but the same three channels " + "also encode brightness information." + "\n\t HSV: Hue, Saturation, Value. Hue - Dominant wavelength. Saturation - " + "Purity / shades of color. Value - Intensity. Best thing is that it uses only " + "one channel to describe color (H), making it very intuitive to specify color." + "\n\t LAB: Lightness, A, B. Lightness - Intensity. A - Color range from green to " + "magenta. B - Color range from blue to yellow. The L channel is independent of " + "color information and encodes brightness only. The other two channels encode " + "color." + "\n\t YCrCb: Y – Luminance or Luma component obtained from RGB after gamma " + "correction. Cr - how far is the red component from Luma. Cb - how far is the " + "blue component from Luma. Separates the luminance and chrominance components " + "into different channels.") + self.add_item( + section=section, title="balance_1", datatype=float, default=0.0, rounding=1, + min_max=(-100.0, 100.0), + info="Balance of channel 1: " + "\n\tRGB: Red " + "\n\tHSV: Hue " + "\n\tLAB: Lightness " + "\n\tYCrCb: Luma ") + self.add_item( + section=section, title="balance_2", datatype=float, default=0.0, rounding=1, + min_max=(-100.0, 100.0), + info="Balance of channel 2: " + "\n\tRGB: Green " + "\n\tHSV: Saturation " + "\n\tLAB: Green > Magenta " + "\n\tYCrCb: Distance of red from Luma") + self.add_item( + section=section, title="balance_3", datatype=float, default=0.0, rounding=1, + min_max=(-100.0, 100.0), + info="Balance of channel 3: " + "\n\tRGB: Blue " + "\n\tHSV: Intensity " + "\n\tLAB: Blue > Yellow " + "\n\tYCrCb: Distance of blue from Luma") section = "color.match_hist" self.add_section(title=section, info="Options for matching the histograms between the source and " diff --git a/plugins/convert/color/manual_balance.py b/plugins/convert/color/manual_balance.py new file mode 100644 index 0000000000..2e59f3533b --- /dev/null +++ b/plugins/convert/color/manual_balance.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +""" Manual Balance colour adjustment plugin for faceswap.py converter """ + +import cv2 +import numpy as np +from ._base import Adjustment + + +class Color(Adjustment): + """ Adjust the mean of the color channels to be the same for the swap and old frame """ + + def process(self, old_face, new_face, raw_mask): + image = self.convert_colorspace(new_face * 255.0) + adjustment = np.array([self.config["balance_1"] / 100.0, + self.config["balance_2"] / 100.0, + self.config["balance_3"] / 100.0]).astype("float32") + for idx in range(3): + if adjustment[idx] >= 0: + image[:, :, idx] = ((1 - image[:, :, idx]) * adjustment[idx]) + image[:, :, idx] + else: + image[:, :, idx] = image[:, :, idx] * (1 + adjustment[idx]) + + image = self.convert_colorspace(image * 255.0, to_bgr=True) + return image + + def convert_colorspace(self, new_face, to_bgr=False): + """ Convert colorspace based on mode or back to bgr """ + mode = self.config["colorspace"].lower() + colorspace = "YCrCb" if mode == "ycrcb" else mode.upper() + conversion = "{}2BGR".format(colorspace) if to_bgr else "BGR2{}".format(colorspace) + image = cv2.cvtColor(new_face.astype("uint8"), # pylint: disable=no-member + getattr(cv2, "COLOR_{}".format(conversion))).astype("float32") / 255.0 + return image diff --git a/tools/lib_alignments/media.py b/tools/lib_alignments/media.py index c588a53d62..30f5601e35 100644 --- a/tools/lib_alignments/media.py +++ b/tools/lib_alignments/media.py @@ -134,7 +134,7 @@ def check_input_folder(self): def valid_extension(filename): """ Check whether passed in file has a valid extension """ extension = os.path.splitext(filename)[1] - retval = extension in _image_extensions + retval = extension.lower() in _image_extensions logger.trace("Filename has valid extension: '%s': %s", filename, retval) return retval