1

I currently have a code that will search for a bitmap in a screenshot taken by this program, however, the bitmap exists three times in the screenshot and I want it to click the second time it finds it.

Is there any way to do this? A lot of thanks in advance...

Code:

private Bitmap Screenshot()
{
    Bitmap bmpScreenShot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
    Graphics g = Graphics.FromImage(bmpScreenShot);
    g.CopyFromScreen(0, 0, 0, 0, Screen.PrimaryScreen.Bounds.Size);
    return bmpScreenShot;
}

private bool FindBitmap(Bitmap BmpNeedle, Bitmap BmpHaystack, out Point location)
{
    for (int outerX = 0; outerX < BmpHaystack.Width - BmpNeedle.Width; outerX++)
    {
        for (int outerY = 0; outerY < BmpHaystack.Height - BmpNeedle.Height; outerY++)
        {
            for (int innerX = 0; innerX < BmpNeedle.Width; innerX++)
            {
                for (int innerY = 0; innerY < BmpNeedle.Height; innerY++)
                {
                    Color cNeedle = BmpNeedle.GetPixel(innerX, innerY);
                    Color cHaystack = BmpHaystack.GetPixel(innerX + outerX, innerY + outerY);
                    if (cNeedle.R != cHaystack.R || cNeedle.G != cHaystack.G || cNeedle.B != cHaystack.B)
                    {
                        continue;
                    }
                }
            }
            location = new Point(outerX, outerY);
            return true;
        }
    }
    location = Point.Empty;
    return false;
}

public void findImage()
{
    Bitmap bmpScreenshot = Screenshot();
    Point location;
    bool success = FindBitmap(Properties.Resources.xxx, bmpScreenshot, out location);
}

Don't know if that really helps, all I want it to do is click the second bitmap it finds.

A friend did suggest splitting my screenshot into grids and doing it that why, is doing grids the way to go or is it possible to find the second bitmap?

Update: Say I have 5 of the the exact same images on my screen. I want my program to click the third bitmap it finds.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Matt
  • 11
  • 2
  • Don't you want to return nullable Point `Point?`, not a boolean, and check the result against null: `Point? p = FindBimap(); if (p.HasValue) { }` – abatishchev Apr 03 '12 at 06:02
  • @abatishchev Not really what I'm after, was after clicking the second bitmap it finds... `if (success == true) { Cursor.Position = location; (Which clicks the second bitmap it finds the in screenshot) }` In all honesty, I'm happy with what I have at the moment. Trying to get it to click the bitmap the second time it finds it... – Matt Apr 03 '12 at 06:05
  • Hi Matt. I have problems by the description "Find Bitmap in a screenshot". Bitmap is a fileheader description and a screenshot is any image from phone as I see which already need any file image header. If you want to ask how to determine if user has clicked twice or detected second image that could be easy solved. Please explain. Here you can download an sample project with image detection: http://www.activevb.de/rubriken/kolumne/kol_30/wp7_einfuehrung.html – Nasenbaer Apr 03 '12 at 06:22
  • @Nasenbaer Don't know what you are talking about. My code searches for a bitmap image in a screenshot. O.O Completely lost me there... – Matt Apr 03 '12 at 06:31
  • @Matt: just search for `compare images`. I think that can help you to compare image regions by grid (like your friend said) http://www.codeproject.com/Articles/9299/Comparing-Images-using-GDI to improve speed for detection. – Nasenbaer Apr 03 '12 at 06:38
  • @Matt: Returning bool and out value that a C style, not C#. In case of nullable point you can still use your logic: `Point? p = FindBitmap(); if (p.HasValue) { Cursor.Position = p.Value }`. That's looks more correct for me. – abatishchev Apr 03 '12 at 08:21

1 Answers1

1

Easiest way to do would be to introduce a counter that shows how many times the picture was found. Somehow like this:

private bool FindBitmap(Bitmap BmpNeedle, Bitmap BmpHaystack, out Point location)
{
    int countTimesFound = 0;
    for (int outerX = 0; outerX < BmpHaystack.Width - BmpNeedle.Width; outerX++)
    {
        for (int outerY = 0; outerY < BmpHaystack.Height - BmpNeedle.Height; outerY++)
        {
            for (int innerX = 0; innerX < BmpNeedle.Width; innerX++)
            {
                for (int innerY = 0; innerY < BmpNeedle.Height; innerY++)
                {
                    Color cNeedle = BmpNeedle.GetPixel(innerX, innerY);
                    Color cHaystack = BmpHaystack.GetPixel(innerX + outerX, innerY + outerY);
                    if (cNeedle.R != cHaystack.R || cNeedle.G != cHaystack.G || cNeedle.B != cHaystack.B)
                    {
                        continue;
                    }
                }
            }
            countTimesFound++;
            if (countTimesFound == 2)
            {
                location = new Point(outerX, outerY);
                return true;
            }
        }
    }
    location = Point.Empty;
    return false;
}

Though you should really look into techniques for image detection. There are libraries that allow doing that easier.

Dmitry Reznik
  • 6,812
  • 2
  • 32
  • 27
  • Eugh, Sorry I probably should have mentioned... If it finds 3 bitmaps, I only want it to click the second... I want it to be able to cycle through the same bitmap... I'll edit my original post to give you an idea... – Matt Apr 03 '12 at 06:55
  • Well, as I see it - that's what the code does currently. When it finds first bitmap, it skips. When it finds second bitmap - it returns it's location. – Dmitry Reznik Apr 03 '12 at 06:57
  • 1
    Had to edit it a bit to get it working for me, Thanks a lot mate! – Matt Apr 03 '12 at 07:22