Cómo leer el Color de un Pixel de Pantalla

De acuerdo, estoy buscando una función o algo que lea el color de un determinado píxel en mi monitor, y cuando se detecte ese color, se habilitará otra función. Me imagino usando RGB. Toda ayuda apreciada. Gracias.

    Este es el más eficiente: toma un píxel en la ubicación del cursor, y no se basa solo en tener un monitor.

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

    Ahora, obviamente, no tiene que usar la ubicación actual del cursor, pero esta es la idea general.

    EDITAR:

    Dada la función GetColorAt anterior, puede sondear un cierto píxel en la pantalla de una manera segura y amigable para el rendimiento como esta:

     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() } } 

    Puede envolver eso en un subproceso si lo desea, o ejecutarlo desde una aplicación de consola. “Lo que sea que te guste”, supongo.

    La mayoría de las respuestas aquí usan la misma fuente de ese píxel (PC de escritorio).
    La función clave es 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); } 

    Creo que esta es la manera más limpia y rápida.

    Nota :

    Si ha modificado el tamaño de texto predeterminado entre la Configuración de pantalla en Windows para boost la legibilidad en una pantalla de alta resolución, los parámetros de coordenadas de GetPixel () deben ajustarse de la misma manera. Por ejemplo, si la ubicación del cursor es (x, y) con un 150% del tamaño del texto en Windows 7, debe llamar a GetPixel (x * 1.5, y * 1.5) para obtener el color del píxel debajo del cursor.

    Por favor, compruebe estas dos funciones diferentes que he usado en uno de mis proyectos anteriores:

    1) Esta función toma una instantánea del escritorio

     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) Esta función toma una imagen en la entrada y calcula el promedio RGB del rango de píxeles dado.

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

    Estas dos funciones juntas podrían resolver su problema. Happy Coding 🙂

    EDITAR : Tenga en cuenta que GetPixel es una función muy lenta. Lo pensaré dos veces antes de usarlo.

    Hasta donde yo sé, la forma más fácil de hacerlo es:

    1. tomar una captura de pantalla
    2. mira el bitmap y obtén el color del píxel

    Editar

    Probablemente no haya forma de “esperar” hasta que el píxel cambie a un determinado color. Su progtwig probablemente tendrá que repetir y revisarlo de vez en cuando hasta que vea el color.

    Por ejemplo:

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

    EDIT 2

    Aquí hay un código de muestra que puede modificar. Este código simplemente cambia el color de una etiqueta en función del color actual en un píxel determinado. Este código evita la pérdida de identificador mencionada.

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

    }

    Esta función es más corta y puede lograr el mismo resultado usando System.Drawing , sin 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); }