用PythonNumpy创造霓虹辉光

evrscar2  于 2022-11-10  发布在  Python
关注(0)|答案(2)|浏览(199)

我正在尝试用源图像创建霓虹灯效果。我已经包括了三张图片,来源,我目前的尝试和目标。该程序获取图像,找到白色边缘,并计算每个像素到最近的白色边缘的距离(这些部分都很好用);从那里,我努力寻找正确的饱和度和值参数来创建霓虹灯发光。
从目标图像来看,我需要的基本上是白色边缘上的饱和度为0,然后显著增加它离边缘越远;对于值,我需要白色边缘上的饱和度为1,然后急剧减小。我找不出处理Distance_Image(它保存每个像素到最近的白色边缘的距离)的最佳方法,比如使用饱和度和值来实现这两个结果。

from PIL import Image
import cv2
import numpy as np
from scipy.ndimage import binary_erosion
from scipy.spatial import KDTree

def find_closest_distance(img):
    white_pixel_points = np.array(np.where(img))
    tree = KDTree(white_pixel_points.T)
    img_meshgrid = np.array(np.meshgrid(np.arange(img.shape[0]),
                                        np.arange(img.shape[1]))).T
    distances, _ = tree.query(img_meshgrid)
    return distances

def find_edges(img):
    img_np = np.array(img)
    kernel = np.ones((3,3))
    return img_np - binary_erosion(img_np, kernel)*255

img = Image.open('a.png').convert('L')
edge_image = find_edges(img)
distance_image = find_closest_distance(edge_image)
max_dist = np.max(distance_image)
distance_image = distance_image / max_dist

hue = np.full(distance_image.shape, 0.44*180)
saturation = distance_image * 255
value = np.power(distance_image, 0.2)
value = 255 * (1 - value**2)

new_tups = np.dstack((hue, saturation, value)).astype('uint8')
new_tups = cv2.cvtColor(new_tups, cv2.COLOR_HSV2BGR)
new_img = Image.fromarray(new_tups, 'RGB').save('out.png')

下图显示了源数据(左)、当前结果(中)和所需结果(右)。

nhaq1z21

nhaq1z211#

我想我会用convolution来做这件事。将图像与Gaussian kernel进行卷积是blur an image的常见方法。您可以使用多种方法来完成此操作,但可能最容易使用的是scipy.ndimage.gaussian_filter。这里有一种实现所有这些的方法,看看你是否喜欢结果。

from PIL import Image
from io import BytesIO
import requests
import numpy as np

r = requests.get('https://i.stack.imgur.com/MhUQZ.png')
img = Image.open(BytesIO(r.content))
imarray = np.asarray(img)[..., 0] / 255

这是你的第一张图片,白色长方形。
现在,我将制作这些轮廓,进行模糊处理,创建彩色图像,然后将它们组合在一起:

from scipy.ndimage import binary_erosion
from scipy.ndimage import gaussian_filter

eroded = binary_erosion(imarray, iterations=3)

# Make the outlined rectangles.

outlines = imarray - eroded

# Convolve with a Gaussian to effect a blur.

blur = gaussian_filter(outlines, sigma=11)

# Make binary images into neon green.

neon_green_rgb = [0.224, 1.0, 0.0784]
outlines = outlines[:, :, None] * neon_green_rgb
blur = blur[:, :, None] * neon_green_rgb

# Combine the images and constrain to [0, 1].

blur_strength = 3
glow = np.clip(outlines + blur_strength*blur, 0, 1)

然后看看它:

import matplotlib.pyplot as plt

plt.imshow(glow)

您需要调整高斯的sigma(其宽度)、颜色、模糊强度等。希望能有所帮助。

1u4esq0p

1u4esq0p2#

以下是在Python/OpenCV中执行此操作的一种方法。

  • 阅读输入
  • 转换为灰度
  • 二进制的阈值
  • 使用形态渐变获得所需厚度的边缘
  • 在白色背景上将边缘反转为黑色
  • 进行距离变换
  • 拉伸至全动态范围
  • 反转
  • 通过除以最大值来归一化到0到1的范围
  • 使用幂定律控制距离滚落(坡度)进行衰减
  • 创建具有输入大小和所需颜色的彩色图像
  • 将衰减图像乘以彩色图像
  • 保存结果

输入:

import cv2
import numpy as np
import skimage.exposure

# read input

img = cv2.imread('rectangles.png')

# convert to grayscale

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# threshold

thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]

# do morphology gradient to get edges and invert so black edges on white background

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
edges = cv2.morphologyEx(thresh, cv2.MORPH_GRADIENT, kernel)
edges = 255 - edges

# get distance transform

dist = edges.copy()
distance = cv2.distanceTransform(dist, distanceType=cv2.DIST_L2, maskSize=3)
print(np.amin(distance), np.amax(distance))

# stretch to full dynamic range and convert to uint8 as 3 channels

stretch = skimage.exposure.rescale_intensity(distance, in_range=('image'), out_range=(0,255))

# invert

stretch = 255 - stretch
max_stretch = np.amax(stretch)

# normalize to range 0 to 1 by dividing by max_stretch

stretch = (stretch/max_stretch)

# attenuate with power law

pow = 4
attenuate = np.power(stretch, pow)
attenuate = cv2.merge([attenuate,attenuate,attenuate])

# create a green image the size of the input

color_img = np.full_like(img, (0,255,0), dtype=np.float32)

# multiply the color image with the attenuated distance image

glow = (color_img * attenuate).clip(0,255).astype(np.uint8)

# save results

cv2.imwrite('rectangles_edges.png', edges)
cv2.imwrite('rectangles_stretch.png', (255*stretch).clip(0,255).astype(np.uint8))
cv2.imwrite('rectangles_attenuate.png', (255*attenuate).clip(0,255).astype(np.uint8))
cv2.imwrite('rectangles_glow.png', glow)

# view results

cv2.imshow("EDGES", edges)
cv2.imshow("STRETCH", stretch)
cv2.imshow("ATTENUATE", attenuate)
cv2.imshow("RESULT", glow)
cv2.waitKey(0)

边(反转):

拉伸距离变换:

衰减距离变换:

光晕结果:

相关问题