-1

I am scanning the screen for a button to click using the code below.

I pass in two bitmaps one is a picture of the button the other is a screenshot.

Is there anyway I can speed this basic method up?

private PositionToClick IsInCapture(Bitmap searchFor, Bitmap searchIn)
{
    for (int x = 0; x < searchIn.Width; x++)
    {
        for (int y = 0; y < searchIn.Height; y++)
        {
            bool invalid = false;
            int k = x, l = y;
            for (int a = 0; a < searchFor.Width; a++)
            {
                l = y;
                for (int b = 0; b < searchFor.Height; b++)
                {
                    if (searchFor.GetPixel(a, b) != searchIn.GetPixel(k, l))
                    {
                        invalid = true;
                        break;
                    }
                    else
                        l++;
                }
                if (invalid)
                    break;
                else
                    k++;
            }

            if (!invalid)
                return new PositionToClick() { X = x, Y = y, found = true };
        }
    }

    return new PositionToClick();
}
Mr J
  • 2,655
  • 4
  • 37
  • 58
  • 1
    Seems like this would be better on [codereview](https://codereview.stackexchange.com). – itsme86 Mar 26 '19 at 14:32
  • 1
    Avoid GetPixel for something like this. Instead look for how to copy blocks of video memory and compare those. – 500 - Internal Server Error Mar 26 '19 at 14:32
  • Try using a method as described in [this question](https://stackoverflow.com/questions/2031217/what-is-the-fastest-way-i-can-compare-two-equal-size-bitmaps-to-determine-whethe); scan a crop of the subject bitmap with the criteria bitmap for every possible X/Y offset. I'd strongly recommend you consider heuristic methods - perhaps only look for the left-edge of a button first, then other features. – Patrick Mar 26 '19 at 14:33
  • This was exactly what I needed if anyone stumbles upon this. Very quick. https://codereview.stackexchange.com/questions/138011/find-a-bitmap-within-another-bitmap – Mr J Mar 26 '19 at 17:49

1 Answers1

1

You can convert the bitmaps to byte arrays first, and then compare those arrays. Also, you can restrict your search area by subtracting the width and height of the image you are searching from. I did not test the code below, it's just an illustration of what I mean.

private PositionToClick IsInCapture(Bitmap searchFor, Bitmap searchIn)
{
    var searchForArray = ImageToByte2(searchFor);
    var searchInArray = ImageToByte2(searchIn);
    for (int x = 0; x <= searchIn.Width - searchFor.Width; x++)
    {
        for (int y = 0; y <= searchIn.Height - searchFor.Height; y++)
        {
            bool invalid = false;
            int k = x, l = y;
            for (int a = 0; a < searchFor.Width; a++)
            {
                l = y;
                for (int b = 0; b < searchFor.Height; b++)
                {
                    var pixelFor = searchForArray[a * searchFor.Width + b];
                    var pixelIn = searchInArray[k + searchIn.Width + l];
                    if (pixelIn != pixelFor)
                    {
                        invalid = true;
                        break;
                    }
                    else
                        l++;
                }
                if (invalid)
                    break;
                else
                    k++;
            }

            if (!invalid)
                return new PositionToClick() { X = x, Y = y, found = true };
        }
    }
    return new PositionToClick();
}

public static byte[] ImageToByte2(Image img)
{
    using (var stream = new MemoryStream())
    {
        img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
        return stream.ToArray();
    }
}
Bart van der Drift
  • 1,287
  • 12
  • 30