使用 python numpy 创建霓虹灯

use*_*293 2 python arrays opencv numpy image-processing

我正在尝试使用源图像创建霓虹灯效果。我包含了三张图片:来源、我当前的尝试和目标。该程序获取图像,找到白边,并计算每个像素到最近的白边的距离(这些部分都工作正常);从那里开始,我正在努力寻找正确的饱和度和值参数来创建霓虹灯。

从目标图像来看,我需要做的基本上是使白边缘的饱和度为 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')
Run Code Online (Sandbox Code Playgroud)

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

来源 当前的 目标

fmw*_*w42 5

这是在 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)
Run Code Online (Sandbox Code Playgroud)

边缘(倒置):

在此输入图像描述

拉伸距离变换:

在此输入图像描述

衰减距离变换:

在此输入图像描述

发光结果:

在此输入图像描述