SyfSchydea / New-Horizons-Pattern-Generator

Takes an image and outputs a New Horizons pattern
3 stars 0 forks source link
animal-crossing cli image-processing k-means-clustering new-horizons opencv

New Horizons Pattern Generator

This script converts images into patterns for Animal Crossing: New Horizons.

This is written in Python 3 and requires NumPy and OpenCV.

Basic Usage:

Call the script using:

./convert-pattern.py path/to/your/image.png

Your image should be a 32×32 pixel image. It may be in any file-type which OpenCV is able to open, which includes most common image formats such as .jpg and .png.

This will generate a preview image at nh-pattern.png, and a text file containing instructions of how to produce the pattern at nh-pattern-instructions.txt. The output location of the preview image may be overridden with the -o/--out option, and the location of the instructions file may be overridden with the -i/--instructions-out option. eg.:

./convert-pattern.py input.png --out preview-output.png --instructions-out instructions-output.txt

Instructions Files:

This file will show you how to draw the generated pattern.

Colour palette:

eg.:

Colour palette:
        Hue:  6   8   4  11   3   7   4  11   3   4   7  11   4   2  15
  Vividness:  5   7   6   9   6   9   7  11   7   6   6  12   5  12  10
 Brightness: 11  10  13   6  14  12  14   9  14  14   8   7  13   8   5

This section shows the colour palette to use to create this pattern. Each column of numbers represents one colour in the palette. Each row represents one channel in the colour space used by New Horizons. The numbers represent how far along each slider to go, with 0 being the furthest left value on each slider. For hue, the furthest right value is 29, while for vividness and brightness, the furthest right value is 14.

Pixel Maps:

eg.:

Colour 3 [11  9  6]:
  c c · · · · · · · c · c · c · ·  · · · · c c c · · · · · · · · c
  · · · · · · · · · · · · · · · ·  a b a · · · · · c · c · · c · ·
  · · · · c · c c c c · c c a b ·  · # # a · · · · · · · c · · · ·
  · · · c c · c b · · · · · · · ·  · · · · · · · · · c · · · c · ·
  · · · · c · a · · · · · · · · ·  · · · · · · · · · · c c c · c ·
  · · · · · · b · · · · · · · · ·  # # # · · · · · · c c · c · · ·
  · · · c · · a · · # · · · # # ·  · · # · · · · · · · c · c · c ·
  c · c · · · · · · # · · · · · ·  · # # a · c c · · · · · · · c ·
  c · c · · · · a · · · · · · · #  # # # · c · c c c · · · · · · c
  · c · · · · · a · · · # # · # ·  · · · a c · · c · · · · · · · ·
  · · c · · · · a · · · · · · · #  · # · · c · c · c · · · · · · ·
  c · · · · · · c · · · · · · · ·  · · · · c · · c · · · · · · c ·
  · · · · · · · c · · · · · · · ·  · # · # · · · · · · · · · · · ·
  · · · · c c · a · · · · · · · ·  · · # # · c · · · · c · c · · ·
  · · · · c · · a · · · · · · · ·  · # · # · # · c c · c · c · · ·
  · · · · · c · · · · · · · · · b  · b b b b b # # a · · c · · · ·
[...]

The next section in the instructions file is a map of pixels for each colour in the palette. Pixels represented as a dot (·) have not yet been filled by any colour. Pixels represented by a hash (#) should be filled in with the current colour. Pixels represented by a lower-case letter should have already been filled by a previous colour. The first colour is represented by an a, the second colour is represented by a b, and so on.

Algorithm

To choose a palette, the script uses k-means clustering on all the colours present in the image. This chooses a good subset of colours to represent the full set of colours.

Before performing k-means, the colours are converted to the Lab colour space as this provides a better representation of perceptual differences between colours.

After a palette has been generated, it is rounded to get an approximation of the palette, which can be used in New Horizons. The palette is then used map each pixel in the image to a colour in the palette.

Dithering

Dithering may be used to simulate better colour variation, while creating a slightly more noisy look to the pattern, which may be desirable or undesirable depending on the image. The script can use Floyd-Steinberg dithering to achieve this effect in your patterns.

This option defaults to off, but may be toggled on using the -d/--dithering flag.

Duplicate colours

Sometimes, when a palette is generated, two or more of the colours may be close enough to each other that when converted to New Horizons' colour space, they are rounded to exactly the same value. This is obviously undesirable, as this means one colour is effectively going unused.

The current default policy to handle this situation is simply to output a warning and continue regardless. Alternatively, you can pass the -r/--retry-duplicate flag to automatically increment the RNG seed and retry palette generation until a palette with no duplicates is created.

Weight maps

A weight map may be used to give higher weights to some pixels when choosing palettes. A weight map may be passed using the -w/--weight-map, and should be a greyscale image with the same size as the main input image. Areas in the main image corresponding to brighter values in the weight map will receive greater consideration than darker areas when performing k-means to choose colours. This can be used to give more detail to an area if you think it needs it.

RNG Seed

The k-means algorithm does not generate the optimal set of clusters for its input data. Doing so would be an NP-hard problem. Rather, it is a heuristic which aims to find a "good" solution in a reasonable time. It also depends on a randomised starting state, and as such, may produce slightly different results each time it is run. This starting state is determined by the RNG seed. The script generates and prints a random seed before starting k-means. If you want to re-run the script exactly as you previously ran it, you can pass a seed using -s/--seed.

Logging

The script prints some information about what it is doing to stdout as it runs. If you want to see some more debug information, you can pass the -v/--verbose flag. If you want to see less information you can pass the -q/--quiet flag. This flag also stacks to hide even more output. Stacking the flag twice (-qq) hides info and warnings. Stacking the flag three times (-qqq) hides info, warnings, and errors.

TTY Colours

The instructions file may be written with TTY colour control codes. This defaults to on if the instructions file is being written directly to a console, but may also be forced on with -c/--tty-colours or forced off with --no-tty-colours.