from IPython.display import Image
Image(filename="./output3.png")
# Result:
import cairo, math, spectra
from tqdm import tqdm_notebook as tqdm
def polar(r, a):
return (r * math.cos(a / 180 * math.pi), r * math.sin(a / 180 * math.pi))
def clamp(t):
if t < 0:
return 0
if t > 1:
return 1
return t
def mix(v0, v1, t):
return v0 * (1 - t) + v1 * t
def hcl(h, c, l, alpha=1):
r, g, b = spectra.lch(l, c, h).rgb
return (clamp(r), clamp(g), clamp(b), alpha)
def line(pt0, pt1):
ctx.new_path()
ctx.move_to(*pt0)
ctx.line_to(*pt1)
ctx.stroke()
def circle(pos, r, stroke=False):
ctx.new_path()
x, y = pos
ctx.arc(x, y, r, 0, 2 * math.pi)
if stroke:
ctx.stroke()
else:
ctx.fill()
def rnd(mx):
return random.random() * mx
def rint(mx):
return math.floor(rnd(mx))
def prob(p):
return random.random() < p
def quant(val, step):
return round(val / step) * step
def rdeg2():
return 2 ** rint(MAX_DEG)
def variate(val, mn, mx, disp = 1, tmax = 1):
new_val = mn + random.random() * (mx - mn)
t = random.random() ** disp * tmax
return val * (1 - t) + new_val * t
def divide(subset):
# random.seed(subset['seed1'])
if prob(0.2):
d1 = rdeg2()
d2 = rdeg2()
d3 = rint(d2)
def flt(x, y):
return (x // d1) % d2 < d3
elif prob(0.5):
d1 = rdeg2()
d2 = rdeg2()
d3 = rint(d2)
def flt(x, y):
return (y // d1) % d2 < d3
elif prob(1):
x0, x1 = sorted([rnd(WIDTH), rnd(WIDTH)])
y0, y1 = sorted([rnd(HEIGHT), rnd(HEIGHT)])
def flt(x, y):
return x0 <= x <= x1 and y0 <= y <= y1
if prob(0.01):
color1 = subset['color']
color2 = [rnd(360), rnd(100), rnd(100)]
elif prob(1):
h, s, l = subset['color']
color1 = [h, s, l]
tmax = 0.2
color2 = [
variate(h, 0, 360, subset['level'], tmax),
variate(s, 0, 100, subset['level'], tmax),
variate(l, 0, 100, subset['level'], tmax),
]
subsets = sorted([{
'level': subset['level'] + 1,
'pixels': [(x, y) for x, y in subset['pixels'] if flt(x, y)]
}, {
'level': subset['level'] + 1,
'pixels': [(x, y) for x, y in subset['pixels'] if not flt(x, y)]
}], key=lambda x: -len(x['pixels']))
subsets[0]['color'] = color1
subsets[1]['color'] = color2
return [subset for subset in subsets if len(subset['pixels']) > 0]
DOWNSCALE = 1
WIDTH, HEIGHT = 1920 // DOWNSCALE, 1080 // DOWNSCALE
MAX_DEG = math.floor(math.log(HEIGHT) / math.log(2))
subsets = []
subsets.append({
'level': 1,
'pixels': set([(i, j) for i in range(WIDTH) for j in range(HEIGHT)]),
'color': [100, 100, 100],
'seed1': 0,
'seed2': 0,
})
import random
random.seed(2)
for i in tqdm(range(100)):
new_subsets = []
for subset in subsets:
for new_subset in divide(subset):
if len(new_subset['pixels']) == 0:
continue
new_subsets.append(new_subset)
subsets = new_subsets
HBox(children=(IntProgress(value=0), HTML(value='')))
import json
old_subsets = json.dumps(subsets)
subsets = json.loads(old_subsets)
subsets.sort(key=lambda x: x['color'][0])
for no, subset in enumerate(subsets):
subset['color'][0] = no / len(subsets) * 360
subsets.sort(key=lambda x: x['color'][1])
for no, subset in enumerate(subsets):
subset['color'][1] = (no / len(subsets)) ** 2 * 100
subsets.sort(key=lambda x: x['color'][2])
accum = 0
for no, subset in enumerate(subsets):
accum += len(subset['pixels'])
subset['color'][2] = mix(accum / WIDTH / HEIGHT, 1, clamp(math.log(1 + len(subset['pixels'])) / 10)) * 100
subsets.sort(key=lambda x: -len(x['pixels']))
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH * DOWNSCALE, HEIGHT * DOWNSCALE)
ctx = cairo.Context(surface)
ctx.set_source_rgba(*hcl(0, 0, 0))
ctx.paint()
ctx.scale(DOWNSCALE, DOWNSCALE)
for subset in subsets:
pat = cairo.LinearGradient(0.0, 0.0, WIDTH, HEIGHT)
h, c, l = subset['color']
t0 = rnd(2 / 3)
t1 = t0 + 1 / 3
if prob(0.0):
t0, t1 = t1, t0
pat.add_color_stop_rgba(t0, *hcl(h, c, l * 0.9))
pat.add_color_stop_rgba(t1, *hcl(h, c, l * 0.2))
ctx.set_source(pat)
ctx.new_path()
for x, y in subset['pixels']:
ctx.rectangle(x, y, 1, 1)
ctx.fill()
surface.write_to_png('output.png')