尝试匹配像素颜色然后单击 [C#]

Trying to match pixel colour then click [C#]

我需要帮助让我的程序将 "stored" 颜色与同一位置的当前颜色匹配,如果相同则单击鼠标。到目前为止,在我的代码中抓取颜色效果很好,只是不确定如何匹配颜色和点等。

循环的 start/stop 按钮也不错。

到目前为止我的代码:

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Pixel_detection_test_3
{
    public partial class PixelDetectionForm : Form
    {
        private const UInt32 MOUSEEVENTF_LEFTDOWN = 0x0002;
        private const UInt32 MOUSEEVENTF_LEFTUP = 0x0004;

        [DllImport("user32.dll")]
        private static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, uint dwExtraInf);

        private int pixelY;
        private int pixelX;
        private Point pixelYX;
        private static Color currentColour;
        private static Color storedColour;

        public PixelDetectionForm()
        {
            InitializeComponent();
        }

        static Color GetPixel(Point position)
        {
            using (var bitmap = new Bitmap(1, 1))
            {
                using (var graphics = Graphics.FromImage(bitmap))
                {
                    graphics.CopyFromScreen(position, new Point(0, 0), new Size(1, 1));
                }
                return bitmap.GetPixel(0, 0);
            }
        }

        private void PixelDetectionForm_KeyDown(object sender, KeyEventArgs e)
        {
            // Get Cursor Pixel Position
            if (e.KeyCode == Keys.F1 || e.KeyCode == Keys.F2)
            {
                pixelY = Cursor.Position.Y;
                pixelX = Cursor.Position.X;
                pixelYX = Cursor.Position;
                textBoxYPos.Text = pixelY.ToString();
                textBoxXPos.Text = pixelX.ToString();
                e.Handled = true;
            }
            // Get Cursor Pixel Colour
            if (e.KeyCode == Keys.F1 || e.KeyCode == Keys.F3)
            {
                storedColour = GetPixel(Cursor.Position);
                textBoxColour.Text = storedColour.ToString().Remove(0, 14).TrimEnd(']');
                panelColourDisplay.BackColor = storedColour;
                e.Handled = true;
            }
        }

        // Not working, need help with this
        private async void buttonStart_Click(object sender, EventArgs e)
        {
            while (true)
            {
                GetPixel(pixelYX);

                // Should get position of 'pixelY' and 'pixelX'
                panelColourDisplay2.BackColor = GetPixel(Cursor.Position);

                if (pixelYX == storedColour)
                {
                    MousePress();
                }
                // Need this to prevent not responding
                await Task.Delay(3);
            }
        }

        private void MousePress()
        {
            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
        }

        private void PixelDetectionForm_Click(object sender, EventArgs e)
        {
            ActiveControl = null;
        }

        private void PixelDetectionForm_Activated(object sender, EventArgs e)
        {
            ActiveControl = null;
        }
    }
}

谢谢

嗯,while..loop 的替代方法是使用 Timer 来实现。

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Pixel_detection_test_3
{
    public partial class PixelDetectionForm : Form
    {
        private readonly Timer Tmr;

        private Point lastPoint;
        //Assign this from your input code.
        private Color targetColor;

        public PixelDetectionForm()
        {
            Tmr = new Timer { Interval = 50 };
            Tmr.Tick += (s, e) => FindMatches(Cursor.Position);
        }
        //...

在计时器的 Tick 事件中,调用 FindMatches(..) 方法来检查当前 Cursor.Position 并将不同的匹配项添加到 ListBox 中。您可以在找到匹配项时将最后一部分替换为您真正需要做的事情。比如在你的代码中调用 MousePress() 方法:

        //...
        private void FindMatches(Point p)
        {
            //To avoid the redundant calls..
            if (p.Equals(lastPoint)) return;

            lastPoint = p;

            using (var b = new Bitmap(1, 1))
            using (var g = Graphics.FromImage(b))
            {
                g.CopyFromScreen(p, Point.Empty, b.Size);

                var c = b.GetPixel(0, 0);

                if (c.ToArgb().Equals(targetColor.ToArgb()) &&
                    !listBox1.Items.Cast<Point>().Contains(p))
                {
                    listBox1.Items.Add(p);
                    listBox1.SelectedItem = p;
                }
            }
        }

        private void PixelDetectionForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            Tmr.Dispose();
        }
    }
}

StartStop 按钮的点击事件中启动和停止计时器。

这是一个演示:

另一种选择是使用全局鼠标和键盘挂钩。查看 this, , and this 了解更多详情。


编辑 2/11/2020

如果你只想检查给定图像中给定点的给定颜色是否存在,那么你可以这样做:

private void buttonStart_Click(object sender, EventArgs e)
{
    var targetColor = ...; //target color.
    var targetPoint = ...; //target point.
    var sz = Screen.PrimaryScreen.Bounds.Size;
    using (var b = new Bitmap(sz.Width, sz.Height, PixelFormat.Format32bppArgb))
    using (var g = Graphics.FromImage(b))
    {
        g.CopyFromScreen(Point.Empty, Point.Empty, b.Size, CopyPixelOperation.SourceCopy);

        var bmpData = b.LockBits(new Rectangle(Point.Empty, sz), ImageLockMode.ReadOnly, b.PixelFormat);
        var pixBuff = new byte[bmpData.Stride * bmpData.Height];

        Marshal.Copy(bmpData.Scan0, pixBuff, 0, pixBuff.Length);

        b.UnlockBits(bmpData);

        for (var y = 0; y < b.Height; y++)
        for(var x = 0; x < b.Width; x++)
        {
            var pos = (y * bmpData.Stride) + (x * 4);
            var blue = pixBuff[pos];
            var green = pixBuff[pos + 1];
            var red = pixBuff[pos + 2];
            var alpha = pixBuff[pos + 3];

            if (Color.FromArgb(alpha, red, green, blue).ToArgb().Equals(targetColor.ToArgb()) &&
                new Point(x, y).Equals(targetPoint))
            {
                //execute you code here..
                MessageBox.Show("The given color exists at the given point.");
                return;
            }
        }
    }
    MessageBox.Show("The given color doesn't exist at the given point.");
}

如果你想得到给定颜色的所有位置的列表,那么新建一个List<Point>()并将检查条件更改为:

//...
var points = new List<Point>();
if (Color.FromArgb(alpha, red, green, blue).ToArgb().Equals(targetColor.ToArgb()))
{
    points.Add(new Point(x, y));
}