确定 winforms 应用程序中像素的颜色
本文关键字:颜色 像素 winforms 应用程序 确定 | 更新日期: 2023-09-27 18:30:55
我希望能够确定屏幕上某个点的背景颜色,这样我就可以根据该特定颜色采取一些操作。可悲的是,System.Drawing库似乎没有指定使我能够这样做的方法。
那么我应该如何确定某个点的颜色?
使用它:
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;
}
}
}
假设你想要远离 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;
}
这与已经提供的其他答案略有不同,因为您只声明要确定"颜色",但没有明确说明您想要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色彩空间的维基百科文章。