generated from thinkode/modelRepository
64 lines
1.9 KiB
Python
64 lines
1.9 KiB
Python
from dataclasses import dataclass
|
|
|
|
import numpy as np
|
|
from PIL import Image, ImageFilter
|
|
|
|
from moviepy.Clip import Clip
|
|
from moviepy.Effect import Effect
|
|
|
|
|
|
@dataclass
|
|
class Painting(Effect):
|
|
"""Transforms any photo into some kind of painting.
|
|
|
|
Transforms any photo into some kind of painting. Saturation
|
|
tells at which point the colors of the result should be
|
|
flashy. ``black`` gives the amount of black lines wanted.
|
|
|
|
np_image : a numpy image
|
|
"""
|
|
|
|
saturation: float = 1.4
|
|
black: float = 0.006
|
|
|
|
def to_painting(self, np_image, saturation=1.4, black=0.006):
|
|
"""Transforms any photo into some kind of painting.
|
|
|
|
Transforms any photo into some kind of painting. Saturation
|
|
tells at which point the colors of the result should be
|
|
flashy. ``black`` gives the amount of black lines wanted.
|
|
|
|
np_image : a numpy image
|
|
"""
|
|
image = Image.fromarray(np_image)
|
|
image = image.filter(ImageFilter.EDGE_ENHANCE_MORE)
|
|
|
|
# Convert the image to grayscale
|
|
grayscale_image = image.convert("L")
|
|
|
|
# Find the image edges
|
|
edges_image = grayscale_image.filter(ImageFilter.FIND_EDGES)
|
|
|
|
# Convert the edges image to a numpy array
|
|
edges = np.array(edges_image)
|
|
|
|
# Create the darkening effect
|
|
darkening = black * (255 * np.dstack(3 * [edges]))
|
|
|
|
# Apply the painting effect
|
|
painting = saturation * np.array(image) - darkening
|
|
|
|
# Clip the pixel values to the valid range of 0-255
|
|
painting = np.maximum(0, np.minimum(255, painting))
|
|
|
|
# Convert the pixel values to unsigned 8-bit integers
|
|
painting = painting.astype("uint8")
|
|
|
|
return painting
|
|
|
|
def apply(self, clip: Clip) -> Clip:
|
|
"""Apply the effect to the clip."""
|
|
return clip.image_transform(
|
|
lambda im: self.to_painting(im, self.saturation, self.black)
|
|
)
|