Exemple #1
0
    def apply_horizontal_lines(
            self,
            intensity=CONFIGS.DEFAULTS["horizontal_lines"]["intensity"],
            blur=CONFIGS.DEFAULTS["horizontal_lines"]["blur"],
            inplace=True):
        if isinstance(intensity, (int, float)) == False:
            raise TypeError("Parameter 'intensity' must be a float.")
        if isinstance(blur, (int, float)) == False:
            raise TypeError("Parameter 'blur' must be a float.")
        if isinstance(inplace, bool) == False:
            raise TypeError("Parameter 'inplace' must be a boolean.")

        w, h = self.modified_img.size

        intensity = utils.clamp(intensity,
                                CONFIGS.MINS["horizontal_lines"]["intensity"],
                                CONFIGS.MAXS["horizontal_lines"]["intensity"])

        height_divided = h / CONFIGS.DEFAULTS["horizontal_lines"][
            "height_divider"]
        n_lines = utils.pctg_to_value(intensity, height_divided)
        n_lines = utils.translate_ranges(n_lines, 0, height_divided,
                                         height_divided, 0)

        blur = utils.clamp(blur, 0, 1)
        blur = utils.pctg_to_value(blur,
                                   CONFIGS.MAXS["horizontal_lines"]["blur"])

        resulted_img = self.modified_img
        if resulted_img.mode != "RGBA":
            resulted_img = resulted_img.convert("RGBA")

        resulted_arr = np.array(resulted_img).astype(float)

        lines_arr = np.zeros((h, w), dtype=np.uint8)
        lines_rows = lines_arr.shape[0]
        lines_cols = lines_arr.shape[1]

        pixels_between = int(h / n_lines)
        for row in range(lines_rows):
            if row % pixels_between == 0:
                lines_arr[row, :] = 1

        lines_img = Image.fromarray(lines_arr * 255).convert("RGBA")
        lines_img = lines_img.filter(ImageFilter.GaussianBlur(blur))
        lines_arr = np.array(lines_img).astype(float)

        resulted_arr = blend_modes.soft_light(
            resulted_arr, lines_arr,
            CONFIGS.DEFAULTS["horizontal_lines"]["bright"])
        resulted_img = Image.fromarray(resulted_arr.astype(np.uint8))

        if inplace == False:
            return resulted_img
        else:
            self.modified_img = resulted_img
Exemple #2
0
    def apply_film_grain(self,
                         intensity=CONFIGS.DEFAULTS["film_grain"]["intensity"],
                         blur=CONFIGS.DEFAULTS["film_grain"]["blur"],
                         inplace=True):
        if isinstance(intensity, (int, float)) == False:
            raise TypeError("Parameter 'intensity' must be a float.")
        if isinstance(blur, (int, float)) == False:
            raise TypeError("Parameter 'blur' must be a float.")
        if isinstance(inplace, bool) == False:
            raise TypeError("Parameter 'inplace' must be a boolean.")

        w, h = self.modified_img.size

        intensity = utils.clamp(intensity, 0, 1)
        intensity = utils.translate_ranges(
            intensity, 0, 1, CONFIGS.MINS["film_grain"]["intensity"], 1)
        blur = utils.clamp(blur, 0, 1)
        blur = utils.pctg_to_value(blur, CONFIGS.MAXS["film_grain"]["blur"])

        middle_gray = Image.new("RGB", self.modified_img.size,
                                (119, 119, 119)).convert("RGBA")

        noise_arr = np.random.normal(
            0, CONFIGS.DEFAULTS["film_grain"]["gaussian_std"], w * h)
        noise_arr = np.uint8(noise_arr.reshape(h, w))
        noise_img = Image.fromarray(noise_arr).convert("RGBA")

        noise_img = Image.blend(middle_gray, noise_img, intensity)
        noise_img = noise_img.filter(ImageFilter.GaussianBlur(blur))

        resulted_img = self.modified_img
        if resulted_img.mode != "RGBA":
            resulted_img = resulted_img.convert("RGBA")

        noise_arr = np.array(noise_img).astype(float)
        resulted_arr = np.array(resulted_img).astype(float)

        resulted_arr = blend_modes.overlay(resulted_arr, noise_arr,
                                           intensity / 2)
        resulted_img = Image.fromarray(resulted_arr.astype(np.uint8))

        if inplace == False:
            return resulted_img
        else:
            self.modified_img = resulted_img
Exemple #3
0
    def apply_wave_warp(self,
                        intensity=CONFIGS.DEFAULTS["wave_warp"]["intensity"],
                        row=None,
                        inplace=True):
        if isinstance(intensity, (float, int)) == False:
            raise TypeError("Parameter 'intensity' must be a float.")
        if isinstance(row, int) == False and row != None:
            raise TypeError("Parameter 'row' must be an integer.")
        if isinstance(inplace, bool) == False:
            raise TypeError("Parameter 'inplace' must be a boolean.")

        w, h = self.modified_img.size

        if row != None:
            if row < 0 or row >= h:
                raise ValueError(
                    "Parameter 'row' must be lesser than image's height.")
        else:
            row = random.randint(0, h)

        intensity = utils.clamp(intensity,
                                CONFIGS.MINS["wave_warp"]["intensity"],
                                CONFIGS.MAXS["wave_warp"]["intensity"])

        height_divided = h / CONFIGS.DEFAULTS["wave_warp"]["height_divider"]
        max_number_of_warps = utils.pctg_to_value(intensity, height_divided)
        max_number_of_warps = utils.translate_ranges(max_number_of_warps, 0,
                                                     height_divided,
                                                     height_divided, 0)

        img_arr = np.asarray(self.modified_img)
        img_arr.flags.writeable = True

        size = int(h / max_number_of_warps)

        if row - size * 2 >= 0:
            img_arr[row - size:row, :] = img_arr[row - size * 2:row - size, :]

        resulted_img = Image.fromarray(img_arr)
        if inplace == False:
            return resulted_img
        else:
            self.modified_img = resulted_img
Exemple #4
0
    def apply_color_glitch(
            self,
            intensity=CONFIGS.DEFAULTS["color_glitch"]["intensity"],
            crop=True,
            inplace=True):
        if isinstance(intensity, (int, float)) == False:
            raise TypeError("Parameter 'intensity' must be a float.")
        if isinstance(crop, bool) == False:
            raise TypeError("Parameter 'crop' must be a boolean.")
        if isinstance(inplace, bool) == False:
            raise TypeError("Parameter 'inplace' must be a boolean.")

        h = self.modified_img.size[1]

        intensity = utils.clamp(intensity, 0, 1)
        intensity = utils.translate_ranges(
            intensity, 0, 1, CONFIGS.MINS["color_glitch"]["intensity"],
            CONFIGS.MAXS["color_glitch"]["intensity"])
        offset = int(
            utils.pctg_to_value(
                intensity,
                h / CONFIGS.DEFAULTS["color_glitch"]["height_divider"]))
        offset = utils.clamp(offset, CONFIGS.MINS["color_glitch"]["offset"],
                             CONFIGS.MAXS["color_glitch"]["offset"])

        red_img = self.__get_single_channel_rgb_img("r").convert("RGBA")
        red_img = ImageChops.offset(red_img, offset, -offset)

        green_img = self.__get_single_channel_rgb_img("g").convert("RGBA")

        blue_img = self.__get_single_channel_rgb_img("b").convert("RGBA")
        blue_img = ImageChops.offset(blue_img, -offset, offset)

        resulted_img = ImageChops.add(green_img, red_img, 1)
        resulted_img = ImageChops.add(resulted_img, blue_img, 1)

        if crop == True:
            resulted_img = ImageOps.crop(resulted_img, offset)

        if inplace == False:
            return resulted_img
        else:
            self.modified_img = resulted_img
Exemple #5
0
    def apply_play_text(self,
                        intensity=CONFIGS.DEFAULTS["play_text"]["intensity"],
                        datetime=None,
                        hour=None,
                        inplace=True):
        if isinstance(intensity, (int, float)) == False:
            raise TypeError("Parameter 'intensity' must be a float.")
        if isinstance(datetime, dt.datetime) == False and datetime != None:
            raise TypeError(
                "Parameter 'datetime' must be a datetime.datetime object.")
        if isinstance(hour, int) == False and hour != None:
            raise TypeError("Parameter 'hour' must be an integer.")
        if isinstance(inplace, bool) == False:
            raise TypeError("Parameter 'inplace' must be a boolean.")

        if hour != None and (hour < 0 or hour > 23):
            raise ValueError(
                "Parameter 'hour' must be an integer between 0 and 23.")

        if datetime == None:
            datetime = utils.get_random_datetime(1980, 1990, hour)
        elif datetime != None and hour != None:
            raise ValueError(
                "Parameter 'hour' can only be passed if parameter 'datetime' is None."
            )

        intensity = utils.clamp(intensity, 0, 1)
        intensity = utils.translate_ranges(
            intensity, 0, 1, CONFIGS.MINS["play_text"]["intensity"],
            CONFIGS.MAXS["play_text"]["intensity"])

        w, h = self.modified_img.size
        x_offset = w * CONFIGS.DEFAULTS["play_text"]["offset_multiplier"]
        y_offset = h * CONFIGS.DEFAULTS["play_text"]["offset_multiplier"]

        width_divided = w / CONFIGS.DEFAULTS["play_text"]["width_divider"]
        font_size = int(utils.pctg_to_value(intensity, width_divided))

        resulted_img = copy.deepcopy(self.modified_img)

        draw = ImageDraw.Draw(resulted_img)

        vhs_font_path = str(CONFIGS.PATHS["fonts"] /
                            Path("VCR_OSD_MONO_1.001.ttf"))
        play_icon_path = str(CONFIGS.PATHS["fonts"] / Path("play_icon.ttf"))
        vhs_font = ImageFont.truetype(vhs_font_path, font_size)
        play_icon = ImageFont.truetype(play_icon_path, font_size)

        draw.text((x_offset, y_offset), "PLAY", (255, 255, 255), font=vhs_font)
        draw.text((x_offset + 2.2 * font_size, y_offset),
                  ">", (255, 255, 255),
                  font=play_icon)
        draw.text((w - x_offset - 3 * font_size, h - y_offset - font_size),
                  "SP", (255, 255, 255),
                  font=vhs_font)
        draw.text((w - x_offset - 3 * font_size, y_offset),
                  "--:--", (255, 255, 255),
                  font=vhs_font)

        month = datetime.strftime("%h").upper()
        day = datetime.strftime("%0d")
        period = datetime.strftime("%p")
        hour = datetime.strftime("%0I")
        minute = datetime.strftime("%0M")

        datetime_str = "{}:{} {}\n{}. {} {}".format(hour, minute, period,
                                                    month, day, datetime.year)

        draw.text((x_offset, h - y_offset - 2 * font_size),
                  datetime_str, (255, 255, 255),
                  font=vhs_font)

        if inplace == False:
            return resulted_img
        else:
            self.modified_img = resulted_img
Exemple #6
0
    def generate_noise_lines(
            size=CONFIGS.SIZE,
            intensity=CONFIGS.DEFAULTS["noise_lines"]["intensity"],
            blur=CONFIGS.DEFAULTS["noise_lines"]["blur"],
            bright=CONFIGS.DEFAULTS["noise_lines"]["bright"]):
        if isinstance(size, tuple) == False:
            raise TypeError("Parameter 'size' must be a tuple.")
        if isinstance(intensity, (int, float)) == False:
            raise TypeError("Parameter 'intensity' must be a float.")
        if isinstance(blur, (int, float)) == False:
            raise TypeError("Parameter 'blur' must be a float.")
        if isinstance(bright, (int, float)) == False:
            raise TypeError("Parameter 'bright' must be a float.")

        intensity = utils.clamp(intensity,
                                CONFIGS.MINS["noise_lines"]["intensity"], 1)
        blur = utils.clamp(blur, 0, 1)
        bright = utils.clamp(bright, 0, 1)

        p_threshold = utils.translate_ranges(
            intensity, 1, 0, CONFIGS.MINS["noise_lines"]["p_threshold"], 1)

        iterations = int(
            utils.pctg_to_value(intensity,
                                CONFIGS.MAXS["noise_lines"]["iter"]))
        blur = utils.pctg_to_value(blur, CONFIGS.MAXS["noise_lines"]["blur"])
        bright = utils.pctg_to_value(bright,
                                     CONFIGS.MAXS["noise_lines"]["bright"])

        size = (size[1], size[0])
        if isinstance(size, tuple) == False:
            raise TypeError("Parameter 'size' must be a tuple.")

        noise_arr = np.zeros(size, dtype=np.uint8)

        n_rows = noise_arr.shape[0]
        n_cols = noise_arr.shape[1]

        for i in range(iterations):
            for row in range(n_rows):
                p = random.uniform(0,
                                   1)  #probability of row become a noise line
                if row < n_rows / 10 or n_rows - row < n_rows / 10:  #increases probability for top and bottom rows
                    p += p * 0.1
                elif row < n_rows / 30 or n_rows - row < n_rows / 30:
                    p += p * 0.1

                if p > p_threshold:  #row becomes a noise line
                    hsize = np.random.choice(np.arange(1, 3),
                                             p=[0.95,
                                                0.05])  #line horizontal size
                    vstart = random.randint(0, n_cols -
                                            1)  #line vertical start pixel
                    vend = random.randint(
                        0,
                        int(n_cols / np.random.choice(
                            np.array([5, 10, 15, 20]), p=[0.1, 0.2, 0.3, 0.4]))
                    )  #line vertical end pixel based on array size. Smaller lines have more chance to occur

                    noise_arr[row:row + hsize,
                              vstart % n_cols:(vstart + vend) % n_cols] = 1

                    np.random.shuffle(
                        noise_arr[row, vstart:vstart + vend +
                                  int(n_cols /
                                      15)])  #creates noise for each line

        noise_lines_img = Image.fromarray(noise_arr * 255, "L")
        noise_lines_img = noise_lines_img.filter(
            ImageFilter.GaussianBlur(blur))  #applying gaussian blur
        bright_enhancer = ImageEnhance.Brightness(noise_lines_img)
        noise_lines_img = bright_enhancer.enhance(
            bright)  #enhancing brightness

        return noise_lines_img