0

I want to make color_detection_bot and This bot provide me that when I click the button in this form, mousecursor changes position to facebook login button and click it.First of all I created a bitmap in Paint and save in System.Resources name as bmpLogin and this bitmap shows a 24 bit bitmap of facebook login button.

 private void btn_login_Click(object sender, EventArgs e)
    {

        this.BackgroundImage = Screenshot(); //Method which is take screenshot

        Point location;
        bool success=FindBitmap(Properties.Resources.bmpLogin, Screenshot(), out location);


        if (success == false)
        {
            MessageBox.Show("Couldn't find the login button");
            return;
        }


        Cursor.Position = location;   //bitmap location within screenshot

        MouseCLick();                //Mouse click event works successfull

    }

/// <summary>
    /// Find the location of bitmap within  another bitmap and return if it was succesfully found
    /// </summary>
    /// <param name="bmpNeedle"> The image we want to find </param>
    /// <param name="bmpHaystack"> Where we want to search for the image </param>
    /// <param name="location"> Where we found the image </param>
    /// <returns> If the bmpNeedle was found succesfully </returns>
    private Boolean FindBitmap(Bitmap bmpNeedle, Bitmap bmpHaystack, out Point location)
    {
        for (int outerX = 0; outerX < bmpHaystack.Width; outerX++)
        {
            for (int outerY = 0; outerY < bmpHaystack.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)
                        {
                            goto Notfound;
                        }
                    }
                }
                location = new Point(outerX, outerY);
                return true;
                Notfound:
                continue;

            }      
        }

        location = Point.Empty;
        return false;
    }

This codes works perfectly But When I change if statemant as shown in below, Bot doesnt work.Where am I doing logical error

private Boolean FindBitmap(Bitmap bmpNeedle, Bitmap bmpHaystack, out Point location)
    {
        for (int outerX = 0; outerX < bmpHaystack.Width; outerX++)
        {
            for (int outerY = 0; outerY < bmpHaystack.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)
                        {
                            location = new Point(outerX, outerY);
                            return true;
                        }
                    }
                } 

            }      
        }

        location = Point.Empty;
        return false;
    }
Algosu Aresi
  • 25
  • 1
  • 4
  • Probably a good demonstration what's wrong with `goto`. Stop shooting your leg off by writing a FindNeedle() method that returns *true* only when *all* of the pixels in the needle match the color. – Hans Passant Dec 21 '14 at 11:33
  • @HansPassant But First code works perfectly and dont need to match all pixels – Algosu Aresi Dec 21 '14 at 11:36
  • 1
    @HansPassant actually I took this programs from [link](http://www.youtube.com/watch?v=gEgxZrXPnzc) – Algosu Aresi Dec 21 '14 at 11:38
  • I think there's a problem with your outerX and outerY indexes. You don't want to search all the way across haystack, only to the right edge of haystack minus the width of needle. Likewise, you don't want to search all the way down haystack, only til you get to bottom of haystack minus height of needle. Otherwise this code "bmpHaystack.GetPixel(innerX + outerX, innerY + outerY);" will produce invalid indexes down in the bottom right corner of haystack. – RenniePet Dec 21 '14 at 11:51

1 Answers1

1

In your first code sample, the algorithm is matching all the pixels. In your second code sample, the algorithm is returning the location of the first matched pixel.

It's not enough just to match one pixel. For example, say your full image is:

    1    2    3    4
1   a    a    b    b
2   a    a    c    a
3   a    b    a    a

And you're searching for:

    1    2
1   a    b
2   a    c

Your second block of code looks first at 1,1 and says, brilliant, they are both a, job done, and merrily returns the wrong answer. However your first block of code will look at 1,1, it matches so then it goes to 1,2 see that it is b whereas they haystack is a, and then the goto takes it to not found, and it searches the next position of the haystack.

As already pointed out, it's a good demonstration of what's wrong with goto. See here GOTO still considered harmful? for a full discussion on the topic.

Two other problems with this - one already mentioned, that if your search image is in the bottom right, you're going to go out of bounds when you compare it to the larger image - if we use the simple example above, if your search start point is at 4,3, then as you go to compare to the second column of the smaller image, you're looking at 5,3, which doesn't exist. Second problem, GetPixel is very slow, for a large search image this code is going to take a while - and it can't be multi-threaded. A faster but more complicated implementation is to use LockBits, which is much faster to access. Sample implementation is below.

static void Main(string[] args)
{
    Bitmap haystack = (Bitmap)Image.FromFile(@"c:\temp\haystack.bmp");
    Bitmap needle = (Bitmap)Image.FromFile(@"c:\temp\needle.bmp");

    Point location;
    if (FindBitmap(haystack, needle, out location) == false)
    {
        Console.WriteLine("Didn't find it");
    }
    else
    {
        using (Graphics g = Graphics.FromImage(haystack))
        {
            Brush b = new SolidBrush(Color.Red);
            Pen pen = new Pen(b, 2);
            g.DrawRectangle(pen, new Rectangle(location, new Size(needle.Width, needle.Height)));
        }

        haystack.Save(@"c:\temp\found.bmp");

        Console.WriteLine("Found it @ {0}, {1}", location.X, location.Y);
    }

    Console.ReadKey();
}

public class LockedBitmap : IDisposable
{
    private BitmapData _data = null;
    private Bitmap _sourceBitmap = null;
    private byte[] _pixelData = null;

    public readonly int BytesPerPixel, WidthInBytes, Height, Width, ScanWidth;

    public LockedBitmap(Bitmap bitmap)
    {
        _sourceBitmap = bitmap;
        _data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);

        BytesPerPixel = Bitmap.GetPixelFormatSize(bitmap.PixelFormat) / 8;
        ScanWidth = _data.Stride;
        int byteCount = _data.Stride * bitmap.Height;
        _pixelData = new byte[byteCount];
        Marshal.Copy(_data.Scan0, _pixelData, 0, byteCount);
        WidthInBytes = bitmap.Width * BytesPerPixel;
        Height = bitmap.Height;
        Width = bitmap.Width;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void GetPixel(int x, int y, out int r, out int g, out int b)
    {
        int realY = y * ScanWidth;
        int realX = x * BytesPerPixel;
        b = (int)_pixelData[realY + realX];
        g = (int)_pixelData[realY + realX + 1];
        r = (int)_pixelData[realY + realX + 2];
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);               
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposing) return;

        if (_sourceBitmap != null && _data != null) 
            _sourceBitmap.UnlockBits(_data);                
    }
}

private static bool FindBitmap(Bitmap haystack, Bitmap needle, out Point location)
{
    using (LockedBitmap haystackToSearch = new LockedBitmap(haystack))
    using (LockedBitmap needleToSearch = new LockedBitmap(needle))
    {
        for (int outerY = 0; outerY <= (haystackToSearch.Height - needleToSearch.Height); outerY++)
        {
            for (int outerX = 0; outerX <= (haystackToSearch.Width - needleToSearch.Width); outerX++)
            {
                bool isMatched = true;
                for (int innerY = 0; innerY < needleToSearch.Height; innerY++)
                {
                    for (int innerX = 0; innerX < needleToSearch.Width; innerX++)
                    {
                        int needleR, needleG, needleB;
                        int haystackR, haystackG, haystackB;
                        haystackToSearch.GetPixel(outerX + innerX, outerY + innerY, out haystackR, out haystackG, out haystackB);
                        needleToSearch.GetPixel(innerX, innerY, out needleR, out needleG, out needleB);

                        isMatched = isMatched && needleR == haystackR && haystackG == needleG && haystackB == needleB;
                        if (!isMatched)
                            break;
                    }

                    if (!isMatched)
                        break;
                }

                if (isMatched)
                {
                    location = new Point(outerX, outerY);
                    return true;
                }
            }
        }
    }

    location = new Point();
    return false;
}
Community
  • 1
  • 1
steve16351
  • 5,372
  • 2
  • 16
  • 29