Friday, July 30, 2010

xrite Color Challenge Solver

Alright, here's my newest addition to the big list of projects I've created.

First, you have to go here : http://www.xrite.com/custom_page.aspx?PageID=77 and try the challenge!

My score was 6. Good? Bad? I don't know, but it was not the perfect score. However, when I saw this web page, one thing came to my mind right away, "I have to code a solver for this!".

Since this is a fairly easy project, I started right away. Well, it was my birthday, and I have to admit I was taking it a bit relaxed that day :)

So I started Visual Studio, new C# form project, a button with "Do-It", and started coding.

The first thing to do was take a screenshot so that I can then get the color of every pixel (http://support.microsoft.com/kb/892462). Done.

Then, I had to write code to find the squares on the screen. The algorithm looks like this:
  • For each pixel, check if the next pixels (horizontal and vertical) are of the same color.
  • Also make sure that lines surrounding the imaginary square are not of the same color.
  • While doing this, also calculate the width and height.
  • If we manage to "grow" a perfect square with a unique color, surrounded by a different color, good!
  • Then, to prevent false positives, I also check that the size is within 30 to 50 pixels.
OK, that IS the only option in the application and I could have simply hard-coded 40, but hey, options are nice, aren't they?

Anyway, the result of this operation was an ordered list of rectangles (x, y, width, height) with a color. It was now time to solve the problem!

First, I build a list of all the rectangles with the same y-coordinate and solve this subset. Once solved, I find the next list of rectangles and solve it, etc.

For each "problem", the solution implemented is quite simple. Start with the left-most movable square, find which square has the smallest hue difference with the left fixed square, and drag it to the first position (remove it from the list, and insert it back to its final position). Of course, finding the Hue value of a color is probably the most difficult thing to do in this project. You need to do a lot of research to know how to convert an RGB value to a unique Hue float value, don't you? Nah, just joking. The Color class has a neat function Color.GetHue(). How simple!

Really, the biggest challenge probably was to programmatically generate a mouse drag, the kind of stuff you try and it just doesn't work. Anyway, I ended up using the C# "Cursor.Position" to change the mouse position, and Win32 "mouse_event" to send LEFTDOWN and LEFTUP events. However, it would not work, I don't know why, but doing Down-Up-Down before dragging fixed it. If you know why that is, let me know!

In the end, I do something like:

Cursor.Position = new Point(x, y);
mouse_event(LEFTDOWN, 0, 0, 0);
mouse_event(LEFTUP, 0, 0, 0);
mouse_event(LEFTDOWN, 0, 0, 0);
Cursor.Position = new Point(x2, y2);
mouse_event(LEFTUP, 0, 0, 0);

And there you go, we have a C# application that can solve the Online Color Challenge in... (Oh, wait, I should really add a timer to the application... Doing so right now...) 8 seconds! (Most of the time taken by analyzing the screen, and this could easily be improved.)

I can now say that I have "perfect color vision"!

Here's a link to the source code AND the compiled application if you want to try it!


3 comments:

  1. Got a 13, but my eyes are bleeding from how tired I am! That, and I suck at colors :)

    Very cool project, JF!

    ReplyDelete
  2. Cool project !
    I got a 0 somehow.
    I was sure I had a few errors but apparently it was all good.

    ReplyDelete