Spaces:
Running
Running
# change rainy drop func from | |
# https://github.com/EvoCargo/RaindropsOnWindshield/blob/main/raindrops_generator/raindrop/raindrop.py | |
import math | |
import random | |
from random import randint | |
import cv2 | |
import numpy as np | |
from PIL import Image, ImageDraw, ImageFilter | |
from raindropper.config import cfg | |
def make_bezier(xys): | |
# xys should be a sequence of 2-tuples (Bezier control points) | |
n = len(xys) | |
combinations = pascal_row(n - 1) | |
def bezier(ts): | |
# This uses the generalized formula for bezier curves | |
# http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Generalization | |
result = [] | |
for t in ts: | |
tpowers = (t**i for i in range(n)) | |
upowers = reversed([(1 - t)**i for i in range(n)]) | |
coefs = [c * a * b for c, a, b in zip(combinations, tpowers, upowers)] | |
result.append(tuple(sum([coef * p for coef, p in zip(coefs, ps)]) for ps in zip(*xys))) | |
return result | |
return bezier | |
def pascal_row(n, memo={}): | |
# This returns the nth row of Pascal Triangle | |
if n in memo: | |
return memo[n] | |
result = [1] | |
x, numerator = 1, n | |
for denominator in range(1, n // 2 + 1): | |
x *= numerator | |
x /= denominator | |
result.append(x) | |
numerator -= 1 | |
if n & 1 == 0: | |
result.extend(reversed(result[:-1])) | |
else: | |
result.extend(reversed(result)) | |
memo[n] = result | |
return result | |
class Raindrop(): | |
def __init__(self, key, centerxy=None, radius=None, shape=None): | |
# param key: a unique key identifying a drop | |
# param centerxy: tuple defining coordinates of raindrop center in the image | |
# param radius: radius of a drop | |
# param shape: int from 0 to 2 defining raindrop shape type | |
self.key = key | |
self.ifcol = False | |
self.col_with = [] | |
self.center = centerxy | |
self.radius = radius | |
# self.blur_coeff = max(int(self.radius/3), 1) | |
# self.blur_coeff = max(int(cfg["maxR"] / self.radius), 1) | |
self.blur_coeff = 3 | |
self.shape = shape | |
self.type = 'default' | |
# label map's WxH = 4*R , 5*R | |
self.labelmap = np.zeros((self.radius * 5, self.radius * 4)) | |
self.alphamap = np.zeros((self.radius * 5, self.radius * 4)) | |
self.background = None | |
self.texture = None | |
self.control_point = {} | |
self._create_label() | |
self.use_label = False | |
def setCollision(self, col, col_with): | |
self.ifcol = col | |
self.col_with = col_with | |
def updateTexture(self, bg): | |
# gaussian blur radius may be 1, 3, 5 | |
radius_array = [1, 3] | |
blur_radius_idx = randint(0, 1) | |
blur_radius = radius_array[blur_radius_idx] | |
fg = (Image.fromarray(np.uint8(bg))).filter(ImageFilter.GaussianBlur(radius=blur_radius)) | |
fg = np.asarray(fg) | |
# add fish eye effect to simulate the background | |
K = np.array([[30 * self.radius, 0, 2 * self.radius], [0., 20 * self.radius, 3 * self.radius], [0., 0., 1]]) | |
D = np.array([0.0, 0.0, 0.0, 0.0]) | |
Knew = K.copy() | |
Knew[(0, 1), (0, 1)] = math.pow(self.radius, 1 / 500) * 2 * Knew[(0, 1), (0, 1)] | |
fisheye = cv2.fisheye.undistortImage(fg, K, D=D, Knew=Knew) | |
tmp = np.expand_dims(self.alphamap, axis=-1) | |
tmp = np.concatenate((fisheye, tmp), axis=2) | |
self.texture = Image.fromarray(tmp.astype('uint8'), 'RGBA') | |
def _create_label(self): | |
self._createDefaultDrop() | |
def _createDefaultDrop(self): | |
"""create the raindrop Alpha Map according to its shape type update | |
raindrop label.""" | |
if (self.shape == 0): | |
cv2.circle(self.labelmap, (self.radius * 2, self.radius * 3), int(self.radius), 128, -1) | |
self.alphamap = (Image.fromarray(np.uint8(self.labelmap))).filter( | |
ImageFilter.GaussianBlur(radius=self.blur_coeff)) | |
self.alphamap = np.asarray(self.alphamap).astype(np.float) | |
self.alphamap = self.alphamap / np.max(self.alphamap) * 255.0 | |
# set label map | |
self.labelmap[self.labelmap > 0] = 1 | |
if (self.shape == 1): | |
cv2.circle(self.labelmap, (self.radius * 2, self.radius * 3), int(self.radius), 128, -1) | |
cv2.ellipse(self.labelmap, (self.radius * 2, self.radius * 3), | |
(self.radius, int(1.3 * math.sqrt(3) * self.radius)), 0, 180, 360, 128, -1) | |
self.alphamap = (Image.fromarray(np.uint8(self.labelmap))).filter( | |
ImageFilter.GaussianBlur(radius=self.blur_coeff)) | |
self.alphamap = np.asarray(self.alphamap).astype(np.float) | |
self.alphamap = self.alphamap / np.max(self.alphamap) * 255.0 | |
# set label map | |
self.labelmap[self.labelmap > 0] = 1 | |
if (self.shape == 2): | |
C0 = random.uniform(0, 1) | |
C1 = random.uniform(0, 1) | |
A0 = random.uniform(0, 1) | |
A1 = random.uniform(2, 3) | |
D0 = random.uniform(2, 3) | |
D1 = random.uniform(2, 3) | |
B0 = random.uniform(2, 3) | |
B1 = random.uniform(0, 1) | |
self.control_point['A'] = (A0, A1) | |
self.control_point['B'] = (B0, B1) | |
self.control_point['C'] = (C0, C1) | |
self.control_point['D'] = (D0, D1) | |
img = Image.fromarray(np.uint8(self.labelmap), 'L') | |
draw = ImageDraw.Draw(img) | |
ts = [t / 100.0 for t in range(101)] | |
xys = [(self.radius * C0, self.radius * C1), (self.radius * B0, self.radius * B1), | |
(self.radius * D0, self.radius * D1)] | |
bezier = make_bezier(xys) | |
points = bezier(ts) | |
xys = [(self.radius * C0, self.radius * C1), (self.radius * A0, self.radius * A1), | |
(self.radius * D0, self.radius * D1)] | |
bezier = make_bezier(xys) | |
points.extend(bezier(ts)) | |
draw.polygon(points, fill='gray') | |
self.alphamap = img.filter(ImageFilter.GaussianBlur(radius=self.blur_coeff)) | |
self.alphamap = np.asarray(self.alphamap).astype(np.float) | |
self.alphamap = self.alphamap / np.max(self.alphamap) * 255.0 | |
# set label map | |
self.labelmap[self.labelmap > 0] = 1 | |
def setKey(self, key): | |
self.key = key | |
def getLabelMap(self): | |
return self.labelmap | |
def getAlphaMap(self): | |
return self.alphamap | |
def getTexture(self): | |
return self.texture | |
def getCenters(self): | |
return self.center | |
def getRadius(self): | |
return self.radius | |
def getKey(self): | |
return self.key | |
def getIfColli(self): | |
return self.ifcol | |
def getCollisionList(self): | |
return self.col_with | |
def getUseLabel(self): | |
return self.use_label | |