Strategize All The Things

Some time ago, I wrote a program to generate image mosaics from Magic: The Gathering cards. I eventually got it to a point where I could generate reasonably nice mosaics, but there were a number of places in the code where it became impossible for me to do more interesting things with my solvers. So I recently set out to do a complete code cleanup, to make it easier to do some of those things.

One of the main things that I have been doing with my code cleanup is replacing many of the static functions with the strategy pattern. The main idea behind the strategy pattern is to abstract away the implementation of a family of algorithms so that it’s easy to vary the algorithm, without having to rewrite a lot of code. I’ve already done this with the actual solver algorithms (i.e. I wrote a bunch of different ways to “solve” the mosaic), but I found that I was actually very limited in the ways that I could vary anything else.

My goal is to allow a number of other things to vary, besides simply the solver code. Specifically, the current things I want the ability to vary are (blue items were the options in my old code):

Mosaic Solver:

  • Random Solver
  • Greedy Solver
  • Hungarian Solver
  • Binning Solver
  • Clustering Solver
  • Dynamic Binning Solver

The interesting thing about these algorithms is that the first three algorithms are the only ones that directly solve the mosaic problem, while the others are more like preconditioners that break the problem down into smaller problems. Since they all present the same interface, they are easily stackable and interchangeable.

Pixel Difference Computation

  • RGB
  • CIE-L*ab

These algorithms will allow me to change how the other algorithms choose which image is a “best” match for a segment of the goal image. RGB is just standard distance on the RGB vector space (the only option in my original code), however, CIE-L*ab was designed with the human eye in mind, and I am hoping that I can use it to create better mosaics.

Low-fidelity image approximation

  • Average color
  • Lightness
  • Color configuration

Most of my preconditioners use a low-fidelity approximation of the images and goal segments, so being able to vary this allows me to vary how the algorithm works without changing the algorithm code.