C# 或 WPF 中如何判断两个颜色是否近似
独立观察员 2023 年 5 月 13 日
一、算法
对于这种算法问题,直接询问 ChatGPT 是最快的:
也就是说有两种方法,一是计算两个颜色的 RGB 分量差之和,二是计算两个颜色的欧几里得距离,然后两者都是与给定的阈值进行比较,小于阈值即可认为是近似的。
本次主要用于 WPF,同时为了便于测试 Demo 的使用,我把 ChatGPT 给的方法整理了一下:
https://gitee.com/dlgcy/WPFTemplateLib/blob/master/WpfHelpers/MediaColorHelper.cs
using System;
using System.Windows.Media;
/*
* 源码己托管: https://gitee.com/dlgcy/WPFTemplateLib
* 版本:2023年5月13日
*/
namespace WPFTemplateLib.WpfHelpers
{
/// <summary>
/// 媒体颜色帮助类
/// </summary>
public class MediaColorHelper
{
#region 相似比较
/// <summary>
/// [ChatGPT] 计算两个颜色之间的欧几里得距离(即两个颜色在 RGB 空间中的距离)
/// </summary>
public static double ColorDistance(Color color1, Color color2)
{
int rDiff = color1.R - color2.R;
int gDiff = color1.G - color2.G;
int bDiff = color1.B - color2.B;
return Math.Sqrt(rDiff * rDiff + gDiff * gDiff + bDiff * bDiff);
}
/// <summary>
/// [ChatGPT] 判断两个颜色是否近似(使用 两个颜色之间的欧几里得距离 与 给定阈值 进行比较,如果距离小于指定的阈值,则认为这两个颜色近似)
/// </summary>
public static bool AreColorsSimilar1(Color color1, Color color2, double threshold = 26)
{
double distance = ColorDistance(color1, color2);
return distance <= threshold;
}
/// <summary>
/// 获取两个颜色的 RGB 分量差之和
/// </summary>
public static int ColorSumOfComponentDifferences(Color color1, Color color2)
{
int rDiff = Math.Abs(color1.R - color2.R);
int gDiff = Math.Abs(color1.G - color2.G);
int bDiff = Math.Abs(color1.B - color2.B);
return rDiff + gDiff + bDiff;
}
/// <summary>
/// [ChatGPT] 判断两个颜色是否近似(判断两个颜色的 RGB 分量差之和是否小于指定的阈值,如果小于则认为这两个颜色近似)
/// </summary>
/// <param name="color1"></param>
/// <param name="color2"></param>
/// <param name="threshold"></param>
/// <returns></returns>
public static bool AreColorsSimilar2(Color color1, Color color2, int threshold = 45)
{
int sum = ColorSumOfComponentDifferences(color1, color2);
return sum <= threshold;
}
#endregion
#region 媒体颜色转换
/// <summary>
/// System.Drawing.Color 转 System.Windows.Media.Color
/// </summary>
/// <returns><see cref="Color"/> 对象,转换失败返回透明色</returns>
public static Color DrawingColorToMediaColor(System.Drawing.Color drawingColor)
{
try
{
return (Color)ColorConverter.ConvertFromString(drawingColor.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex);
return Colors.Transparent;
}
}
/// <summary>
/// 从颜色字符串(支持RGB和ARGB)转换为媒体颜色
/// </summary>
/// <param name="colorStr">ARGB颜色字符串(如#FF000000、#000000)</param>
/// <returns><see cref="Color"/> 对象,转换失败返回透明色</returns>
public static Color ColorStrToMediaColor(string colorStr)
{
try
{
return (Color)ColorConverter.ConvertFromString(colorStr);
}
catch (Exception ex)
{
Console.WriteLine(ex);
return Colors.Transparent;
}
}
#endregion
}
}
至于 C# 版,是一模一样的,只不过颜色对象的命名空间不同而已。WPF 是 System.Windows.Media.Color 媒体颜色,而 C# 是 System.Drawing.Color 绘图颜色。
C# 的绘图颜色帮助类可在如下地址获取:
https://gitee.com/dlgcy/dotnetcodes/blob/dlgcy/DotNet.Utilities/%E9%A2%9C%E8%89%B2/DrawingColorHelper.cs
二、测试程序
在本人的 DLGCY_WPFPractice 项目中添加了一个测试窗口:
窗口上放了两个 HandyControl 的 ColorPicker 颜色选择器控件,选择后(不需要点击确定)会在下方 “方法一” 和 “方法二” 标签前面分别显示 颜色 1 和 颜色 2,方便肉眼近距离比较。方法一比较阈值和两个颜色的欧几里得距离,方法二比较阈值和两个颜色的 RGB 分量差之和,两者的阈值都可以在界面上设置,结果显示在最后面。
推荐使用连续模式,拖动任何一个颜色,底下的所有数据包括比较结果都能实时变动。
三、阈值说明
算法是确定的,但是阈值是不确定的,ChatGPT 也是这样说的:
本次制作这个测试程序的初衷也是为了方便找到一个合适的阈值,当然,这个 “合适” 是针对具体需求来说的,换一个需求场景,阈值也需要跟着变换,这时这个测试程序就能派上用场了。
在帮助类中,我给方法一设置了默认阈值为 26,给方法二设置了默认阈值为 45:
如果你只是粗略判断,或者不知道什么阈值合适,可以直接使用默认阈值,调用时就不用传具体阈值数值了:
另外,无论怎么调整阈值,几乎总能找到一对颜色,让两个方法一个判定为相似,另一个判定为不相似。而且两个方法到底哪个好,目前没有结论。所以在实际使用时,不用纠结用哪个方法,挑一个你觉得顺眼的,然后选好一个阈值,一直用下去就行了。
以下是一些示例:
四、资源
1、颜色比较帮助类:(见第一节)
2、包含此帮助类的 NuGet 包:[WPFTemplateLib](https://www.nuget.org/packages/WPFTemplateLib/)
3、示例程序代码:https://gitee.com/dlgcy/DLGCY_WPFPractice/tree/Blog20230513
4、示例程序 获取方法:
在微信公众号 “独立观察员博客(DLGCY_BLOG)” 消息框回复 “WPFPractice” 获取。
原创文章,转载请注明: 转载自 独立观察员 (dlgcy.com)
本文链接地址:[C# 或 WPF 中如何判断两个颜色是否近似](http://dlgcy.com/how-to-determine-two-color-is-similar-in-csharp-or-wpf/)
-
技术群:添加小编微信并备注进群
小编微信:mm1552923
公众号:dotNet编程大全