画面上の特定のポイントでWinFormの背景色を判別できるようにしたいので、その特定の色に応じて何らかのアクションを実行できます。残念ながら、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に変換し、色相の違いを使用して色を決定します。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度の色相許容度により、システムはかなり堅牢になります。
2つの色を比較して、許容できる程度に類似しているかどうかを判断するサンプルコードを次に示します。
public static bool AreSimilar(Color c1, Color c2, float tolerance = 15f)
{
return Math.Abs(c1.GetHue() - c2.GetHue() <= tolerance;
}
これが機能する理由の詳細については、HSV色空間に関するこのウィキペディアの記事を参照してください。