Find a thumbnail in a mosaic After the last Ludum Dare (LD) game programming contest a friend of mine made a nice mosaic of all the LD game thumbnails:



After searching for my own game I quickly gave up and decided to solve it like a real programmer... by writing code that finds my game thumbnail.

This is the thumbnail of my game:



More examples can be found by going to the Ludum Dare list of games.

So what is the challenge? Write a program that has the following input:

&lt;filename_mosaic&gt; &lt;amount_of_tiles_x&gt; &lt;amount_of_tiles_y&gt; &lt;filename_target&gt;


For example using the images above:

mosaic.jpg 59 43 target.png


The output should be the index of the target image. For the mosaic and screenshot above the correct index is:

48,18


The following (non-golfed) code provides a working example:

public class MosaicFinder {

    //Start with java MosaicFinder mosaic.jpg  59 43 target.png
    public static void main(String[] args)  throws Exception {
        String mosaicFilename = args[0]; 
        int tilesX = Integer.parseInt(args[1]);
        int tilesY = Integer.parseInt(args[2]);
        String targetFilename = args[3];

        BufferedImage mosaic = ImageIO.read(new File(mosaicFilename));
        int tileHeight = mosaic.getHeight()/tilesY;
        int tileWidth = mosaic.getWidth()/tilesX;

        BufferedImage tofind = ImageIO.read(new File(targetFilename));

        //Translate target.png to correct size:
        BufferedImage matchCanvas = new BufferedImage(tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB);
        AffineTransform at = AffineTransform.getScaleInstance((tileWidth*1.0)/tofind.getWidth(), (tileHeight*1.0)/tofind.getHeight());
        ((Graphics2D)matchCanvas.getGraphics()).drawRenderedImage(tofind, at);

        int bestIndexX = 0, bestIndexY = 0;
        BigInteger lowest = null;
        for(int x = 0; x&lt;tilesX;x++) {
            for(int y = 0; y&lt;tilesY;y++) {
                //For all tiles:
                BigInteger error = BigInteger.ZERO;
                for(int x1 = 0; x1&lt;tileWidth;x1++) {
                    for(int y1 = 0; y1&lt;tileHeight;y1++) {
                        int rgb1 = matchCanvas.getRGB(x1, y1);
                        int rgb2 = mosaic.getRGB((x*tileWidth)+x1, (y*tileHeight)+y1);
                        int r1 = (rgb1 &gt;&gt; 16) &amp; 0xFF;
                        int r2 = (rgb2 &gt;&gt; 16) &amp; 0xFF;
                        error = error.add(BigInteger.valueOf(Math.abs(r1-r2)));

                        int g1 = (rgb1) &amp; 0xFF;
                        int g2 = (rgb2) &amp; 0xFF;
                        error = error.add(BigInteger.valueOf(Math.abs(g1-g2)));

                        int b1 = rgb1 &amp; 0xFF;
                        int b2 = rgb2 &amp; 0xFF;
                        error = error.add(BigInteger.valueOf(Math.abs(b1-b2)));
                    }
                }
                if(lowest == null || lowest.compareTo(error) &gt; 0) {
                    lowest = error;
                    bestIndexX = (x+1);
                    bestIndexY = (y+1);
                }
            }
        }
        System.out.println(bestIndexX+","+bestIndexY);
    }
}


This is a visual example of the code running:


This contest is a code-golf contest, the shortest code wins the challenge.

Update: It seems stackexchange messes up the images a bit, on my blog you can find the source images for the examples in correct resolution.
Also: I've fixed the amount of images from 42 to 43

Current best: David Carraher, Mathematica (280)
Mathematica - 280 247
No need to scale the target to the tile size.  The key is to match the average color for the target and for each tile.  Closest match wins.
In principle, it would be possible for the routine to choose the wrong match, but the test case suggests that this approach is surprisingly robust. The mean colors of target and selected tile were almost a perfect match: a distance of 0.00296966 away from the target mean color in RGB colorspace &quot;cube&quot; with edges of length 1.
Ungolfed 364 chars
f[{m_, tilesx_, tilesy_, targ_}] :=
 Module[{mosaic = Import[m],target = Import[targ], mDim = ImageDimensions[mosaic],
 
 (* find the average RGB colors for the target *)
 meanTargetPixelColor = Mean[Flatten[ImageData[target], 1]], m, t},
 m = ImagePartition[mosaic, {mDim[[1]]/tilesx, mDim[[2]]/tilesy}];
 
 (*Find the color distances between target mean rob and each mosaic tile 
 Select the tile that best matches the average pixel color.*)
 t = SortBy[{#, EuclideanDistance[Mean[Flatten[ImageData[#], 1]], 
 meanTargetPixelColor]} &amp; /@ Flatten[m], Last][[1, 1]];
 Reverse[Position[m, t][[1]]]]

Example
Assuming that mosaic and targethold the respective filenames.
f[{mosaic, 59, 43, target}]


{48,18}


Golfed 247
f@{p_,x_,y_,s_}:=Module[{k=Flatten,i=Import,z=i@p,w,m,t,r},r=ImageDimensions@z;
w=Mean[k[ImageData[i@s],1]];m=ImagePartition[z,{r[[1]]/x,r[[2]]/y}];
Reverse[Position[m,SortBy[{#,EuclideanDistance[Mean[k[ImageData@#,1]],w]}&amp;/@k@m,Last][[1,1]]][[1]]]]