Feature Friday: Map Grid Detection
I love a great map for tabletop gaming. When playing in person, I often print out maps in color on standard printer paper and tape the sheets together to form sprawling maps that cover the dining room table. For online play, I’ve amassed a large library of detailed images from a variety of sources, predominantly Patreon as of late. One of my frustrations however has been setting up a map in the VTT for gameplay. Seems that getting the image and grid aligned and sized correctly is always more trouble than it should be. How can it be that I sometimes have to manually count grid squares to get it right? For Tabyltop, I was convinced we could do better.
The obvious solution in this era of Artificial Intelligence was to create an algorithm that could look at a map and automatically figure out the grid spacing and dimensions. How hard could that be?
First, to understand the problem, I looked through the library of maps I’ve used for playing online in the last few years. I’ve used maps from a variety of sources: some intended for VTT use, but many of them not. The quality, detail, style, and resolution was all over the map (See what I did there?). I grabbed a sample that included both recent VTT maps from some of my favorite creators as well as maps I created myself or converted from published books by downloading the image from DDB official content or screenshotting a PDF. Time to write some code.
I slapped together some Python code to try to identify the repetitive features of the gridlines in the image. By averaging all the pixels of the image horizontally and then vertically, and then summing pixel values at a various intervals, I could pick out the grid spacing for many maps:
< figcaption>The grid size stands out on the intensity chart, with a smaller peak at the half-grid value.Unfortunately, this approach had two major drawbacks. First, it really only handles integer grid sizes well. If the gridlines are not pixel-aligned, it struggles, often picking up some multiple of the grid size instead. But the biggest problem is it is absolutely no help if the map doesn’t have gridlines embedded in it. As I went back through my map collection, I was surprised to find a majority had one or both of these characteristics and would therefore fail.
The solution came last week during a review with Ben and Jonathan. We decided to make the simplifying assumption that an imported map will always be completely covered by a whole number of grid squares, aligned to the edges of the image. Reviewing my library, I found that this is almost always the case, even when the size of an individual square is something wacky (as often happens when the original image is resized) and whether or not the grid is actually embedded in the image. I actually made one other minor assumption, which is that an individual grid tile would be between 32 and 256 pixels square. This reduces the computation required and eliminates some absurd solutions, like your 3200×3200 map being a 2×2 grid.
So with this in in mind, time for some new code. The new solution looks for grids that completely cover the image with square tiles. The aspect ratio error is saved for ranking solutions. In addition, integer tile sizes are preferred if they exist. Once the list of tile sizes is found, each is checked using a method similar to that described above looking for repeating patterns in pixel intensity. The results are fast and accurate:
The Tabyltop screenshot above shows a map being loaded and set up. On the client, within seconds of selecting the map, it correctly suggested an 18×22 grid. This map has a clearly defined grid and was created with VTT in mind, so it is the easiest test case. (City Sewers map from Moonlight Maps, check them out on Patreon.)
Here’s another test on an absolutely massive map from Spellarena Map Atlas:
For the gridless versions of these maps, Tabyltop guesses the grid size at 2x actual, but provides the correct dimensions in a short list of options. The preview shows the grid as you cycle through options. Two clicks and your grid is set up the the way you want.
Here’s a map from DM Tom at Frontier Maps with no grid and a fractional pixel tile size. Once more, correct layout in 2 clicks!:
OK, but how does it do with a real challenge? Here’s a couple of maps from the Dragon of Icespire Peak which were probably never intended to be used in a VTT:
The Dragon Barrow map has an inconsistent grid, is slightly misaligned, fractional grid size, and aspect ratio is a little off. Nonetheless the algorithm guesses 2x the grid size with the correct grid size as the second option. The Axeholm map below gets similar performance, despite the fact that it is actually two maps with one offset by a couple pixels. If you look closely the grid is offset horizontally in the right side of the image, but it’s still definitely close enough to play on, and was identified automatically.
Overall, I’m thrilled by the performance of this new algorithm. We have lots of plans for the future, including additional map types (hex and isometric for example) but we’re staying hyper-focused on core 5e mechanics for the initial release.
In the future, I think this could be improved for maps with no gridlines by using some machine learning on the outputs of the algorithm. I suspect it’ll be possible to determine the desired grid size automatically in the vast majority of cases.
Got an idea for map handling you’d like to see as part of Tabyltop? Find us over on Twitter and drop us a note. See you at the Tabyl!