스펙트럼 에어 브러싱 (Python, PIL, scipy)
이것은 정교한 수학적 알고리즘을 사용하여 다채로운 넌센스를 생성합니다. 이 알고리즘은 Google의 PageRank 알고리즘과 관련이 있지만 웹 페이지 대신 픽셀에 적용됩니다.
홍수 접근 기반 방법과 달리 닭과 나무와 같은 이미지에 완전히 대처할 수 없을 것이라고 생각했기 때문에이 접근법을 취했습니다. 검은 선으로 완전히 둘러싸이지 않은 모양이 있습니다. 보시다시피, 그것은 하늘의 다른 부분에서 다른 색상으로 착색되는 경향이 있지만 일종의 작품입니다.
수학적으로 생각하는 것 : 그것이하는 일은 본질적으로 이미지의 while 픽셀의 인접 그래프를 구성 한 다음 그래프 Laplacian의 상위 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))