Bueno, estoy buscando una función o algo que va a leer el color de un píxel determinado en mi monitor, y cuando el color es detectado, la otra función estará habilitada. Me imagino que el uso de RGB. Toda la ayuda es apreciada. Gracias.

  • ¿Quieres controlar todo el escritorio o una aplicación específica para este píxel cambio?
  • un píxel determinado. Como dice el pixel en la 125, 130 necesito esperar hasta que se detecta el RGB del píxel ir a cierta RGB.
  • ¿Por qué usted necesita hacer esto? Parece que hay algún tipo de razón subyacente que si nos dan un poco más de información que podría ser capaz de dar una mejor manera para lograr la misma cosa. Estás escribiendo un juego y la necesidad de determinar cuando dos objetos chocan? Estás tratando de averiguar si un determinado programa se ha iniciado?
  • Es para un juego, se trata de dos de verificar si es en una pantalla determinada, y cuando es así, se inicia una función.
  • Pero usted debe saber lo de la pantalla del juego en el que estás en control de código…
InformationsquelleAutor Brandon | 2009-09-27

5 Comentarios

  1. 40

    Este es el más eficiente: Se agarra un píxel en la posición del cursor, y no depender de un solo 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 (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);
    }
    }
    }

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

    EDICIÓN:

    Dado lo anterior GetColorAt función puede sondear un determinado píxel en la pantalla en un lugar seguro, el rendimiento de manera fácil como esto:

    private void PollPixel(Point location, Color color)
    {
    while(true)
    {
    var c = GetColorAt(location);
    if (c.R == color.R && c.G == color.G && c.B == 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()
    }
    }

    Usted puede envolver que en un Hilo si quieres, o ejecutar desde una aplicación de Consola. «Lo que se adapte a su fantasía,» supongo.

    • +1 por señalar que CopyFromScreen puede ser utilizado para simplemente capturar una pequeña área de la pantalla.
    • Pero tenga en cuenta que CopyFormScreen se fuga de un mango cada vez que llama.
    • Actualizado para evitar la fuga.
    • Gracias Juan, este funciona de maravilla, otra pregunta rápida. Si quiero que esta continuamente en la búsqueda de píxeles, ¿cómo puedo lograr esto?
    • Sé que esto es 10 años de retraso, pero en caso de que alguien esté interesado en la respuesta a @Brandon pregunta: he utilizado un temporizador, establecer un intervalo para cada 250 ms (o sin embargo rápido que usted desea buscar) y, a continuación, en la timer_tick hacer la lectura real. enlace
  2. 16

    La mayoría de las respuestas aquí el uso de la misma fuente de ese píxel (de escritorio de cc).

    La función de la clave 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 más limpia y más rápida.

    Nota:

    Si ha modificado el tamaño de texto por defecto entre los Ajustes de la Pantalla en Windows para aumentar la legibilidad en una pantalla de alta resolución, las coordenadas de los parámetros de GetPixel() deben ser ajustados de la misma manera. Por ejemplo, si la ubicación del cursor es (x,y) con el 150% del tamaño del texto en Windows 7, usted necesita llamar a GetPixel(x*1.5, y*1.5) para obtener el color del píxel bajo el cursor.

    • Habib, la nota agregó que no es parte de mi respuesta. No es mi know-how, es tuyo. Por favor hacer un comentario, si puedes. Entonces usted puede conseguir upvotes en el comentario. Además creo que el ajuste de x e y en GetPixel está fuera de lugar. Es mejor para comprobar la resolución de los ajustes y la posición del cursor en algún lugar fuera de la GetColorAt-método.
    • +1 por la nota sobre el tamaño del texto en la pantalla. Si hay un texto diferente tamaño de 100% y no está ajustado correctamente, el método de obtener los colores de la mal píxeles.
  3. 6

    Esta función es más corto y se puede lograr el mismo resultado con el uso de 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);
    }
  4. 5

    Por favor revise esta dos funciones diferentes que he utilizado en uno de mis anteriores proyectos :

    1) Esta función toma instantánea de 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 RGB promedio de píxel dado alcance.

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

    Esta dos funciones en conjunto podría resolver su problema. Feliz Codificación 🙂

    EDITAR : por Favor, tenga en cuenta que GetPixel es muy lento de la función. Voy a pensar dos veces antes de usarlo.

  5. 4

    Hasta donde yo sé la manera más fácil de hacer esto es:

    1. tomar una captura de pantalla
    2. mirar el mapa de bits y obtener el color de los píxeles

    Editar

    Probablemente no hay manera de «esperar» hasta que el píxel cambia a un color determinado. El programa tendrá que probablemente solo bucle y comprobar que cada tan a menudo hasta que se ve 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();

    EDITAR 2

    Aquí está el código de ejemplo que se puede modificar. Este código sólo cambia el color de una etiqueta basada en el color actual en un píxel dado. Este código se evita la pérdida de manejar mencionado.

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

    }

    • Preferiría no hacerlo de esta manera, he pensado en ello, pero simplemente no es una opción. El píxel tiene que ser visto como constantemente como la que se encuentra el píxel sobre el que está buscando en menos de un minuto, constantemente.
    • Luego no ponen un sueño. Este bucle probablemente tendría todas las de .1 segundos para recorrer peor de los casos.
    • Tenga en cuenta que usted no debe correr .CopyFromScreen, dispone de un asa de fuga, lo mejor es aplicar este código de uso de API de Win32
    • Bitmap.GetPixel() devuelve un Color así que no veo ninguna razón para llamar a ToArgb() y pasar a Color.FromArgb()

Dejar respuesta

Please enter your comment!
Please enter your name here