在WinForms应用程序中确定像素的颜色

3

我希望能够确定屏幕上某一点的winform背景颜色,以便根据该特定颜色采取一些操作。不幸的是,System.Drawing库似乎没有指定可以实现此操作的方法。

那么我应该如何确定某一点的颜色呢?


可能是https://dev59.com/7nM_5IYBdhLWcg3wMgAF的重复问题。 - Marco
3个回答

5

请使用以下方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;

namespace ColorUnderCursor
{
    class CursorColor
    {
        [DllImport("gdi32")]
        public static extern uint GetPixel(IntPtr hDC, int XPos, int YPos);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern bool GetCursorPos(out POINT pt);

        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr GetWindowDC(IntPtr hWnd);

        /// <summary> 
        /// Gets the System.Drawing.Color from under the mouse cursor. 
        /// </summary> 
        /// <returns>The color value.</returns> 
        public static Color Get()
        {
            IntPtr dc = GetWindowDC(IntPtr.Zero);

            POINT p;
            GetCursorPos(out p);

            long color = GetPixel(dc, p.X, p.Y);
            Color cc = Color.FromArgb((int)color);
            return Color.FromArgb(cc.B, cc.G, cc.R);
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int X;
        public int Y;
        public POINT(int x, int y)
        {
            X = x;
            Y = y;
        } 
    }
}

这是不完整的,你用来调用GetPixel的'dc'变量在哪里定义? - fuaaark

4
假設您想避免使用Win32 API,您可以使用Graphics.CopyFromScreen()將屏幕內容繪製到一個Bitmap對象中。從那裡,您只需要使用Bitmap.GetPixel()來檢索具有正確顏色的Color對象。

以下是可用於檢索完整桌面(可與多個顯示器一起使用)的代碼:

public Image GetScreenshot()
{
    int screenWidth = Convert.ToInt32(System.Windows.SystemParameters.VirtualScreenWidth);
    int screenHeight = Convert.ToInt32(SystemParameters.VirtualScreenHeight);
    int screenLeft = Convert.ToInt32(SystemParameters.VirtualScreenLeft);
    int screenTop = Convert.ToInt32(SystemParameters.VirtualScreenTop);

    Image imgScreen = new Bitmap(screenWidth, screenHeight);
    using (Bitmap bmp = new Bitmap(screenWidth, screenHeight, PixelFormat.Format32bppArgb))
    using (Graphics g = Graphics.FromImage(bmp))
    using (Graphics gr = Graphics.FromImage(imgScreen))
    {
        g.CopyFromScreen(screenLeft, screenTop, 0, 0, new Size(screenWidth, screenHeight));
        gr.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
        gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
        gr.DrawImage(bmp, new Rectangle(0, 0, screenWidth, screenHeight));
    }

    return imgScreen;
}

2
这是对其他已有答案的略微不同看法,因为您只声明想确定“颜色”,但并没有明确说明您需要RGB值。
这种区别是必要的,因为颜色可能存在人眼无法察觉的变化。例如,假设您想检测颜色“蓝色”。值(5, 5, 240)和(10, 10, 255)与(0, 0, 255)之间仅有微小差异。实际上,差异非常微妙,您需要将颜色样本并排比较才能区分它们,即使如此,这还取决于您的监视器质量。它们在我的台式电脑显示器上略有不同,但在我的笔记本电脑上则无法区分。简而言之,RGB值不是确定颜色的好方法。
有许多方法可帮助计算颜色之间的差异,其中最常见的是Delta-E方法。然而,如果您只需要一个快速而简单的方法,这可能会过度了。将RGB空间转换为HSV,并使用色调差异来确定颜色。修改Amen的示例,您可以得到以下内容:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;

class CursorHue
    {
        [DllImport("gdi32")]
        public static extern uint GetPixel(IntPtr hDC, int XPos, int YPos);

        public static float GetHue(Point p)
        {           
            long color = GetPixel(dc, p.X, p.Y);
            Color cc = Color.FromArgb((int)color);
            return cc.GetHue();
        }
    }

纯蓝色的色调值为240。之前的例子(5, 5, 240)和(10, 10, 255)的色调都是240。这是个好消息,因为它意味着色调是一个相当容忍RGB差异的度量,而且差异也很容易计算(即只需取色调值的绝对差)。在这一点上,我们还应该介绍另一个参数,它控制了对颜色差异的可接受容忍度。15度的色调容差将使系统相当健壮。
下面是比较两种颜色以确定它们是否相似的示例代码。
public static bool AreSimilar(Color c1, Color c2, float tolerance = 15f)
{
  return Math.Abs(c1.GetHue() - c2.GetHue() <= tolerance;
}

为了更深入地解释为什么这样做有效,请参阅维基百科关于HSV色彩空间的文章

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接