光谱喷枪(Python,PIL,scipy)
这使用了复杂的数学算法来产生色彩丰富的废话。该算法与Google的PageRank算法有关,但适用于像素而不是网页。
我之所以采用这种方法,是因为我认为与基于洪水填充的方法不同,它可能能够处理像鸡和树这样的图像,其中的形状并没有完全被黑线包围。如您所见,虽然它也倾向于在天空的不同部分以不同的颜色进行着色,但它确实可以工作
对于具有数学思维的人:它的工作本质上是构造图像中while像素的邻接图,然后找到图拉普拉斯算子的前25个特征向量。(除了不尽然,因为我们确实包括了深色像素,我们只是给它们的连接赋予了较低的权重。这有助于处理抗锯齿,并且总体上似乎也可以提供更好的结果。)找到特征向量之后,它创建了一个由它们的反特征值加权对它们进行随机线性组合,以形成输出图像的RGB分量。
为了计算时间,在执行所有这些操作之前先将图像缩小,然后再次放大,然后再乘以原始图像。尽管如此,它仍然无法快速运行,在我的机器上大约要花费2到10分钟,具体取决于输入的图像,尽管由于某种原因,鸡肉只花了17分钟。
通过制作一个交互式应用程序,您可以在其中控制每个特征向量的颜色和强度,实际上有可能将这个想法变成有用的东西。这样,您可以淡出将天空划分为不同部分的图像,并淡入那些可以吸收图像相关特征的图像。但是我没有计划自己做:)
以下是输出图像:
(在南瓜上效果不佳,所以我省略了那个。)
这是代码:
import sys
from PIL import Image
import numpy as np
import scipy.sparse as sp
import scipy.sparse.linalg as spl
import os
import time
start_time = time.time()
filename = sys.argv[1]
img = Image.open(filename)
orig_w, orig_h = img.size
# convert to monochrome and remove any alpha channel
# (quite a few of the inputs are transparent pngs)
img = img.convert('LA')
pix = img.load()
for x in range(orig_w):
for y in range(orig_h):
l, a = pix[x,y]
l = (255-a) + a*l/255
a = 255
pix[x,y] = l,a
img = img.convert('L')
orig_img = img.copy()
# resize to 300 pixels wide - you can get better results by increasing this,
# but it takes ages to run
orig_w, orig_h = img.size
print "original size:", str(orig_w)+ ', ' + str(orig_h)
new_w = 300
img = img.resize((new_w, orig_h*new_w/orig_w), Image.ANTIALIAS)
pix = img.load()
w, h = img.size
print "resizing to", str(w)+', '+str(h)
def coords_to_index(x, y):
return x*h+y
def index_to_coords(i):
return (int(i/h), i%h)
print "creating matrix"
A = sp.lil_matrix((w*h,w*h))
def setlink(p1x, p1y, p2x, p2y):
i = coords_to_index(p1x,p1y)
j = coords_to_index(p2x,p2y)
ci = pix[p1x,p1y]/255.
cj = pix[p2x,p2y]/255.
if ci*cj > 0.9:
c = 1
else:
c = 0.01
A[i,j] = c
return c
for x in range(w):
for y in range(h):
d = 0.
if x>0:
d += setlink(x,y,x-1,y)
if x<w-1:
d += setlink(x,y,x+1,y)
if y>0:
d += setlink(x,y,x,y-1)
if y<h-1:
d += setlink(x,y,x,y+1)
i = coords_to_index(x,y)
A[i,i] = -d
A = A.tocsr()
# the greater this number, the more details it will pick up on. But it increases
# execution time, and after a while increasing it won't make much difference
n_eigs = 25
print "finding eigenvectors (this may take a while)"
L, V = spl.eigsh(A, k=n_eigs, tol=1e-12, which='LA')
print "found eigenvalues", L
out = Image.new("RGB", (w, h), "white")
out_pix = out.load()
print "painting picutre"
V = np.real(V)
n = np.size(V,0)
R = np.zeros(n)
G = np.zeros(n)
B = np.zeros(n)
for k in range(n_eigs-1):
weight = 1./L[k]
R = R + V[:,k]*np.random.randn()*weight
G = G + V[:,k]*np.random.randn()*weight
B = B + V[:,k]*np.random.randn()*weight
R -= np.min(R)
G -= np.min(G)
B -= np.min(B)
R /= np.max(R)
G /= np.max(G)
B /= np.max(B)
for x in range(w):
for y in range(h):
i = coords_to_index(x,y)
r = R[i]
g = G[i]
b = B[i]
pixval = tuple(int(v*256) for v in (r,g,b))
out_pix[x,y] = pixval
out = out.resize((orig_w, orig_h), Image.ANTIALIAS)
out_pix = out.load()
orig_pix = orig_img.load()
for x in range(orig_w):
for y in range(orig_h):
r,g,b = out_pix[x,y]
i = orig_pix[x,y]/255.
out_pix[x,y] = tuple(int(v*i) for v in (r,g,b))
fname, extension = os.path.splitext(filename)
out.save('out_' + fname + '.png')
print("completed in %s seconds" % (time.time() - start_time))