C# 或 WPF 中如何判断两个颜色是否近似
一、算法
对于这种算法问题,直接询问 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# 的绘图颜色帮助类可在如下地址获取:
二、测试程序
在本人的 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 中如何判断两个颜色是否近似](https://dlgcy.com/how-to-determine-two-color-is-similar-in-csharp-or-wpf/)
关注微信公众号 独立观察员博客(DLGCY_BLOG) 第一时间获取最新文章
发表评论