Comment lire la couleur d'un Pixel D'écran

OK, je cherche une fonction ou quelque chose qui va lire la couleur d'un certain pixel sur mon moniteur, et quand cette couleur est détectée, une autre fonction sera activée. Je pense utiliser le RGB. Toute aide appréciée. remercier.

32
demandé sur Henk Holterman 2009-09-27 20:51:02

5 réponses

C'est le plus efficace: Il s'empare d'un pixel à l'emplacement du curseur, et ne pas compter sur un seul moniteur.

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

Maintenant, évidemment, vous n'avez pas à utiliser le curseur à l'emplacement actuel, mais c'est l'idée générale.

EDIT:

étant GetColorAt fonction vous pouvez Poller un certain pixel sur l'écran d'une manière sûre et conviviale comme ceci:

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

vous pouvez l'envelopper dans un fil si vous voulez, ou l'exécutez à partir d'une application Console. "Ce qui vous convient", je suppose.

37
répondu John Gietzen 2009-09-28 06:03:27

la plupart des réponses ici utilisent la même source de ce pixel (dc de bureau).

La fonction clé est 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);
}

je pense que c'est le plus propre et le plus rapide.

Remarque::

si vous avez modifié la taille de texte par défaut parmi les paramètres D'affichage sur Windows pour augmenter la lisibilité sur un écran de haute résolution, les paramètres de coordonnées de GetPixel() doivent être ajustés de la même manière. Par exemple, si l'emplacement du curseur est(x,y) avec 150% de la taille du texte sur Windows 7, vous devez appeler GetPixel (x*1.5, y*1.5) pour obtenir la couleur du pixel sous le curseur.

15
répondu Bitterblue 2016-09-15 09:26:06

Veuillez vérifier ces deux différentes fonctions que j'ai utilisé dans un de mes précédents projets :

1) Cette fonction prend un instantané du Bureau

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) Cette fonction prend une image en entrée et calcule la moyenne RVB de la plage de pixels donnée.

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

ces deux fonctions ensemble pourraient résoudre votre problème. Amusez-Vous Bien :)

EDIT: veuillez noter que GetPixel est une fonction très lente. Je vais réfléchir à deux fois avant d'utiliser il.

5
répondu MRG 2009-09-27 17:07:46

autant Que je sache, la meilleure façon de le faire est:

  1. prendre une capture d'écran
  2. regardez l'image et obtenir la couleur du pixel

Modifier

il n'y a probablement aucun moyen d ' "attendre" jusqu'à ce que le pixel change en une certaine couleur. Votre programme devra probablement juste boucler et vérifier de temps en temps jusqu'à ce qu'il voit la couleur.

Par exemple:

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

modifier 2

Voici un exemple de code que vous pouvez modifier. Ce code change juste la couleur d'une étiquette basée sur la couleur actuelle dans un pixel donné. Ce code évite la fuite de la poignée mentionnée.

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

}

4
répondu tster 2009-09-27 18:05:11

cette fonction est plus courte et peut atteindre le même résultat en utilisant System.Drawing, sans 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);
}
2
répondu J3soon 2018-04-26 09:50:19