C# 或 WPF 中如何判断两个颜色是否近似

一、算法

对于这种算法问题,直接询问 ChatGPT 是最快的:.

C# 或 WPF 中如何判断两个颜色是否近似

也就是说有两种方法,一是计算两个颜色的 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 项目中添加了一个测试窗口:

C# 或 WPF 中如何判断两个颜色是否近似

窗口上放了两个 HandyControl 的 ColorPicker 颜色选择器控件,选择后(不需要点击确定)会在下方 “方法一” 和 “方法二” 标签前面分别显示 颜色 1 和 颜色 2,方便肉眼近距离比较。方法一比较阈值和两个颜色的欧几里得距离,方法二比较阈值和两个颜色的 RGB 分量差之和,两者的阈值都可以在界面上设置,结果显示在最后面。

推荐使用连续模式,拖动任何一个颜色,底下的所有数据包括比较结果都能实时变动。

三、阈值说明

算法是确定的,但是阈值是不确定的,ChatGPT 也是这样说的:

C# 或 WPF 中如何判断两个颜色是否近似

本次制作这个测试程序的初衷也是为了方便找到一个合适的阈值,当然,这个 “合适” 是针对具体需求来说的,换一个需求场景,阈值也需要跟着变换,这时这个测试程序就能派上用场了。

在帮助类中,我给方法一设置了默认阈值为 26,给方法二设置了默认阈值为 45:

C# 或 WPF 中如何判断两个颜色是否近似

如果你只是粗略判断,或者不知道什么阈值合适,可以直接使用默认阈值,调用时就不用传具体阈值数值了:

C# 或 WPF 中如何判断两个颜色是否近似

另外,无论怎么调整阈值,几乎总能找到一对颜色,让两个方法一个判定为相似,另一个判定为不相似。而且两个方法到底哪个好,目前没有结论。所以在实际使用时,不用纠结用哪个方法,挑一个你觉得顺眼的,然后选好一个阈值,一直用下去就行了。

以下是一些示例:

C# 或 WPF 中如何判断两个颜色是否近似

C# 或 WPF 中如何判断两个颜色是否近似

C# 或 WPF 中如何判断两个颜色是否近似

四、资源

1、颜色比较帮助类:(见第一节)

2、包含此帮助类的 NuGet 包:[WPFTemplateLib](https://www.nuget.org/packages/WPFTemplateLib/)

3、示例程序代码:https://gitee.com/dlgcy/DLGCY_WPFPractice/tree/Blog20230513

4、示例程序 获取方法:

在微信公众号 “独立观察员博客(DLGCY_BLOG)” 消息框回复 “WPFPractice” 获取。