Tags

, , , , , , , , , , , , ,

Arkwood struck a piece of flint. Spark! Slouching back on the flowery sofa, drawing satisfactory puffs from an antique carved pipe, he said, ‘How goes that miner? Willy is his name, yes?’

‘Yes, yes. Miner Willy,’ I replied curtly.

Manic Miner is a classic computer game. I used AForge.NET, an open source C# framework for computer vision and artificial intelligence, to find out How manic is Manic Miner? More precisely, I used its motion detection and processing algorithms to understand which levels of the game had the most stuff moving about on the screen. Turns out that the fifth level, “Eugene’s Lair”, was the most manic. But then I died.

‘So, what next?’ Arkwood enquired, his eyes dilating.

Next, I want to take a closer look at those objects moving about during a game of Manic Miner. I want to understand where they are on the screen. And what they are. Let’s look at the code:

namespace Motion
{
    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;
    using AForge.Vision.Motion;
    using AForge.Imaging;
    using AForge.Imaging.Filters;

    class Program
    {
        static void Main(string[] args)
        {
            // initialise screen
            var screen = new ScreenEasy(new Point(150, 100), new Size(1400, 570));

            // initialise motion detector
            var motionProcessing = new BlobCountingObjectsProcessing { MinObjectsWidth = 50, MinObjectsHeight = 50 };
            var detector = new MotionDetector(new TwoFramesDifferenceDetector(), motionProcessing);

            while (true)
            {
                try
                {
                    // get screenshot
                    var screenshot = screen.Capture();

                    // do motion detection
                    detector.ProcessFrame(screenshot);

                    // save screenshot
                    var filename = String.Format("img/{0}.jpg", DateTime.Now.ToString("HHmmssfff"));
                    screenshot.Save(filename, ImageFormat.Jpeg);

                    // loop each detected object
                    foreach (var rect in motionProcessing.ObjectRectangles)
                    {
                        // get stats of object
                        Crop filter = new Crop(rect);
                        Bitmap rectImage = filter.Apply(screenshot);
                        ImageStatistics stat = new ImageStatistics(rectImage);

                        // write stats to log
                        using (StreamWriter log = new StreamWriter("img/log.txt", true))
                        {
                            log.WriteLine(String.Format("Filename [{0}], Object [TopLeft={1}:{2} HeightWidth={3}:{4} RedGreenBlue={5}:{6}:{7}]",
                                filename, rect.Location.Y, rect.Location.X, rect.Height, rect.Width, stat.Red.Mean, stat.Green.Mean, stat.Blue.Mean));
                        }
                    }
                }
                catch(Exception ex)
                {
                    // likely got too Manic!
                    Console.WriteLine(ex);
                }
            }
        }
    }
}

I have created a C# Console application and added references to AForge.NET ‘Imaging’, ‘Math’ and ‘Vision’ dlls (check out my post on how to get started using AForge.NET).

First up, I create an instance of my ScreenEasy class, which will take screenshots of me playing Manic Miner.

Next, I set up the motion detector. I will make use of the BlobCountingObjectsProcessing class, which will provide information on all objects moving about on screen (note how I set its minimum width and height properties so that I am only detecting objects of a reasonable size).

Then we drop into a while loop, which will run continuously in the background whilst I play Manic Miner, taking around ten screenshots a second.

For each screenshot, we detect motion. We save the screenshot to disk, with red rectangles drawn around the moving objects:

ManicMiner_MarkII_Level1_124430941

The code then obtains an image for each detected object, using the AForge.NET Crop class e.g.

ManicMiner_MarkII_Level1_Object1_124430954

ManicMiner_MarkII_Level1_Object2_124430955

The AForge.NET ImageStatistics class is applied to each object image, providing information such as the mean values of its red, green and blue channels.

Great! All that’s left to do is save the object’s stats to a log file, along its position on the screen:

Filename [img/124430941.jpg], Object [TopLeft=253:652 HeightWidth=66:63 RedGreenBlue=95.504329004329:88.1161616161616:47.1948051948052]
Filename [img/124430941.jpg], Object [TopLeft=348:424 HeightWidth=56:51 RedGreenBlue=92.0798319327731:73.3298319327731:73.3298319327731]

Take a look at the screenshot again, and the red rectangles drawn on it (you may need to click on the screenshot to see the rectangles). Then match each rectangle to a log file entry, which has the position and mean colour of a moving object.

For example, we can see that the first log entry has top-left coordinates of 253:652, which is the yellow trumpet-faced dude. The second log entry has top-left coordinates of 348:424, which is our Miner Willy (he’s further down the screen but not as far left).

‘So, what’s the point in all that, maaaaannnn?‘ Arkwood drooled, the left side of his mouth slack.

‘I’ll tell you what the point is! I now know the location of each moving object in Manic Miner, and I know its color. Soon I will determine which character is which, and provide some artificial intelligence to help me complete the game. I will no longer die!’

‘Big talk,’ he simply stated, taking another puff of his pipe.

I wanted to punch him. I felt deflated. I packed way my C# code and shut down the Windows 7 computer that I had been using to play Manic Miner.

‘What the hell is in that pipe, anyhow?’ I asked him.

‘Herb maaaaannnn. You know, tea, dope, hashish, The Ganja.’

I rolled my eyes and turned another page of The Inscrutable Diaries Of Rodger Saltwash.

Advertisements