Pokemon Fusion: Behind the Scenes
I’ve been getting a few questions about the script used to generate the Pokemon Fusion sprites, so I thought I would write a quick blog post to describe the process.
The inspiration of the website was the idea that it should be possible to automate the process of combining pokemon sprites, and each image is automatically generated by a computer script. Some of the results are less impressive than others, but I think that it adds to the fun and makes it that much more satisfying when you come across ones that work really well.
Preparation
There is a small amount of manual work that goes into adding a new pokemon to the website. It comes down to collecting some basic information about the head’s size and position, as well as the colors that are used.
First, I download the new pokemon’s sprite from Bulbapedia, and manually cut out the head and save it as a new image. The body is also saved separately, and these become the basic parts that are combined with those from other pokemon to create the fusions.
To collect and save each pokemon’s data, I made a simple admin page.
- Inputting the name as a prefix + suffix allows me to combine them to name the results.
Face size
is taken automatically from the size of the image, andHead size
is used to adjust for unusually-shaped faces. In this example, I wanted the lower jaw and whiskers to hang below the main head location so I set the head size to be smaller, matching the colored-out area of the body.- To make setting the face’s size and position easier, there’s a little javascript that lets me click on a point on the image to output the coordinates automatically.
- The basic idea behind the colors is that each sprite will have at most 3 different colors, with at most 5 shades of each color. The 3rd shade of each color is set to be the primary color, with the 2 shades on either side defining highlights and shadows.
- I made a little script here too, that lets me click on a point in the image to automatically output the hex value of that pixel.
After all of the data is saved, I run my fusion script to combine the new pokemon with all of the existing pokemon. At this point, by just adding a few data points for a new pokemon I can generate over 100 new fusions nearly instantly.
The script
The image processing is done with ImageMagick, and I use the RMagick gem to work with it in Ruby. I plan to open source the code after I clean things up more, but here are the most important parts:
Swap the colors to match the new face
body1 = body1.opaque_channel("##{pk1['primary'][i]}","##{pk2['primary'][i]}")
This code looks at the image body1
for every pixel of the given color pk1['primary'][i]
and changes it to the second given color pk2['primary'][i]
. We will then loop for each of the 5 shades of each of the 3 colors.
Resize the face to match its new body
headratiox1 = 1.0 * pk2['headsize'][0] / pk1['headsize'][0]
headratioy1 = 1.0 * pk2['headsize'][1] / pk1['headsize'][1]
newx = pk1['facesize'][0] * headratiox1
newy = pk1['facesize'][1] * headratioy1
face1 = face1.resize(newx, newy)
First, we compare the heads of the two pokemon and see much bigger/smaller the head we’re working with is. Once we have this ratio, we resize the face image by this ratio.
Since we made defined the head to be smaller than the face (to support irregular faces with beaks, tongues, or whiskers that spill over the head area), this makes sure that the face image isn’t shrunken down too much.
Put the head in the right place
body1 = body1.composite(face2, face2x, face2y, Magick::OverCompositeOp)
composite
is the function that overlays an image over another image, and here we are placing the image face2
on top of the image body1
at the coordinates (face2x, face2y)
.
That’s it!
After looping over each existing pokemon the script generates all new combinations using the new pokemon, and I just upload the new images and update the site to show the new combinations.
If you have any other questions, feel free to reach out over email or twitter.
Edit: Because I’ve been getting a lot of questions about it, I’ll mention here that I only plan to support the first 151 pokemon for the site. Thanks for your understanding.