如何读取屏幕像素的颜色
好的,我正在寻找一个function或东西,将读取我的显示器上的某个像素的颜色,当这种颜色被检测到,另一个function将被启用。 我使用RGB图。 所有帮助赞赏。 谢谢。
这是最高效的:它在光标位置抓取一个像素,并且不依赖于只有一个监视器。
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 (cR == cG && cG < 64 && cB > 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); } } }
现在,显然,你不必使用光标的当前位置,但这是一般的想法。
编辑:
鉴于上面的GetColorAt
函数,您可以以安全,性能友好的方式轮询屏幕上的某个像素:
private void PollPixel(Point location, Color color) { while(true) { var c = GetColorAt(location); if (cR == color.R && cG == color.G && cB == color.B) { DoAction(); return; } // By calling Thread.Sleep() without a parameter, we are signaling to the // operating system that we only want to sleep long enough for other // applications. As soon as the other apps yield their CPU time, we will // regain control. Thread.Sleep() } }
如果需要,可以将其封装在线程中,或者从控制台应用程序执行。 “无论你喜欢什么,”我想。
这里的大多数答案都使用与该像素完全相同的来源(桌面直stream)。
关键function是GetPixel
。
[DllImport("user32.dll", SetLastError = true)] public static extern IntPtr GetDesktopWindow(); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr GetWindowDC(IntPtr window); [DllImport("gdi32.dll", SetLastError = true)] public static extern uint GetPixel(IntPtr dc, int x, int y); [DllImport("user32.dll", SetLastError = true)] public static extern int ReleaseDC(IntPtr window, IntPtr dc); public static Color GetColorAt(int x, int y) { IntPtr desk = GetDesktopWindow(); IntPtr dc = GetWindowDC(desk); int a = (int) GetPixel(dc, x, y); ReleaseDC(desk, dc); return Color.FromArgb(255, (a >> 0) & 0xff, (a >> 8) & 0xff, (a >> 16) & 0xff); }
我认为这是最干净,最快捷的方式。
注意 :
如果您在Windows上的“显示设置”中修改了默认的文本大小以提高高分辨率显示的可读性,则需要以相同的方式调整GetPixel()的坐标参数。 例如,如果在Windows 7中光标位置是(x,y)的文本大小是150%,则需要调用GetPixel(x * 1.5,y * 1.5)来获取光标下像素的颜色。
请检查我在以前的一个项目中使用的这两个不同的function:
1)此function拍摄桌面的快照
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)该function将input图像并计算给定像素范围的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 ; }
这两个function可以解决你的问题。 快乐编码:)
编辑 :请注意,GetPixel是非常慢的function。 我会考虑使用它。
据我所知最简单的方法是:
- 截图
- 看看位图并获取像素颜色
编辑
在像素变成某种颜色之前,可能没有办法“等待”。 你的程序可能不得不循环查看,直到看到颜色。
例如:
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; } } } }
}