Created
January 13, 2018 16:10
-
-
Save setupminimal/a53a703e43d2f06fb62de4747c12b75c to your computer and use it in GitHub Desktop.
A program to make 'dueling watercolors'
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy | |
from PIL import Image | |
import random | |
import os | |
WIDTH, HEIGHT = 30, 30 | |
SCALE = 10 | |
randData = numpy.random.rand(WIDTH, HEIGHT, 3) * 255 | |
match = numpy.random.rand(WIDTH, HEIGHT, 3) * 255 | |
border = numpy.random.rand(WIDTH, 1, 3) * 0 | |
blue = numpy.random.rand(WIDTH, 1, 3) * 0 | |
red = numpy.random.rand(WIDTH, 1, 3) * 0 | |
white = numpy.random.rand(WIDTH, 1, 3) * 0 | |
blue[:, :] = (0, 0, 255) | |
red[:, :] = (255, 0, 0) | |
white[:, :] = 255 | |
i = 0 | |
def save(thinking=None, fade=0.5): | |
global i | |
order = None | |
if thinking is not None: | |
order = (randData, border, thinking * (1 - (fade*2 - 1)**2), border, match) | |
else: | |
order = (randData, border, border, border, match) | |
toShow = numpy.concatenate(order, axis = 1) | |
image = Image.fromarray(toShow.astype('uint8')).convert('RGBA') | |
image.resize((WIDTH*SCALE*2 + SCALE*3, HEIGHT*SCALE), resample = Image.NEAREST).save("images/{:0>6}.png".format(i)) | |
i += 1 | |
def sortish(p1, p2): | |
a, b = p1 | |
x, y = p2 | |
if -1 <= a - x <= 1 and -1 <= b - y <= 1: | |
return 0 | |
else: | |
return (a - x) * (b - y) | |
pixels = [(a, b) for a in xrange(WIDTH) for b in xrange(HEIGHT)] | |
random.shuffle(pixels) | |
#pixels.sort(cmp=sortish) | |
brushes = [[(1, 0), (1, 1), (0, 1), (-1, 0), (-1, -1), (0, -1), (-1, 1), (1, -1)], | |
[(1, 0), (0, 1), (-1, 0), (0, -1)]] | |
def sstep(toChange, other): | |
orig = numpy.sum((toChange - other)**2) | |
for q in xrange(24): | |
if len(pixels) == 0: | |
break | |
best = pixels[0] | |
brush = brushes[0] | |
score = numpy.sum((toChange - other)**2) | |
for pixel in pixels: | |
a, b = pixel | |
for offsets in brushes: | |
trial = numpy.copy(toChange) | |
for da, db in offsets: | |
trial[(a + da) % WIDTH, (b + db) % HEIGHT] = (trial[a, b] + trial[(a + da * 2) % WIDTH, (b + db *2) % HEIGHT]) / 2 | |
trialScore = numpy.sum((trial - other)**2) | |
if trialScore < score: | |
best = pixel | |
score = trialScore | |
brush = offsets | |
a, b = best | |
for da, db in brush: | |
toChange[(a + da) % WIDTH, (b + db) % HEIGHT] = (toChange[a, b] + toChange[(a + da * 2) % WIDTH, (b + db *2) % HEIGHT]) / 2 | |
#pixels.remove(best) | |
save() | |
if orig < score + (25000/(30.0*30)*WIDTH*HEIGHT): | |
return True | |
return False | |
prev = 0 | |
while True: | |
for q in range(6): | |
save(thinking=blue, fade=q/6.0) | |
f = sstep(randData, match) | |
for q in range(6): | |
save(thinking=red, fade=q/6.0) | |
g = sstep(match, randData) | |
if f and g: | |
print "Optimum" | |
break | |
if i >= 24*60*10: | |
print "Timeout" | |
break | |
score = numpy.sum((randData - match)**2) | |
print "{:0>6} - {} - {}".format(i, score, prev - score) | |
prev = score | |
for q in range(48): | |
save(thinking=white, fade=q/48.0) | |
os.system("ffmpeg -f image2 -r 12 -i \"images/%06d.png\" -vcodec vp9 -strict -2 -y movie.mp4") | |
os.system("rm images/*.png") | |
print "Done!" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment