zach
initial commit based on github repo
3ef1661
raw
history blame contribute delete
No virus
16.7 kB
# change rainy drop func from
# https://github.com/EvoCargo/RaindropsOnWindshield/blob/main/raindrops_generator/raindrop/dropgenerator.py
import math
import random
from random import randint
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageEnhance
from skimage.measure import label as skimage_label
from .raindrop import Raindrop, make_bezier
def CheckCollision(DropList):
"""This function handle the collision of the drops.
:param DropList: list of raindrop class objects
"""
listFinalDrops = []
Checked_list = []
list_len = len(DropList)
# because latter raindrops in raindrop list should has more colision information
# so reverse list
DropList.reverse()
drop_key = 1
for drop in DropList:
# if the drop has not been handle
if drop.getKey() not in Checked_list:
# if drop has collision with other drops
if drop.getIfColli():
# get collision list
collision_list = drop.getCollisionList()
# first get radius and center to decide how will the collision do
final_x = drop.getCenters()[0] * drop.getRadius()
final_y = drop.getCenters()[1] * drop.getRadius()
tmp_devide = drop.getRadius()
final_R = drop.getRadius() * drop.getRadius()
for col_id in collision_list:
col_id = int(col_id)
Checked_list.append(col_id)
# list start from 0
final_x += DropList[list_len - col_id].getRadius() * DropList[list_len - col_id].getCenters()[0]
final_y += DropList[list_len - col_id].getRadius() * DropList[list_len - col_id].getCenters()[1]
tmp_devide += DropList[list_len - col_id].getRadius()
final_R += DropList[list_len - col_id].getRadius() * DropList[list_len - col_id].getRadius()
final_x = int(round(final_x / tmp_devide))
final_y = int(round(final_y / tmp_devide))
final_R = int(round(math.sqrt(final_R)))
# rebuild drop after handled the collisions
newDrop = Raindrop(drop_key, (final_x, final_y), final_R)
drop_key = drop_key + 1
listFinalDrops.append(newDrop)
# no collision
else:
drop.setKey(drop_key)
drop_key = drop_key + 1
listFinalDrops.append(drop)
return listFinalDrops
def generate_label(h, w, cfg):
"""This function generate list of raindrop class objects and label map of
this drops in the image.
:param h: image height
:param w: image width
:param cfg: config with global constants
:param shape: int from 0 to 2 defining raindrop shape type
"""
maxDrop = cfg['maxDrops']
minDrop = cfg['minDrops']
maxR = cfg['maxR']
minR = cfg['minR']
drop_num = randint(minDrop, maxDrop)
imgh = h
imgw = w
# random drops position
ran_pos = [(int(random.random() * imgw), int(random.random() * imgh)) for _ in range(drop_num)]
listRainDrops = []
listFinalDrops = []
for key, pos in enumerate(ran_pos):
key = key + 1
radius = random.randint(minR, maxR)
shape = random.randint(1, 1)
drop = Raindrop(key, pos, radius, shape)
listRainDrops.append(drop)
# to check if collision or not
label_map = np.zeros([h, w])
collisionNum = len(listRainDrops)
listFinalDrops = list(listRainDrops)
loop = 0
while collisionNum > 0:
loop = loop + 1
listFinalDrops = list(listFinalDrops)
collisionNum = len(listFinalDrops)
label_map = np.zeros_like(label_map)
# Check Collision
for drop in listFinalDrops:
# check the bounding
(ix, iy) = drop.getCenters()
radius = drop.getRadius()
ROI_WL = 2 * radius
ROI_WR = 2 * radius
ROI_HU = 3 * radius
ROI_HD = 2 * radius
if (iy - 3 * radius) < 0:
ROI_HU = iy
if (iy + 2 * radius) > imgh:
ROI_HD = imgh - iy
if (ix - 2 * radius) < 0:
ROI_WL = ix
if (ix + 2 * radius) > imgw:
ROI_WR = imgw - ix
# apply raindrop label map to Image's label map
drop_label = drop.getLabelMap()
# check if center has already has drops
if (label_map[iy, ix] > 0):
col_ids = np.unique(label_map[iy - ROI_HU:iy + ROI_HD, ix - ROI_WL:ix + ROI_WR])
col_ids = col_ids[col_ids != 0]
drop.setCollision(True, col_ids)
label_map[iy - ROI_HU:iy + ROI_HD,
ix - ROI_WL:ix + ROI_WR] = drop_label[3 * radius - ROI_HU:3 * radius + ROI_HD, 2 * radius -
ROI_WL:2 * radius + ROI_WR] * drop.getKey()
else:
label_map[iy - ROI_HU:iy + ROI_HD,
ix - ROI_WL:ix + ROI_WR] = drop_label[3 * radius - ROI_HU:3 * radius + ROI_HD, 2 * radius -
ROI_WL:2 * radius + ROI_WR] * drop.getKey()
# no collision
collisionNum = collisionNum - 1
if collisionNum > 0:
listFinalDrops = CheckCollision(listFinalDrops)
return listFinalDrops, label_map
def generateDrops(imagePath, cfg, listFinalDrops):
"""Generate raindrops on the image.
:param imagePath: path to the image on which you want to generate drops
:param cfg: config with global constants
:param listFinalDrops: final list of raindrop class objects after handling collisions
:param label_map: general label map of all drops in the image
"""
ifReturnLabel = cfg['return_label']
edge_ratio = cfg['edge_darkratio']
PIL_bg_img = Image.open(imagePath).convert('RGB')
bg_img = np.asarray(PIL_bg_img)
label_map = np.zeros_like(bg_img)[:, :, 0]
imgh, imgw, _ = bg_img.shape
A = cfg['A']
B = cfg['B']
C = cfg['C']
D = cfg['D']
alpha_map = np.zeros_like(label_map).astype(np.float64)
for drop in listFinalDrops:
(ix, iy) = drop.getCenters()
radius = drop.getRadius()
ROI_WL = 2 * radius
ROI_WR = 2 * radius
ROI_HU = 3 * radius
ROI_HD = 2 * radius
if (iy - 3 * radius) < 0:
ROI_HU = iy
if (iy + 2 * radius) > imgh:
ROI_HD = imgh - iy
if (ix - 2 * radius) < 0:
ROI_WL = ix
if (ix + 2 * radius) > imgw:
ROI_WR = imgw - ix
drop_alpha = drop.getAlphaMap()
alpha_map[iy - ROI_HU:iy + ROI_HD,
ix - ROI_WL:ix + ROI_WR] += drop_alpha[3 * radius - ROI_HU:3 * radius + ROI_HD,
2 * radius - ROI_WL:2 * radius + ROI_WR]
alpha_map = alpha_map / np.max(alpha_map) * 255.0
PIL_bg_img = Image.open(imagePath)
for idx, drop in enumerate(listFinalDrops):
(ix, iy) = drop.getCenters()
radius = drop.getRadius()
ROIU = iy - 3 * radius
ROID = iy + 2 * radius
ROIL = ix - 2 * radius
ROIR = ix + 2 * radius
if (iy - 3 * radius) < 0:
ROIU = 0
ROID = 5 * radius
if (iy + 2 * radius) > imgh:
ROIU = imgh - 5 * radius
ROID = imgh
if (ix - 2 * radius) < 0:
ROIL = 0
ROIR = 4 * radius
if (ix + 2 * radius) > imgw:
ROIL = imgw - 4 * radius
ROIR = imgw
tmp_bg = bg_img[ROIU:ROID, ROIL:ROIR, :]
try:
drop.updateTexture(tmp_bg)
except Exception:
del listFinalDrops[idx]
continue
tmp_alpha_map = alpha_map[ROIU:ROID, ROIL:ROIR]
output = drop.getTexture()
tmp_output = np.asarray(output).astype(np.float)[:, :, -1]
tmp_alpha_map = tmp_alpha_map * (tmp_output / 255)
tmp_alpha_map = Image.fromarray(tmp_alpha_map.astype('uint8'))
edge = ImageEnhance.Brightness(output)
edge = edge.enhance(edge_ratio)
PIL_bg_img.paste(edge, (ix - 2 * radius, iy - 3 * radius), output)
PIL_bg_img.paste(output, (ix - 2 * radius, iy - 3 * radius), output)
mask = np.zeros_like(bg_img)
if len(listFinalDrops) > 0:
# make circles and elipses
for drop in listFinalDrops:
if (drop.shape == 0):
cv2.circle(mask, drop.center, drop.radius, (255, 255, 255), -1)
if (drop.shape == 1):
cv2.circle(mask, drop.center, drop.radius, (255, 255, 255), -1)
cv2.ellipse(mask, drop.center, (drop.radius, int(1.3 * math.sqrt(3) * drop.radius)), 0, 180, 360,
(255, 255, 255), -1)
img = Image.fromarray(np.uint8(mask[:, :, 0]), 'L')
# make beziers
for drop in listFinalDrops:
if (drop.shape == 2):
img = Image.fromarray(np.uint8(img), 'L')
draw = ImageDraw.Draw(img)
ts = [t / 100.0 for t in range(101)]
xys = [(drop.radius * C[0] - 2 * drop.radius + drop.center[0],
drop.radius * C[1] - 3 * drop.radius + drop.center[1]),
(drop.radius * B[0] - 2 * drop.radius + drop.center[0],
drop.radius * B[1] - 3 * drop.radius + drop.center[1]),
(drop.radius * D[0] - 2 * drop.radius + drop.center[0],
drop.radius * D[1] - 3 * drop.radius + drop.center[1])]
bezier = make_bezier(xys)
points = bezier(ts)
xys = [(drop.radius * C[0] - 2 * drop.radius + drop.center[0],
drop.radius * C[1] - 3 * drop.radius + drop.center[1]),
(drop.radius * A[0] - 2 * drop.radius + drop.center[0],
drop.radius * A[1] - 3 * drop.radius + drop.center[1]),
(drop.radius * D[0] - 2 * drop.radius + drop.center[0],
drop.radius * D[1] - 3 * drop.radius + drop.center[1])]
bezier = make_bezier(xys)
points.extend(bezier(ts))
draw.polygon(points, fill='white')
mask = np.array(img)
im_mask = Image.fromarray(mask.astype('uint8'))
if ifReturnLabel:
output_label = np.array(alpha_map)
output_label.flags.writeable = True
output_label[output_label > 0] = 1
output_label = Image.fromarray(output_label.astype('uint8'))
return PIL_bg_img, output_label, im_mask
return PIL_bg_img
def generateDrops_np(img_np, cfg, listFinalDrops):
"""Generate raindrops on the image.
:param imgs: numpy imgs shape -> [B, H, W, C], type -> np.uint8
:param cfg: config with global constants
:param listFinalDrops: final list of raindrop class objects after handling collisions
:param label_map: general label map of all drops in the image
"""
ifReturnLabel = cfg['return_label']
edge_ratio = cfg['edge_darkratio']
# PIL_bg_img = Image.open(imagePath)
# label_map = np.zeros_like(bg_img)[:,:,0]
# imgh, imgw, _ = bg_img.shape
bg_img = img_np
label_map = np.zeros_like(bg_img)[:, :, 0] # [H, W]
imgh, imgw, _ = bg_img.shape
A = cfg['A']
B = cfg['B']
C = cfg['C']
D = cfg['D']
# 0. generate alpha change map by generated list raindrops
alpha_map = np.zeros_like(label_map).astype(np.float64) # [H, W]
for drop in listFinalDrops:
(ix, iy) = drop.getCenters()
radius = drop.getRadius()
ROI_WL = 2 * radius
ROI_WR = 2 * radius
ROI_HU = 3 * radius
ROI_HD = 2 * radius
if (iy - 3 * radius) < 0:
ROI_HU = iy
if (iy + 2 * radius) > imgh:
ROI_HD = imgh - iy
if (ix - 2 * radius) < 0:
ROI_WL = ix
if (ix + 2 * radius) > imgw:
ROI_WR = imgw - ix
drop_alpha = drop.getAlphaMap()
alpha_map[iy - ROI_HU:iy + ROI_HD,
ix - ROI_WL:ix + ROI_WR] += drop_alpha[3 * radius - ROI_HU:3 * radius + ROI_HD,
2 * radius - ROI_WL:2 * radius + ROI_WR]
alpha_map = alpha_map / np.max(alpha_map) * 255.0
PIL_bg_img = Image.fromarray(np.uint8(bg_img)).convert('RGB')
# convert
for idx, drop in enumerate(listFinalDrops):
(ix, iy) = drop.getCenters()
radius = drop.getRadius()
ROIU = iy - 3 * radius
ROID = iy + 2 * radius
ROIL = ix - 2 * radius
ROIR = ix + 2 * radius
if (iy - 3 * radius) < 0:
ROIU = 0
ROID = 5 * radius
if (iy + 2 * radius) > imgh:
ROIU = imgh - 5 * radius
ROID = imgh
if (ix - 2 * radius) < 0:
ROIL = 0
ROIR = 4 * radius
if (ix + 2 * radius) > imgw:
ROIL = imgw - 4 * radius
ROIR = imgw
tmp_bg = bg_img[ROIU:ROID, ROIL:ROIR]
try:
drop.updateTexture(tmp_bg)
except Exception:
del listFinalDrops[idx]
continue
tmp_alpha_map = alpha_map[ROIU:ROID, ROIL:ROIR]
output = drop.getTexture()
tmp_output = np.asarray(output).astype(np.float)[:, :, -1]
tmp_alpha_map = tmp_alpha_map * (tmp_output / 255)
tmp_alpha_map = Image.fromarray(tmp_alpha_map.astype('uint8'))
edge = ImageEnhance.Brightness(output)
edge = edge.enhance(edge_ratio)
# PIL_bg_img.paste(edge, (ix-2*radius, iy-3*radius), output)
# PIL_bg_img.paste(output, (ix-2*radius, iy-3*radius), output)
PIL_bg_img.paste(edge, (ROIL, ROIU), output)
PIL_bg_img.paste(output, (ROIL, ROIU), output)
# mask process part
mask = np.zeros_like(bg_img)
if len(listFinalDrops) > 0:
# make circles and elipses
for drop in listFinalDrops:
if (drop.shape == 0):
cv2.circle(mask, drop.center, drop.radius, (255, 255, 255), -1)
if (drop.shape == 1):
cv2.circle(mask, drop.center, drop.radius, (255, 255, 255), -1)
cv2.ellipse(mask, drop.center, (drop.radius, int(1.3 * math.sqrt(3) * drop.radius)), 0, 180, 360,
(255, 255, 255), -1)
img = Image.fromarray(np.uint8(mask[:, :, 0]), 'L')
# make beziers
for drop in listFinalDrops:
if (drop.shape == 2):
img = Image.fromarray(np.uint8(img), 'L')
draw = ImageDraw.Draw(img)
ts = [t / 100.0 for t in range(101)]
A0, A1 = drop.control_point['A'][0], drop.control_point['A'][1]
B0, B1 = drop.control_point['B'][0], drop.control_point['B'][1]
C0, C1 = drop.control_point['C'][0], drop.control_point['C'][1]
D0, D1 = drop.control_point['D'][0], drop.control_point['D'][1]
xys = [(drop.radius * C0 - 2 * drop.radius + drop.center[0],
drop.radius * C1 - 3 * drop.radius + drop.center[1]),
(drop.radius * B0 - 2 * drop.radius + drop.center[0],
drop.radius * B1 - 3 * drop.radius + drop.center[1]),
(drop.radius * D0 - 2 * drop.radius + drop.center[0],
drop.radius * D1 - 3 * drop.radius + drop.center[1])]
bezier = make_bezier(xys)
points = bezier(ts)
xys = [(drop.radius * C0 - 2 * drop.radius + drop.center[0],
drop.radius * C1 - 3 * drop.radius + drop.center[1]),
(drop.radius * A0 - 2 * drop.radius + drop.center[0],
drop.radius * A1 - 3 * drop.radius + drop.center[1]),
(drop.radius * D0 - 2 * drop.radius + drop.center[0],
drop.radius * D1 - 3 * drop.radius + drop.center[1])]
bezier = make_bezier(xys)
points.extend(bezier(ts))
draw.polygon(points, fill='white')
mask = np.array(img)
im_mask = Image.fromarray(mask.astype('uint8'))
if ifReturnLabel:
output_label = np.array(alpha_map)
output_label.flags.writeable = True
output_label[output_label > 0] = 1
output_label = Image.fromarray(output_label.astype('uint8'))
return PIL_bg_img, output_label, im_mask
return PIL_bg_img