An iterative algorithm to generate high quality triangulated images.
Triangula uses a modified genetic algorithm to triangulate images. It works best with images smaller than 2000px and with less than 3000 points, typically producing an optimal result within a couple of minutes. To better understand the algorithm, considering reading this page on the wiki.
Install the GUI from the releases page.
Install the CLI using:
go get github.com/RH12503/Triangula-CLI/triangula
For almost all cases, only changing the number of points and leaving all other options with their default values will generate an optimal result.
Name | Flag | Default | Usage |
---|---|---|---|
Points | --points, -p |
300 | The number of points to use in the triangulation |
Mutations | --mutations, --mut, -m |
2 | The number of mutations to make |
Variation | --variation, -v |
0.3 | The variation each mutation causes |
Population | --population, --pop, --size |
400 | The population size in the algorithm |
Cutoff | --cutoff, --cut |
5 | The cutoff value of the algorithm |
Cache | --cache, -c |
22 | The cache size as a power of 2 |
Block | --block, -b |
5 | The size of the blocks used when rendering |
Threads | --threads, -t |
0 | The number of threads to use or 0 to use all cores |
Repetitions | --reps, -r |
500 | The number of generations before saving to the output file (CLI only) |
Comparison to esimov/triangle
esimov/triangle seems to be a similar project to Triangula that is also written in Go. However, the two appear to generate very different styles. One big advantage of triangle is that it generates an image almost instantaneously, while Triangula needs to run many iterations.
esimov/triangle | Triangula |
---|---|
A simple example to use the API would be:
func main() {
// Open and decode a PNG/JPEG
file, err := os.Open("image.png")
if err != nil {
log.Fatal(err)
}
image, _, err := image.Decode(file)
file.Close()
if err != nil {
log.Fatal(err)
}
img := imageData.ToData(image)
pointFactory := func() normgeom.NormPointGroup {
return (generator.RandomGenerator{}).Generate(200) // 200 points
}
evaluatorFactory := func(n int) evaluator.Evaluator {
// 22 for the cache size and 5 for the block size
return evaluator.NewParallel(img, 22, 5, n)
}
var mutator mutation.Method
// 1% mutation rate and 30% variation
mutator = mutation.NewGaussianMethod(0.01, 0.3)
// 400 population size and 5 cutoff
algo := algorithm.NewSimple(pointFactory, 400, 5, evaluatorFactory, mutator)
// Run the algorithm
for {
algo.Step()
fmt.Println(algo.Stats().BestFitness)
}
}