尝试匹配像素颜色,然后单击[C#] [英] Trying to match pixel colour then click [C#]

查看:240
本文介绍了尝试匹配像素颜色,然后单击[C#]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need help getting my program to match the "stored" colour with the current one in the same location then click the mouse if it's the same. The grabbing of the colour works great so far in my code just unsure how to match a colour and a point, etc.

此外,循环的开始/停止按钮会

Also a start/stop button for the loop would be nice.

到目前为止我的代码:

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 的替代方法是使用计时器来实现。

Well, an alternative to the while..loop is using a Timer to achieve that.

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()方法一样:

In the timer's Tick event, the FindMatches(..) method is called to check the current Cursor.Position and add the distinct matches into a ListBox. You can replace the last part with what you really need to do when you find a match. Like calling the MousePress() method in your code:

        //...
        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();
        }
    }
}

在以下事件的点击事件中启动和停止计时器开始停止按钮。

Start and stop the timer in the click events of the Start and Stop buttons.

这是一个演示:

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

Another alternative is to use the Global Mouse and Keyboard Hooks. Check this, this, and this for more details.

编辑2/11/2020

如果您只是想检查给定颜色是否在给定图像中存在给定点,则可以执行以下操作:

If you just want to check whether a given color at a given point exists in a given image, then you can do:

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

If you want to get a list of all the positions of a given color, then create a new List<Point>() and change the check condition to:

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

这篇关于尝试匹配像素颜色,然后单击[C#]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆