Search code examples
imagebitmapscreenscreenshot

Check if exact image in exact location is on screen


I am looking to create a program in Visual Studio (C#) which scans the screen for an exact image in an exact location of the screen. I have seen many discussions which involve algorithms to find a "close" image, but mine will be 100% exact; location, size and all.

I have obtained a png from a section of my screen [Image 1] using this code:

private void button1_Click(object sender, EventArgs e)
    {
        //Create a new bitmap.
        var bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
                                       Screen.PrimaryScreen.Bounds.Height);

        // Create a graphics object from the bitmap.
        var gfxScreenshot = Graphics.FromImage(bmpScreenshot);

        // Take the screenshot from the upper left corner to the right bottom corner.
        gfxScreenshot.CopyFromScreen(1555, 950, 
                                    1700, 1010,
                                    Screen.PrimaryScreen.Bounds.Size,
                                    CopyPixelOperation.SourceCopy);

        // Save the screenshot to the specified path that the user has chosen.
        bmpScreenshot.Save("Screenshot.png");
    }

So, basically here is the flowchart of my program on how I want to move forward: 1) create the master png using the above code 2) run loop: create same screenshot using the same procedure as the master png compare master png to new screenshot png and if:match then move on otherwise reiterate loop.

I am very new to programming, but I don't believe this is beyond me, given a little guidance. I have written fairly complicated (in my opinion) VBA and Matlab programs. Any help is greatly appreciated.

Thank You, Sloan


Solution

  • Digging around a bit through Microsoft's documentation, I came up with a rough function that would do something similar to what you want. https://msdn.microsoft.com/en-us/library/hh191601.aspx

    This function offers the chance of getting stuck in an endless loop, so you might consider calling it with a timeout from your main. See here for info on synchronous methods with timeouts: Monitoring a synchronous method for timeout

    From your main, all you'd have to do is see if it returns true.

    static int Main(string[] args)
    {
       if (ImageInLocation(left, right, top, bottom)) {
          // do other things
       }
    
       return 0;
    }
    

    The only thing I'm not entirely sure on is how strict you can be with the ColorDifference. Even if the images are identical, any pixel difference with an entirely non-tolerant ColorDifference will come up false. If you know it should work and it's not, perhaps consider increasing the tolerance. Here's some more info on that: https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.uitesting.colordifference.aspx

    public bool ImageInLocation(int left, int right, int top, int bottom) {
       bool image_found = false;
       var masterImage = Image.FromFile("path_to_master");
    
       while (!image_found) {
          // screenshot code above, output to "path_to/Screenshot.jpg"
          var compImage = Image.FromFile("path_to/Screenshot.jpg");
    
          // note, all zeroes may not be tolerant enough
          var color_diff = new ColorDifference(0, 0, 0, 0); 
          Image diffImage;
    
          image_found = ImageComparer.Compare(masterImage, compImage, color_diff, out diffImage);
       }
    
       return true;
    }
    

    Good luck! Welcome to the programming community.

    Also, if anyone has any suggestions/changes, feel free to edit this. Happy imaging, friends!