スペクトルエアブラッシング(Python、PIL、scipy)
これは、洗練された数学的アルゴリズムを使用してカラフルなナンセンスを生成します。このアルゴリズムは、GoogleのPageRankアルゴリズムに関連していますが、Webページではなくピクセル用です。
このアプローチを採用したのは、塗りつぶしベースの方法とは異なり、鶏肉や木のような画像に対処できる可能性があると考えたためです。ご覧のとおり、それは一種の作品ですが、空のさまざまな部分を異なる色で着色する傾向があります
数学的には、画像の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))