3

我希望能够在屏幕上的某个点确定 winform 的背景颜色,因此我可以根据该特定颜色采取一些措施。可悲的是 System.Drawing 库似乎没有指定一种方法让我能够这样做。

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

4

3 回答 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;
        } 
    }
}
于 2012-04-12T09:21:20.053 回答
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;
}
于 2012-04-12T09:21:17.123 回答
2

这与已经提供的其他答案略有不同,因为您只声明要确定“颜色”,但没有明确声明您需要 RGB 值。

这种区分是必要的,因为颜色可能存在人眼无法察觉的变化。例如,假设您对检测颜色“蓝色”感兴趣。值 (5, 5, 240) 和 (10, 10, 255) 与 (0, 0, 255) 仅有非常细微的不同。事实上,差异是如此微妙,以至于您需要并排比较颜色样本才能将它们区分开来,即便如此,这也取决于显示器的质量。它们在我的桌面显示器上略有不同,但在我的笔记本电脑上却无法区分。长话短说,RGB 值是确定颜色的不好方法。

有许多方法可以帮助计算颜色之间的差异,最常见的是 Delta-E 方法。但是,如果您只想要一种快速而肮脏的方法,这可能会过头了。将 RGB 空间转换为 HSV 并使用色调的差异来确定颜色。修改阿门的例子,你得到以下内容:

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 颜色空间的Wikipedia文章。

于 2012-04-12T09:43:17.083 回答