def test_gamma(): source = path('gamma_dalai_lama_gray.jpg') dalai_lama = snowy.load(source) snowy.show(dalai_lama) small = snowy.resize(dalai_lama, height=32) snowy.save(small, path('small_dalai_lama.png')) snowy.show(small)
def test_magnification(): i = create_circle(8, 8) a = snowy.resize(i, 100, 100, snowy.NEAREST) b = snowy.resize(i, 100, 100, snowy.TRIANGLE) c = snowy.resize(i, 100, 100, snowy.GAUSSIAN) e = snowy.resize(i, 100, 100, snowy.MITCHELL) d = snowy.resize(i, 100, 100, snowy.LANCZOS) f = snowy.resize(i, 100, 100) snowy.show(np.hstack([a, b, c, d, e, f]))
def test_minification(): n = snowy.generate_noise(1000, 1000, frequency=5, seed=42) n = 0.5 + 0.5 * np.sign(n) a = snowy.resize(n, 100, 100) b = snowy.resize(n, 100, 100, snowy.MITCHELL) c = snowy.resize(n, 100, 100, snowy.GAUSSIAN) d = snowy.resize(n, 100, 100, snowy.NEAREST) x = [a, b, c, d] + [create_circle(100, 100)] snowy.show(np.hstack(x))
def test_coords(): h, w = 800, 800 height, width = h, w # Draw seed image cyan = np.full([h, w, 3], np.float64([(27, 56, 80)]) / 200) pink = np.full([h, w, 3], np.float64([175, 111, 127]) / 255) orange = np.full([h, w, 3], np.float64([239, 159, 95]) / 255) yellow = np.full([h, w, 3], np.float64([239, 207, 95]) / 255) colors = np.zeros([h, w, 3]) def max_color(v): return np.maximum(colors, v) def sub_color(v): return colors * (1 - v) colors = max_color(create_circle(w, h, 0.37, [0.4, 0.5]) * cyan) colors = max_color(create_circle(w, h, 0.37, [0.6, 0.4]) * cyan) colors = max_color(create_circle(w, h, 0.27, [0.7, 0.6]) * cyan) colors = sub_color(create_circle(w, h, 0.35, [0.4, 0.5])) colors = sub_color(create_circle(w, h, 0.35, [0.6, 0.4])) colors = sub_color(create_circle(w, h, 0.25, [0.7, 0.6])) colors = max_color(create_circle(w, h, 0.01, [0.4, 0.5]) * orange) colors = max_color(create_circle(w, h, 0.01, [0.6, 0.4]) * pink) colors = max_color(create_circle(w, h, 0.01, [0.7, 0.6]) * yellow) colors = sn.linearize(colors) # Create generalized voronoi luma = sn.reshape(np.sum(colors, 2)) coords = sn.generate_cpcf(luma != 0) voronoi = sn.dereference_cpcf(colors, coords) # Warp the voronoi warpx, warpy = width / 15, height / 15 noise = sn.generate_fBm(width, height, 4, 4, 3) i, j = np.arange(width, dtype='i2'), np.arange(height, dtype='i2') coords = np.dstack(np.meshgrid(i, j, sparse=False)) warpx = warpx * np.cos(noise * math.pi * 2) warpy = warpy * np.sin(noise * math.pi * 2) coords += np.int16(np.dstack([warpx, warpy])) coords[:, :, 0] = np.clip(coords[:, :, 0], 0, width - 1) coords[:, :, 1] = np.clip(coords[:, :, 1], 0, height - 1) warped = sn.dereference_cpcf(voronoi, coords) strip = [sn.resize(i, height=256) for i in (colors, voronoi, warped)] sn.show(sn.hstack(strip))
def test_udf(): c0 = create_circle(200, 200, 0.3) c1 = create_circle(200, 200, 0.08, 0.8, 0.8) c0 = np.clip(c0 + c1, 0, 1) circles = snowy.add_border(c0, value=1) mask = circles != 0.0 udf = snowy.unitize(snowy.generate_udf(mask)) nx, ny = snowy.gradient(udf) grad = snowy.unitize(nx + ny) snowy.show(snowy.hstack([circles, udf, grad]))
def test_tweet(): import snowy as sn, numpy as np im = sn.generate_noise(2000, 500, 5, seed=2, wrapx=True) df = sn.generate_sdf(im < 0.0, wrapx=True) im = 0.5 + 0.5 * np.sign(im) - im cl = lambda L, U: np.where(np.logical_and(df > L, df < U), -im, 0) im += cl(20, 30) + cl(60, 70) + cl(100, 110) sn.show(sn.resize(im, height=100, wrapx=True)) sn.show(sn.resize(np.hstack([im, im]), height=200, wrapx=True))
def draw_quad(): verts = np.array([[-0.67608007, 0.38439575, 3.70544936, 0., 0. ], [-0.10726266, 0.38439575, 2.57742041, 1., 0. ], [-0.10726266, -0.96069041, 2.57742041, 1., 1. ], [-0.67608007, -0.96069041, 3.70544936, 0., 1. ]]) texture = snowy.load(qualify('../tests/texture.png')) target = np.full((1080, 1920, 4), (0.54, 0.54, 0.78, 1.00), dtype=np.float32) snowy.draw_polygon(target, texture, verts) target = snowy.resize(target[400:770, 700:1000], height = 256) texture = snowy.resize(texture, height = 256) quad = snowy.hstack([texture, target]) snowy.export(quad, qualify('quad.png')) snowy.show(quad)
def test_normals(): isle = create_island(10) height, width, nchan = isle.shape occlusion = np.empty([height, width, 1]) seconds = timeit.timeit( lambda: np.copyto(occlusion, sn.compute_skylight(isle)), number=1) print(f'\ncompute_skylight took {seconds} seconds') normals = np.empty([height - 1, width - 1, 3]) seconds = timeit.timeit( lambda: np.copyto(normals, sn.compute_normals(isle)), number=1) print(f'\ncompute_normals took {seconds} seconds') normals = sn.resize(normals, 750, 512) # Flatten the normals according to landmass versus sea. normals += np.float64([0, 0, 100]) * np.where(isle < 0.0, 1.0, 0.005) normals /= sn.reshape(np.sqrt(np.sum(normals * normals, 2))) # Compute the lambertian diffuse factor lightdir = np.float64([0.2, -0.2, 1]) lightdir /= np.linalg.norm(lightdir) df = np.clip(np.sum(normals * lightdir, 2), 0, 1) df = sn.reshape(df) df *= occlusion # Apply color LUT gradient_image = sn.resize(sn.load(path('terrain.png')), width=1024)[:, :, :3] def applyColorGradient(elevation): xvals = np.arange(1024) yvals = gradient_image[0] apply_lut = interpolate.interp1d(xvals, yvals, axis=0) el = np.clip(1023 * elevation, 0, 1023) return apply_lut(sn.unshape(el)) albedo = applyColorGradient(isle * 0.5 + 0.5) albedo *= df # Visualize the lighting layers normals = 0.5 * (normals + 1.0) isle = np.dstack([isle, isle, isle]) occlusion = np.dstack([occlusion, occlusion, occlusion]) df = np.dstack([df, df, df]) island_strip = sn.resize(sn.hstack([occlusion, normals, df, albedo]), height=256) sn.save(island_strip, 'docs/island_strip.png') sn.show(island_strip)
def test_gdf(): "This is a (failed) effort to create a smoother distance field." c0 = create_circle(200, 200, 0.3) c1 = create_circle(200, 200, 0.08, 0.8, 0.8) c0 = np.clip(c0 + c1, 0, 1) circles = snowy.add_border(c0, value=1) circles = np.clip(snowy.blur(circles, radius=2), 0, 1) circles = np.clip(snowy.blur(circles, radius=2), 0, 1) source = (1.0 - circles) * 2000.0 gdf = np.sqrt(snowy.generate_gdf(source)) gdf = snowy.unitize(gdf) nx, ny = snowy.gradient(gdf) grad = snowy.unitize(nx + ny) snowy.show(snowy.hstack([circles, gdf, grad]))
def test_range(): source = path('../docs/ground.jpg') ground = snowy.load(source) assert np.amin(ground) >= 0 and np.amax(ground) <= 1 with tempfile.NamedTemporaryFile() as fp: target = fp.name + '.png' snowy.save(ground, target) show_filename(target) show_filename(source) show_array(ground) blurred = snowy.blur(ground, radius=10) snowy.show(blurred)
def test_tileable(): n = snowy.generate_noise(200, 400, frequency=4, seed=42, wrapx=True) n = 0.5 + 0.5 * np.sign(n) - n n = np.hstack([n, n]) gold = snowy.resize(n, 200, 200) n = snowy.generate_noise(20, 40, frequency=4, seed=42, wrapx=True) n = 0.5 + 0.5 * np.sign(n) - n n = snowy.resize(n, 100, 200) bad = np.hstack([n, n]) n = snowy.generate_noise(20, 40, frequency=4, seed=42, wrapx=True) n = 0.5 + 0.5 * np.sign(n) - n n = snowy.resize(n, 100, 200, wrapx=True) good = np.hstack([n, n]) snowy.show(snowy.hstack([gold, bad, good], 2, .7))
def test_tileable_distance(): c0 = create_circle(400, 200, 0.3) c1 = create_circle(400, 200, 0.08, 0.8, 0.8) circles = np.clip(c0 + c1, 0, 1) mask = circles != 0.0 sdf = snowy.unitize(snowy.generate_sdf(mask, wrapx=True, wrapy=True)) nx, ny = snowy.gradient(sdf) grad = snowy.unitize(nx + ny) stack2 = np.hstack([sdf, sdf, grad, grad]) snowy.show(snowy.resize(np.vstack([stack2, stack2]), 600, 200)) get_mask = lambda L, U: np.logical_and(sdf > L, sdf < U) get_contour = lambda L, U: np.where(get_mask(L, U), sdf, 0) sdf -= get_contour(.20, .25) sdf -= get_contour(.60, .65) sdf -= get_contour(.90, .95) snowy.show(snowy.resize(np.hstack([sdf, sdf, sdf, sdf]), height=300))
def test_luminance(): source = sn.load('tests/sobel_input.png')[:, :, :3] L = rgb2gray(source) skresult = np.dstack([L, L, L]) small_skresult = sn.resize(skresult, width=256) L = sn.rgb_to_luminance(source) snresult = np.dstack([L, L, L]) small_snresult = sn.resize(snresult, width=256) L = skimage_sobel(source) sksobel = np.dstack([L, L, L]) small_sksobel = sn.resize(sksobel, width=256) L = sn.rgb_to_luminance(source) L = sn.compute_sobel(L) snsobel = np.dstack([L, L, L]) small_snsobel = sn.resize(snsobel, width=256) sn.show( np.hstack( [small_skresult, small_snresult, small_sksobel, small_snsobel]))
def test_thick(): source = sn.load('tests/sobel_input.png')[:, :, :3] small_source = sn.resize(source, width=256) blurred = sn.blur(source, radius=2) small_blurred = sn.resize(blurred, width=256) L = skimage_sobel(blurred) sksobel = np.dstack([L, L, L]) small_sksobel = sn.resize(sksobel, width=256) L = sn.rgb_to_luminance(blurred) L = sn.compute_sobel(L) snsobel = np.dstack([L, L, L]) small_snsobel = sn.resize(snsobel, width=256) small_sksobel = np.clip(1 - small_sksobel * 40, 0, 1) small_snsobel = np.clip(1 - small_snsobel * 40, 0, 1) strip = np.hstack([ small_blurred, small_source * small_sksobel, small_source * small_snsobel ]) sn.show(strip)
def test_draw_quad2(): target = np.full((1080, 1920, 4), (0, 0, 0, 0), dtype=np.float32) texture = snowy.load('tests/texture.png') # These are in NDC so they span -W to +W vertices = np.array([[-0.67608007, 0.38439575, 1.7601049, 3.70544936], [-0.10726266, 0.38439575, 0.60928749, 2.57742041], [-0.10726266, -0.96069041, 0.60928749, 2.57742041], [-0.67608007, -0.96069041, 1.7601049, 3.70544936]]) texcoords = np.array([[0., 0.], [1., 0.], [1., 1.], [0., 1.]]) x, y, w = vertices[:, 0], vertices[:, 1], vertices[:, 3] u, v = texcoords[:, 0], texcoords[:, 1] vertices = np.transpose(np.vstack([x, y, w, u, v])) print(vertices) snowy.draw_polygon(target, texture, vertices) overlay = snowy.load('tests/overlay.png') im = snowy.compose(target, overlay)[400:770, 600:900] target = snowy.resize(im, height=100) snowy.show(target)
gibbons = snowy.load(qualify('gibbons.jpg')) gibbons = snowy.resize(gibbons, width=gibbons.shape[1] // 5) gibbons90 = snowy.rotate(gibbons, 90) gibbons180 = snowy.rotate(gibbons, 180) gibbons270 = snowy.rotate(gibbons, 270) hflipped = snowy.hflip(gibbons) vflipped = snowy.vflip(gibbons) snowy.export(snowy.hstack([gibbons, gibbons180, vflipped], border_width=4, border_value=[0.5,0,0]), qualify("xforms.png")) # Test noise generation n = snowy.generate_noise(100, 100, frequency=4, seed=42, wrapx=True) n = np.hstack([n, n]) n = 0.5 + 0.5 * n snowy.show(n) snowy.export(n, qualify('noise.png')) # First try minifying grayscale gibbons = snowy.load(qualify('snowy.jpg')) gibbons = np.swapaxes(gibbons, 0, 2) gibbons = np.swapaxes(gibbons[0], 0, 1) gibbons = snowy.reshape(gibbons) source = snowy.resize(gibbons, height=200) blurry = snowy.blur(source, radius=4.0) diptych_filename = qualify('diptych.png') snowy.export(snowy.hstack([source, blurry]), diptych_filename) optimize(diptych_filename) snowy.show(diptych_filename)
# 1. Create falloff shape. import snowy import numpy as np from functools import reduce from scipy import interpolate width, height = 768, 256 x, y = np.linspace(-1, 1, width), np.linspace(-1, 1, height) u, v = np.meshgrid(x, y, sparse=True) falloff = np.clip(1 - (u * u + v * v), 0, 1) falloff = snowy.reshape(falloff / 2) snowy.show(falloff) # 2. Add layers of gradient noise and scale with falloff. noise = snowy.generate_noise noise = [noise(width, height, 6 * 2**f, int(f)) * 1 / 2**f for f in range(4)] noise = reduce(lambda x, y: x + y, noise) elevation = falloff * (falloff / 2 + noise) elevation = snowy.generate_udf(elevation < 0.1) elevation /= np.amax(elevation) snowy.show(elevation) # 3. Compute ambient occlusion. occlusion = snowy.compute_skylight(elevation) snowy.show(occlusion) # 4. Generate normal map.
def show(im): snowy.show(snowy.resize(im, height=100, filter=None))
def test_noise_smoothness(): noise = 0.5 + 0.5 * snowy.generate_noise(300, 150, 4, seed=42) grad = snowy.gradient(noise) grad = grad[0] + grad[1] grad = snowy.unitize(grad) snowy.show(grad)
def test_solid(): gray = np.ones([100, 100, 4]) / 2 snowy.show(gray)
def clumpy(cmd): print(f"clumpy {cmd}") result = system(f".release/clumpy {cmd}") if result: raise Exception("clumpy failed") friction = 0.9 spacing = 20 step_size = 2.5 kernel_size = 5 decay = 0.99 nframes = 400 res = 4000, 2000 scalex = 2 scaley = 5 dim = "x".join(map(str, res)) clumpy(f"pendulum_phase {dim} {friction} {scalex} {scaley} field.npy") clumpy(f"bridson_points {dim} {spacing} 0 pts.npy") clumpy( f"advect_points pts.npy field.npy {step_size} {kernel_size} {decay} {nframes} phase.npy" ) im = snowy.reshape(1.0 - np.load("000phase.npy") / 255.0) im = snowy.resize(im, 500, 250) snowy.export(im, "extras/example6.png") snowy.show(im) system("rm *.npy") print("Generated extras/example6.png")
import snowy source = snowy.open('poodle.png') source = snowy.resize(source, height=200) blurry = snowy.blur(source, radius=4.0) snowy.save(snowy.hstack([source, blurry]), 'diptych.png') # This snippet does a resize, then a blur, then horizontally concatenates the two images parrot = snowy.load('parrot.png') height, width = parrot.shape[:2] nearest = snowy.resize(parrot, width * 6, filter=snowy.NEAREST) mitchell = snowy.resize(parrot, width * 6) snowy.show(snowy.hstack([nearest, mitchell])) # This snippet first magnifies an image using a nearest-neighbor filter, then using the default Mitchell filter. parrot = snowy.load('parrot.png') height, width = parrot.shape[:2] nearest = snowy.resize(parrot, width * 6, filter=snowy.NEAREST) mitchell = snowy.resize(parrot, width * 6) snowy.show(snowy.hstack([nearest, mitchell]))