You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET颜色选择器控件:颜色名称不显示及颜色筛选问题咨询

问题解答

一、颜色名称显示问题

原因分析

.NET的Color.IsKnownColor仅对系统预定义的颜色(比如Color.LightGreen、Color.Red等)返回true,这些颜色属于KnownColor枚举成员,总数仅140余种。而从图片中提取的RGB颜色几乎都是非预定义值,因此会显示RGB数值而非名称。

解决方案

要给任意RGB颜色匹配名称,有两种可行思路:

  1. 精确匹配预定义颜色:提前创建字典,存储所有已知颜色的RGB值与名称的映射,提取颜色后先查字典找完全匹配项。
  2. 近似匹配最接近颜色:计算提取颜色与所有已知颜色的色差,返回最接近的颜色名称。

代码实现示例

添加颜色名称获取的辅助方法:

private string GetColorName(Color color)
{
    // 优先检查是否为系统预定义颜色
    if (color.IsKnownColor)
    {
        return color.Name;
    }

    // 扩展预定义颜色映射(可添加更多HTML/自定义颜色)
    var colorMap = new Dictionary<Color, string>
    {
        { Color.FromArgb(255, 240, 248, 255), "AliceBlue" },
        { Color.FromArgb(255, 250, 235, 215), "AntiqueWhite" },
        { Color.FromArgb(255, 0, 255, 255), "Cyan" },
        // 可补充所有KnownColor对应的RGB与名称
    };

    // 查找色差最小的近似颜色
    var closestColor = colorMap.OrderBy(c => ColorDistance(c.Key, color)).FirstOrDefault();
    if (!string.IsNullOrEmpty(closestColor.Value))
    {
        return closestColor.Value;
    }

    // 无匹配时返回RGB值
    return $"RGB: {color.R}, {color.G}, {color.B}";
}

// 计算RGB颜色间的欧几里得色差
private double ColorDistance(Color c1, Color c2)
{
    int rDiff = c1.R - c2.R;
    int gDiff = c1.G - c2.G;
    int bDiff = c1.B - c2.B;
    return Math.Sqrt(rDiff * rDiff + gDiff * gDiff + bDiff * bDiff);
}

修改CreateColorGrid中的鼠标悬浮事件逻辑,替换原有的颜色名称获取代码:

string colorName = GetColorName(color);
toolTip1.SetToolTip(currentLabel, colorName);

二、仅显示肉眼可识别的颜色

原因分析

当前代码直接提取图片中出现频率最高的256种颜色,但图片中存在大量因抗锯齿、压缩产生的细微色差像素,这些差异肉眼无法分辨,导致显示的颜色数量远多于实际可见的种类。

解决方案

需要对提取的颜色进行颜色量化,将相似颜色合并为一种。常用方法包括:

  • 简单阈值合并:设定色差阈值,将差值小于阈值的颜色视为同一种。
  • 中位数切割法:专业的颜色压缩算法,适合将大量颜色提炼为指定数量的代表性颜色。
  • K-Means聚类:通过聚类算法分组颜色,每组取中心色作为代表。

代码实现示例(简单阈值合并)

修改ProcessImage方法,在统计颜色后先合并相似颜色:

private void ProcessImage(Bitmap bmp)
{
    var colorCounts = new Dictionary<int, int>();

    // 原像素读取逻辑保持不变,此处省略...

    // 将统计结果转换为(Color, Count)列表
    var allColors = colorCounts.Select(kvp => new { Color = Color.FromArgb(kvp.Key), Count = kvp.Value }).ToList();

    // 合并相似颜色(阈值可调整,值越大合并的颜色越多)
    int colorThreshold = 30;
    var mergedColors = new List<(Color Color, int TotalCount)>();

    foreach (var item in allColors)
    {
        bool merged = false;
        foreach (var mergedItem in mergedColors.ToList())
        {
            if (ColorDistance(item.Color, mergedItem.Color) < colorThreshold)
            {
                // 合并到已有颜色,累加出现次数
                mergedColors.Remove(mergedItem);
                mergedColors.Add((mergedItem.Color, mergedItem.TotalCount + item.Count));
                merged = true;
                break;
            }
        }
        if (!merged)
        {
            mergedColors.Add((item.Color, item.Count));
        }
    }

    // 按出现次数排序,取合并后的所有颜色
    var topColors = mergedColors.OrderByDescending(m => m.TotalCount).Select(m => m.Color).ToArray();
    UpdateColorGrid(topColors);
}

若需要更精准的效果,建议使用成熟的颜色量化算法(如中位数切割法),可自行实现或引用相关开源库。


相关截图说明

  • 显示颜色名称:初始状态下,网格单元格为淡绿色,鼠标悬浮时显示"LightGreen"名称
  • 显示RGB值:拖拽图片后,单元格悬浮提示仅显示RGB数值,无颜色名称
  • 示例图片颜色:肉眼可识别出约17种不同颜色

原显示颜色名称的方法

private void CreateColorGrid()
{
    // Define the size of the grid and the color cells
    int gridSize = 20;
    int gridCols = 16;
    int gridRows = 16;

    // Initialize the grid with green transparent colors
    Color gridColor = Color.LightGreen; // Semi-transparent green

    for (int i = 0; i < gridCols * gridRows; i++)
    {
        Label lbl = new Label
        {
            AutoSize = false,
            Size = new Size(gridSize, gridSize),
            BackColor = gridColor,
            BorderStyle = BorderStyle.Fixed3D,
            Location = new Point(gridSize * (i % gridCols), gridSize * (i / gridCols)),
            Tag = i // Store the index or color information in the Tag property
        };

        // Set up the tooltip for each label
        lbl.MouseEnter += (sender, e) =>
        {
            Label currentLabel = sender as Label;
            if (currentLabel != null)
            {
                // Get the name of the color if it is known, otherwise show the RGB value
                Color color = currentLabel.BackColor;
                string colorName = color.IsKnownColor ? color.Name : $"RGB: {color.R}, {color.G}, {color.B}";
                toolTip1.SetToolTip(currentLabel, colorName);
            }
        };

        lbl.Click += (s, e) =>
        {
            Label currentLabel = s as Label;
            if (currentLabel != null)
            {
                SelectedColor = currentLabel.BackColor;
                // If you want to show a tooltip when a color is selected
                toolTip1.Show($"Selected: {SelectedColor.Name}", currentLabel, 1000); // Show for 1 second
            }
        };

        // Add the label to the UserControl's Controls collection
        this.Controls.Add(lbl);
    }
}

完整原代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ColorAnalyzer
{
    public partial class ImageColorPciker : UserControl
    {
        public Color SelectedColor { get; private set; }
        private ToolTip toolTip1 = new ToolTip();

        public ImageColorPciker()
        {
            InitializeComponent();

            this.AllowDrop = true;
            this.DragEnter += ImageColorPciker_DragEnter;
            this.DragDrop += ImageColorPciker_DragDrop;

            // Create the color grid on initialization
            CreateColorGrid();
        }

        private void ImageColorPciker_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effect = DragDropEffects.Copy;
            }
        }

        private void ImageColorPciker_DragDrop(object sender, DragEventArgs e)
        {
            var files = (string[])e.Data.GetData(DataFormats.FileDrop);
            if (files.Length > 0)
            {
                string filename = files[0];
                using (Image image = Image.FromFile(filename))
                {
                    ProcessImage((Bitmap)image);
                }
            }
        }

        private void ProcessImage(Bitmap bmp)
        {
            var colorCounts = new Dictionary<int, int>();

            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            BitmapData data = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

            try
            {
                int bytesPerPixel = 4;
                int byteCount = bmp.Width * bmp.Height * bytesPerPixel;
                byte[] pixels = new byte[byteCount];
                IntPtr ptrFirstPixel = data.Scan0;
                Marshal.Copy(ptrFirstPixel, pixels, 0, pixels.Length);
                int heightInPixels = data.Height;
                int widthInBytes = data.Width * bytesPerPixel;

                for (int y = 0; y < heightInPixels; y++)
                {
                    int currentLine = y * data.Stride;
                    for (int x = 0; x < widthInBytes; x = x + bytesPerPixel)
                    {
                        int argb = BitConverter.ToInt32(pixels, currentLine + x);
                        if (!colorCounts.ContainsKey(argb))
                            colorCounts[argb] = 1;
                        else
                            colorCounts[argb]++;
                    }
                }
            }
            finally
            {
                bmp.UnlockBits(data);
            }

            var topColors = colorCounts.OrderByDescending(kvp => kvp.Value).Take(256).Select(kvp => Color.FromArgb(kvp.Key)).ToArray();
            UpdateColorGrid(topColors);
        }

        private void UpdateColorGrid(Color[] colors)
        {
            // Assuming we have already created a grid of labels called 'colorCells'
            int index = 0;

            foreach (Label lbl in this.Controls)
            {
                if (index < colors.Length)
                {
                    lbl.BackColor = colors[index];
                }
                else
                {
                    lbl.BackColor = Color.LightGreen; // Default/fallback color
                }
                index++;
            }
        }

        private void CreateColorGrid()
        {
            // Define the size of the grid and the color cells
            int gridSize = 20;
            int gridCols = 16;
            int gridRows = 16;

            // Initialize the grid with green transparent colors
            Color gridColor = Color.LightGreen; // Semi-transparent green

            for (int i = 0; i < gridCols * gridRows; i++)
            {
                Label lbl = new Label
                {
                    AutoSize = false,
                    Size = new Size(gridSize, gridSize),
                    BackColor = gridColor,
                    BorderStyle = BorderStyle.Fixed3D,
                    Location = new Point(gridSize * (i % gridCols), gridSize * (i / gridCols)),
                    Tag = i // Store the index or color information in the Tag property
                };

                // Set up the tooltip for each label
                lbl.MouseEnter += (sender, e) =>
                {
                    Label currentLabel = sender as Label;
                    if (currentLabel != null)
                    {
                        // Get the name of the color if it is known, otherwise show the RGB value
                        Color color = currentLabel.BackColor;
                        string colorName = color.IsKnownColor ? color.Name : $"RGB: {color.R}, {color.G}, {color.B}";
                        toolTip1.SetToolTip(currentLabel, colorName);
                    }
                };

                lbl.Click += (s, e) =>
                {
                    Label currentLabel = s as Label;
                    if (currentLabel != null)
                    {
                        SelectedColor = currentLabel.BackColor;
                        // If you want to show a tooltip when a color is selected
                        toolTip1.Show($"Selected: {SelectedColor.Name}", currentLabel, 1000); // Show for 1 second
                    }
                };

                // Add the label to the UserControl's Controls collection
                this.Controls.Add(lbl);
            }
        }

        private void ImageColorPciker_Load(object sender, EventArgs e)
        {

        }
    }
}

内容的提问来源于stack exchange,提问作者Daniel Lip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 21:15:53