Skip to content

Generate high-quality triangulated and polygonal art from images.

License

Notifications You must be signed in to change notification settings

rh12503/triangula

Repository files navigation

An iterative algorithm to generate high quality triangulated images.

Test status Go Reference Go Report Card License: MIT

Introduction

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

GUI

Install the GUI from the releases page.

CLI

Install the CLI using:

go get github.com/RH12503/Triangula-CLI/triangula

Options

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)

Example output

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

API

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)
      }
}