【问题标题】:Trying to match pixel colour then click [C#]尝试匹配像素颜色然后单击 [C#]
【发布时间】:2020-02-08 16:11:49
【问题描述】:

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

还有一个循环的开始/停止按钮会很好。

到目前为止我的代码:

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;
        }
    }
}

谢谢

【问题讨论】:

  • ...如果相同,请单击鼠标... 如果我可能会问,请单击鼠标做什么?如果您可以详细说明您要实现的目标,也许有人会提出更好的方法。
  • 嘿,我只是想检测屏幕上的颜色,所以如果它在屏幕上,它的目的就是点击。我打算将点击更改为另一个目的,但这会因为我想做类似的事情。所以为了更清楚,我想运行一个循环搜索使用鼠标位置选择的颜色或在文本框中输入 i (我已经完成),然后在该确切像素与我正在寻找的颜色匹配时单击。如果你愿意,我可以让你知道它的确切目的,但我认为这没有意义,因为这主要是我想要它做的。

标签: c# colors click pixel detection


【解决方案1】:

嗯,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 按钮的点击事件中启动和停止计时器。

这是一个演示:

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


2020 年 2 月 11 日编辑

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

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&lt;Point&gt;()并将检查条件更改为:

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

【讨论】:

  • 哇,谢谢,这比我能做的要好。它并没有完全按照我的意图做,但它仍然对其他事情有用。我的目的是让它能够抓取颜色(它可以做到),然后选择一个像素位置。一旦它具有要查找的像素和颜色,那么它只会检查一个像素是否完全忽略鼠标位置,因为在检查等待它的匹配时不会触摸计算机。所以基本上只需选择一个像素并检查直到它再次相同并单击(我将使用 API 将单击更改为其他一些代码)。
  • 我一定会看看那些全局键盘钩子。我遇到问题的部分是,一旦我选择了像素位置(并将其放置在 X 和 Y 位置的文本框中),我怎样才能将它们放入一个点来代替 cursor.position 以便我可以搜索那一个像素。此外,这不是必需的,但能够检查多个不同的像素和这些像素的颜色将是惊人的,但如果它只是一个工作,我会很高兴。非常感谢!
  • 非常感谢,我一定会尽快尝试的! :)
猜你喜欢
  • 1970-01-01
  • 2011-06-09
  • 2021-07-05
  • 1970-01-01
  • 2015-04-09
  • 2022-10-09
  • 2018-10-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多