C# 如何读取屏幕像素的颜色

C# 如何读取屏幕像素的颜色,c#,winforms,gdi+,pixel,C#,Winforms,Gdi+,Pixel,好的,我正在寻找一个功能或东西,可以读取显示器上某个像素的颜色,当检测到该颜色时,另一个功能将被启用。我想使用RGB。谢谢你的帮助。谢谢。据我所知,最简单的方法是: 查看位图并获得像素颜色 编辑 在像素变为某种颜色之前,可能无法“等待”。您的程序可能需要经常循环并检查它,直到它看到颜色为止 例如: while(!IsPixelColor(x, y, color)) { //probably best to add a sleep here so your program doesn't

好的,我正在寻找一个功能或东西,可以读取显示器上某个像素的颜色,当检测到该颜色时,另一个功能将被启用。我想使用RGB。谢谢你的帮助。谢谢。

据我所知,最简单的方法是:

  • 查看位图并获得像素颜色
  • 编辑

    在像素变为某种颜色之前,可能无法“等待”。您的程序可能需要经常循环并检查它,直到它看到颜色为止

    例如:

    while(!IsPixelColor(x, y, color))
    {
        //probably best to add a sleep here so your program doesn't use too much CPU
    }
    DoAction();
    
    编辑2

    下面是一些可以修改的示例代码。此代码只是基于给定像素中的当前颜色更改标签的颜色。此代码避免了前面提到的句柄泄漏

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;
    using System.Runtime.InteropServices;
    
    namespace WindowsFormsApplication1
    {
    public partial class Form1 : Form
    {
    
        [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
        public static extern int BitBlt(IntPtr hDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);
    
    
        Thread t;
        int x, y;
    
        public Form1()
        {
            InitializeComponent();
        }
    
        private void Form1_Load(object sender, EventArgs e)
        {
            x = 20;
            y = 50;
            t = new Thread(update);
            t.Start();
        }
    
        private void update()
        {
            Bitmap screenCopy = new Bitmap(1, 1);
            using (Graphics gdest = Graphics.FromImage(screenCopy))
            {
                while (true)
                {
                    //g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(256, 256));
                    using (Graphics gsrc = Graphics.FromHwnd(IntPtr.Zero))
                    {
                        IntPtr hSrcDC = gsrc.GetHdc();
                        IntPtr hDC = gdest.GetHdc();
                        int retval = BitBlt(hDC, 0, 0, 1, 1, hSrcDC, x, y, (int)CopyPixelOperation.SourceCopy);
                        gdest.ReleaseHdc();
                        gsrc.ReleaseHdc();
                    }
                    Color c = Color.FromArgb(screenCopy.GetPixel(0, 0).ToArgb());
                    label1.ForeColor = c;
                }
            }
        }
    }
    

    }

    这是最有效的:它在光标位置捕获一个像素,并且不依赖于只有一个监视器

    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    using System.Diagnostics;
    
    namespace FormTest
    {
        public partial class Form1 : Form
        {
            [DllImport("user32.dll")]
            static extern bool GetCursorPos(ref Point lpPoint);
    
            [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
            public static extern int BitBlt(IntPtr hDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void MouseMoveTimer_Tick(object sender, EventArgs e)
            {
                Point cursor = new Point();
                GetCursorPos(ref cursor);
    
                var c = GetColorAt(cursor);
                this.BackColor = c;
    
                if (c.R == c.G && c.G < 64 && c.B > 128)
                {
                    MessageBox.Show("Blue");
                }
            }
    
            Bitmap screenPixel = new Bitmap(1, 1, PixelFormat.Format32bppArgb);
            public Color GetColorAt(Point location)
            {
                using (Graphics gdest = Graphics.FromImage(screenPixel))
                {
                    using (Graphics gsrc = Graphics.FromHwnd(IntPtr.Zero))
                    {
                        IntPtr hSrcDC = gsrc.GetHdc();
                        IntPtr hDC = gdest.GetHdc();
                        int retval = BitBlt(hDC, 0, 0, 1, 1, hSrcDC, location.X, location.Y, (int)CopyPixelOperation.SourceCopy);
                        gdest.ReleaseHdc();
                        gsrc.ReleaseHdc();
                    }
                }
    
                return screenPixel.GetPixel(0, 0);
            }
        }
    }
    

    如果需要,您可以将其包装在线程中,或者从控制台应用程序执行它。“随便你喜欢什么,”我想。

    请检查我在以前的一个项目中使用过的两个不同功能:

    1) 此函数用于拍摄桌面的快照

    private void CaptureScreenAndSave(string strSavePath)
            {
    
                //SetTitle("Capturing Screen...");
    
                Bitmap bmpScreenshot;
    
                Graphics gfxScreenshot;
                bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height,System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                gfxScreenshot = Graphics.FromImage(bmpScreenshot);
                gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
                MemoryStream msIn = new MemoryStream();
                bmpScreenshot.Save(msIn, System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders()[0], null);
    
                msIn.Close();
    
                byte[] buf = msIn.ToArray();
    
                MemoryStream msOut = new MemoryStream();
    
                msOut.Write(buf, 0, buf.Length);
    
                msOut.Position = 0;
    
                Bitmap bmpOut = new Bitmap(msOut);
    
                try
                {
                    bmpOut.Save(strSavePath, System.Drawing.Imaging.ImageFormat.Bmp);
                    //SetTitle("Capturing Screen Image Saved...");
                }
    
                catch (Exception exp)
                {
    
                }
    
                finally
                {
                    msOut.Close();
                }
            }
    
    2) 此函数在输入中获取图像,并计算给定像素范围的RGB平均值

    double GetRGBAverageForPixelRange( int istartRange, int iEndRange,  Bitmap oBitmap )
            {
                double dRetnVal = 0 ;
                Color oTempColor ; 
                int i, j ;
                for( int iCounter = istartRange ; iCounter < iEndRange ; iCounter++ )
                {
                    i = (iCounter % (oBitmap.Width));
                    j = ( iCounter / ( oBitmap.Width ) ) ;
                    if (i >= 0 && j >= 0 && i < oBitmap.Width && j < oBitmap.Height )
                    {
                        oTempColor = oBitmap.GetPixel(i, j);
                        dRetnVal = dRetnVal + oTempColor.ToArgb();
                    }
    
                }
                return dRetnVal ;
            }
    
    double GetRGBAverageForPixelRange(int-istartRange、int-iEndRange、位图oBitmap)
    {
    双德雷特瓦尔=0;
    颜色和颜色;
    int i,j;
    for(int-iCounter=istartRange;iCounter=0&&j>=0&&i
    这两个功能结合在一起可能会解决您的问题。快乐编码:)


    编辑:请注意GetPixel的功能非常慢。在使用它之前,我会三思而后行。

    这里的大多数答案都使用相同的像素源(桌面dc)。
    关键功能是

    我认为这是最干净、最快捷的方法

    注意


    如果修改了Windows上显示设置中的默认文本大小,以提高高分辨率显示的可读性,则需要以相同的方式调整GetPixel()的坐标参数。例如,在Windows 7上,如果光标位置为(x,y)且文本大小为150%,则需要调用GetPixel(x*1.5,y*1.5)以获取光标下像素的颜色。

    此函数较短,并且可以使用
    System.Drawing
    ,而不使用Pinvoke获得相同的结果

    Bitmap bmp = new Bitmap(1, 1);
    Color GetColorAt(int x, int y)
    {
        Rectangle bounds = new Rectangle(x, y, 1, 1);
        using (Graphics g = Graphics.FromImage(bmp))
            g.CopyFromScreen(bounds.Location, Point.Empty, bounds.Size);
        return bmp.GetPixel(0, 0);
    }
    

    这条线大约用10毫秒

    int retval = BitBlt(hDC, 0, 0, 1, 1, hSrcDC, location.X, location.Y, (int)CopyPixelOperation.SourceCopy);
    

    是否要监视整个桌面或特定应用程序的像素更改?特定像素。比如说125130的像素,我需要它等到它检测到这个像素的RGB变成某个RGB,为什么要这样做?似乎有某种潜在的原因,如果你给我们多一点信息,我们可能会给你一个更好的方法来实现同样的目标。你正在写一个游戏,需要确定两个物体何时碰撞?你想知道某个程序是否已经启动了吗?这是一个游戏,需要两次检查它是否在某个屏幕上,当它在某个屏幕上时,它会启动一个函数。但是你应该知道游戏在哪个屏幕上,因为你控制着代码……我不想这样做,我已经考虑过了,但这不是一个选项。像素必须不断地被观察,因为它会在不到一分钟的时间内不断地找到它要找的像素。然后不要睡觉。在最坏的情况下,此循环可能需要花费所有的.1秒来循环。请注意,您不应该运行.CopyFromScreen,它有一个句柄泄漏,最好是使用Win32 API
    Bitmap.GetPixel()
    返回一个
    颜色
    ,因此我认为没有理由调用
    ToArgb()
    并将其传递到
    Color.FromArgb()
    +1中,以指出CopyFromScreen可用于仅捕获屏幕的一小部分。但请注意,CopyFormScreen每次调用时都会泄漏一个句柄。谢谢John,这非常有效,这是另一个快速问题。如果我想让它持续搜索像素,我该如何实现呢?我知道这已经晚了10年,但如果有人对@Brandon的问题的答案感兴趣:我使用了一个计时器,每250毫秒设置一个间隔(或者你希望它搜索的速度有多快),然后在计时器上打勾进行实际读取。哈比卜,你加的字条不是我答案的一部分。这不是我的技术,是你的。如果可以的话,请发表评论。然后你可以在评论上获得投票。此外,我认为在GetPixel上调整x和y是错误的。最好在GetColorAt方法之外的某个地方检查分辨率调整和光标位置。+1用于显示文本大小的注释。如果文本大小不同于100%,且未正确调整,则该方法将从错误的像素获取颜色。
    Bitmap bmp = new Bitmap(1, 1);
    Color GetColorAt(int x, int y)
    {
        Rectangle bounds = new Rectangle(x, y, 1, 1);
        using (Graphics g = Graphics.FromImage(bmp))
            g.CopyFromScreen(bounds.Location, Point.Empty, bounds.Size);
        return bmp.GetPixel(0, 0);
    }
    
    int retval = BitBlt(hDC, 0, 0, 1, 1, hSrcDC, location.X, location.Y, (int)CopyPixelOperation.SourceCopy);