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

如何将Color转换为KnownColor名称?自定义方法返回Unknown

问题:ARGB颜色转KnownColor名称始终返回Unknown

我的List<Color>集合里存了39000多种从图片提取的颜色,例如第一个元素是{Name = ffcecece, ARGB = (255, 206, 206, 206)}。我想把这些颜色的ARGB值转换为对应的KnownColor名称(比如Blue、Red),但自定义的GetKnownColorName方法始终返回"Unknown"。

相关代码

点击事件代码

private void label1_Click(object sender, EventArgs e)
{
    if(colorsAdded)
    {
        for(int i =0; i < colors.Count; i++)
        {
            colorsNames.Add(GetKnownColorName(colors[i]));
        }
    }
}

转换方法代码

private string GetKnownColorName(Color color)
{
    foreach (KnownColor knownColor in Enum.GetValues(typeof(KnownColor)))
    {
        Color knownColorValue = Color.FromKnownColor(knownColor);

        if (knownColorValue.ToArgb() == color.ToArgb())
        {
            return knownColor.ToString();
        }
    }

    return "Unknown";
}

完整代码

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;

namespace Colors_Scanner
{
    public partial class Form1 : Form
    {
        private Bitmap imageBitmap;
        private Bitmap imageBitmapComparison;
        private Color currentColor;
        private List<string> colorsNames = new List<string>();
        private List<Color> colors = new List<Color>();
        private Bitmap bmp;
        private bool colorsAdded = false; // Flag to track if colors have been added

        public Form1()
        {
            InitializeComponent();

            // Load images into PictureBox controls
            LoadImages();

            // Initialize the bitmap for pictureBox2
            bmp = new Bitmap(pictureBox2.Image);
        }

        private void LoadImages()
        {
            // Load an image into the PictureBox control
            imageBitmap = new Bitmap(@"D:\Ffmpeg Capture\radar1.jpg"); // Replace with your image
            pictureBox1.Size = imageBitmap.Size;
            pictureBox1.Image = imageBitmap;

            imageBitmapComparison = new Bitmap(@"D:\Ffmpeg Capture\colorslevels1.jpg"); // Replace with your ruler image
            pictureBox2.Size = imageBitmapComparison.Size;
            pictureBox2.Image = imageBitmapComparison;
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (IsMouseWithinPictureBoxBounds(e.Location, pictureBox1))
            {
                UpdateColorLabel(e.Location);
                currentColor = GetColorAtCursor(e.Location, imageBitmap);
                pictureBox2.Invalidate();
            }
        }

        private void pictureBox2_Paint(object sender, PaintEventArgs e)
        {
            Pen pen = new Pen(currentColor);
            e.Graphics.DrawRectangle(pen, new Rectangle(0, 0, 3, 3));

            if (!colorsAdded)
            {
                // Add colors from pictureBox2 only once
                AddColorsFromPictureBox2();
                colorsAdded = true; // Set the flag to true after adding colors
            }
        }

        private List<Color> AddColorsFromPictureBox2()
        {
            if (bmp != null)
            {
                for (int i = 0; i < bmp.Width; i++)
                {
                    if (i == bmp.Width - 1)
                    {
                        break;
                    }

                    for (int j = 0; j < bmp.Height; j++)
                    {
                        Color c = bmp.GetPixel(i, j);
                        // You can add the color to your list here
                        colors.Add(c);
                    }
                }
            }

            return colors;
        }

        private void UpdateColorLabel(Point location)
        {
            Color color = GetColorAtCursor(location, imageBitmap);
            label1.Text = $"RGB: ({color.R}, {color.G}, {color.B})";
            label1.BackColor = color;
        }

        private Color GetColorAtCursor(Point location, Bitmap bitmap)
        {
            int x = location.X;
            int y = location.Y;

            if (IsMouseWithinPictureBoxBounds(location, pictureBox1))
            {
                BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                    ImageLockMode.ReadOnly, bitmap.PixelFormat);

                try
                {
                    int bytesPerPixel = Bitmap.GetPixelFormatSize(bitmap.PixelFormat) / 8;
                    IntPtr ptr = bmpData.Scan0;
                    int pixelOffset = y * bmpData.Stride + x * bytesPerPixel;

                    byte b = System.Runtime.InteropServices.Marshal.ReadByte(ptr, pixelOffset);
                    byte g = System.Runtime.InteropServices.Marshal.ReadByte(ptr, pixelOffset + 1);
                    byte r = System.Runtime.InteropServices.Marshal.ReadByte(ptr, pixelOffset + 2);

                    return Color.FromArgb(r, g, b);
                }
                finally
                {
                    bitmap.UnlockBits(bmpData);
                }
            }

            return Color.Black; // Default color if outside of PictureBox bounds
        }

        private bool IsMouseWithinPictureBoxBounds(Point location, PictureBox pictureBox)
        {
            return location.X >= 0 && location.X < pictureBox.Width && location.Y >= 0 && location.Y < pictureBox.Height;
        }

        private void label1_Click(object sender, EventArgs e)
        {
            if(colorsAdded)
            {
                for(int i =0; i < colors.Count; i++)
                {
                    colorsNames.Add(GetKnownColorName(colors[i]));
                }
            }
        }

        private string GetKnownColorName(Color color)
        {
            foreach (KnownColor knownColor in Enum.GetValues(typeof(KnownColor)))
            {
                Color knownColorValue = Color.FromKnownColor(knownColor);

                if (knownColorValue.ToArgb() == color.ToArgb())
                {
                    return knownColor.ToString();
                }
            }

            return "Unknown";
        }
    }
}

原因分析
  1. KnownColor数量有限:KnownColor枚举仅包含约140种预定义颜色,其中还包括大量随系统主题变化的系统颜色(如ActiveBorder、Window),而图片中的颜色是24位/32位真彩色,理论上有几百万种可能,大部分颜色本来就不在KnownColor范围内。
  2. 系统颜色干扰:原方法遍历了所有KnownColor,包括系统主题色,这些颜色的ARGB值会随系统设置变化,无法与固定的图片颜色匹配。
  3. 效率低下:遍历所有KnownColor(约140次)匹配每个颜色,对于39000个颜色来说,会产生大量不必要的计算。

解决方案

1. 只匹配固定命名颜色(排除系统颜色)

修改转换方法,跳过系统颜色,只匹配固定ARGB值的命名颜色(如Red、Blue):

private string GetKnownColorName(Color color)
{
    foreach (KnownColor knownColor in Enum.GetValues(typeof(KnownColor)))
    {
        Color knownColorValue = Color.FromKnownColor(knownColor);
        // 跳过系统颜色,只匹配固定命名颜色
        if (knownColorValue.IsSystemColor)
            continue;
        
        if (knownColorValue.ToArgb() == color.ToArgb())
        {
            return knownColor.ToString();
        }
    }

    return "Unknown";
}

2. 预缓存颜色字典提升效率

提前将所有固定命名颜色的ARGB值和名称存入字典,后续查询直接从字典获取,大幅提升效率:

// 类级别的字典缓存
private static readonly Dictionary<int, string> _knownColorMap = new Dictionary<int, string>();

// 在静态构造函数中初始化缓存
static Form1()
{
    foreach (KnownColor knownColor in Enum.GetValues(typeof(KnownColor)))
    {
        Color knownColorValue = Color.FromKnownColor(knownColor);
        if (!knownColorValue.IsSystemColor)
        {
            int argb = knownColorValue.ToArgb();
            if (!_knownColorMap.ContainsKey(argb))
            {
                _knownColorMap.Add(argb, knownColor.ToString());
            }
        }
    }
}

// 修改后的转换方法
private string GetKnownColorName(Color color)
{
    int argb = color.ToArgb();
    return _knownColorMap.TryGetValue(argb, out string name) ? name : "Unknown";
}

3. 接受“Unknown”是正常结果

如果图片中的颜色确实不是预定义的KnownColor,返回"Unknown"是合理的。如果需要对这些颜色进行命名,可以考虑使用颜色近似匹配(比如计算颜色相似度,找到最接近的KnownColor)。


内容的提问来源于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.05 13:52:02