Last active
May 29, 2021 16:33
-
-
Save RemyPorter/b6021b690d9c5af7648ef9d9e5ce92c1 to your computer and use it in GitHub Desktop.
A Markov Chain-based glyph generator
This file contains 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
/** | |
A markov-chain based glyph generator. Given sequences of points as a corpus, this will create a markov chain based on those points. | |
Then, by sampling the chain, we can generate entirely new glyphs that weren't in our original dataset. | |
Press "r" to generate a new frame. Press "s" to save the frame to a file (with a random UUID as its name). | |
Requires the PostFx library: https://github.com/cansik/processing-postfx/ | |
*/ | |
import java.util.*; | |
import static java.util.UUID.randomUUID; | |
import ch.bildspur.postfx.builder.*; | |
import ch.bildspur.postfx.pass.*; | |
import ch.bildspur.postfx.*; | |
/** | |
Generic MarkovChain class. This is a very lazy implementation. | |
There is a key for each unique item. Each key has an arraylist of items | |
which were seen to follow it. | |
*/ | |
class MarkovChain<T> extends HashMap<T, ArrayList<T>> { | |
//safety wrapper to ensure we always have data for every key | |
ArrayList<T> get(Object key) { | |
if (!this.containsKey(key)) { | |
this.put((T)key, new ArrayList<T>()); | |
} | |
return super.get(key); | |
} | |
//populate the chain with a corpus | |
void analyze(List<T> sequence) { | |
for (int i = 1; i < sequence.size(); i++) { | |
T item = sequence.get(i-1); | |
this.get(item).add(sequence.get(i)); | |
} | |
} | |
T getRandomKey() { | |
T[] keys = (T[])this.keySet().toArray(); | |
int r = (int)random(keys.length); | |
return keys[r]; | |
} | |
T getRandomFollower(T key) { | |
ArrayList<T> entry = get(key); | |
return entry.get((int)random(entry.size())); | |
} | |
//Generate a new sequence of len items | |
ArrayList<T> generate(int len) { | |
ArrayList<T> res = new ArrayList<T>(); | |
T start = this.getRandomKey(); | |
res.add(start); | |
for (int i = 1; i < len; i++) { | |
try { | |
start = getRandomFollower(start); | |
res.add(start); | |
} catch (IndexOutOfBoundsException ex) { | |
start = this.getRandomKey(); | |
res.add(start); | |
} | |
} | |
return res; | |
} | |
} | |
/** POINT LISTS - my input dataset **/ | |
PVector[] square = { | |
new PVector(0,0), | |
new PVector(1,0), | |
new PVector(1,1), | |
new PVector(0,1), | |
new PVector(0,0) | |
}; | |
PVector[] buildSinus(int n) { | |
PVector[] res = new PVector[n]; | |
for (int i = 0; i < n; i++) { | |
float x = i / n; | |
PVector p = new PVector(x, sin(x*2*PI)); | |
res[i] = p; | |
} | |
return res; | |
} | |
PVector[] triangle = { | |
new PVector(0,0), | |
new PVector(0,1), | |
new PVector(1,0), | |
new PVector(0,0) | |
}; | |
PVector[] sinusPath = buildSinus(10); | |
PVector[] snowflake = { | |
new PVector(0, 0.25), | |
new PVector(0.25, 0.5), | |
new PVector(0, 0.75), | |
new PVector(0.25, 0.75), | |
new PVector(0.5, 1), | |
new PVector(0.75, 0.75), | |
new PVector(1,0.75), | |
new PVector(0.75,0.5), | |
new PVector(1., 0.25), | |
new PVector(0.75, 0.25), | |
new PVector(0.5, 0), | |
new PVector(0.25, 0.25), | |
new PVector(0, 0.25) | |
}; | |
PVector[] c = { | |
new PVector(0,0), | |
new PVector(0,1), | |
new PVector(1,1), | |
new PVector(1,0.75), | |
new PVector(0.25,0.75), | |
new PVector(0.25, 0.25), | |
new PVector(1., 0.25), | |
new PVector(1, 0), | |
new PVector(0, 0) | |
}; | |
PVector[] a = { | |
new PVector(0, 1), | |
new PVector(0.25, 0.5), | |
new PVector(0.75, 0.5), | |
new PVector(1, 1), | |
new PVector(0.5, 0), | |
new PVector(0, 1) | |
}; | |
PVector[] l = { | |
new PVector(0, 0), | |
new PVector(0, 1), | |
new PVector(1, 1), | |
new PVector(1, 0.75), | |
new PVector(0.25, 0.75), | |
new PVector(0.25, 0), | |
new PVector(0, 0) | |
}; | |
PVector[] t = { | |
new PVector(0, 0), | |
new PVector(1, 0), | |
new PVector(1, 0.25), | |
new PVector(0.75, 0.25), | |
new PVector(0.75, 1), | |
new PVector(0.25, 1), | |
new PVector(0.25, 0.25), | |
new PVector(0, 0.25), | |
new PVector(0, 0) | |
}; | |
PVector[] o = { | |
new PVector(0, 0), | |
new PVector(0, 1), | |
new PVector(0.75, 1), | |
new PVector(0.75, 0), | |
new PVector(0, 0) | |
}; | |
PVector[] sev = { | |
new PVector(0,0), | |
new PVector(0, 0.25), | |
new PVector(0.75, 0.25), | |
new PVector(0, 0.75), | |
new PVector(0, 1), | |
new PVector(1, 0), | |
new PVector(0, 0) | |
}; | |
PVector[] bx = { | |
new PVector(0, 0), | |
new PVector(0, 0.5), | |
new PVector(0.75, 0.5), | |
new PVector(0.75, 0.75), | |
new PVector(1, 0.75), | |
new PVector(1, 0), | |
new PVector(0, 0) | |
}; | |
PVector[] tup = { | |
new PVector(0, 1), | |
new PVector(1, 1), | |
new PVector(1, 0.5), | |
new PVector(0, 1) | |
}; | |
/** END POINT LISTS **/ | |
PVector[][] chains = { | |
bx, sev, t, l, a, c, square, o, triangle, sinusPath, snowflake, tup | |
}; | |
MarkovChain<PVector> s = new MarkovChain<PVector>(); | |
PostFX fx; | |
void setup() { | |
fullScreen(P3D); | |
//populate the markov chain out of our input dataset | |
for (int i = 0; i < chains.length; i++) { | |
s.analyze(Arrays.asList(chains[i])); | |
} | |
background(0); | |
frameRate(10); | |
fill(#00FF00); | |
noStroke(); | |
fx = new PostFX(this); | |
} | |
boolean redraw = true; | |
void draw() { | |
if (!redraw) return; | |
clear(); | |
for (int x = 0; x < width + 20; x += 20) { | |
for (int y = 0; y < height + 20; y += 20) { | |
ArrayList<PVector> gen = s.generate(10); | |
pushMatrix(); | |
translate(x, y); | |
scale(15); | |
beginShape(); | |
for (PVector p : gen) { | |
vertex(p.x, p.y); | |
} | |
endShape(CLOSE); | |
popMatrix(); | |
} | |
} | |
fx.render() | |
.sobel() | |
.brightPass(0.25) | |
.pixelate(width/2.75) | |
.bloom(0.5, 20, 40) | |
.vignette(0.75, 0.25) | |
.noise(0.25, 0.25) | |
.compose(); | |
redraw = false; | |
//save("sample.png"); | |
} | |
void keyPressed() { | |
if (key == 'r') { | |
redraw = true; | |
} | |
else if (key == 's') { | |
save(randomUUID().toString() + ".png"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment