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

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

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

独立观察员 2023 年 5 月 13 日

一、算法

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

%title插图%num

 

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

%title插图%num

 

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

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

 

三、阈值说明

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

%title插图%num

 

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

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

%title插图%num

 

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

%title插图%num

 

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

 

以下是一些示例:

%title插图%num

%title插图%num

%title插图%num

 

四、资源

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) 第一时间获取最新文章

%title插图%num

发表评论