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

如何实现十六进制颜色值转ncurses颜色值的算法?

问题:十六进制颜色转ncurses颜色值的算法实现

我想写一个能把十六进制颜色转换成ncurses颜色值的算法,比如下面的示例:

std::string bar = "#A400C6";
init_pair(1, foo(bar), COLOR_BLACK); // foo应该返回COLOR_MAGENTA(也就是5)
attron(COLOR_PAIR(1));
wprintw(win, "Example");
attroff(COLOR_PAIR(1));

我尝试过让foo函数在整数数组里查找近似值,但没成功。

补充:我写的有问题的算法

class RGB 
{
public:
  uint8_t r;
  uint8_t g;
  uint8_t b;

  RGB(uint8_t r, uint8_t g, uint8_t b)
  {
    this->r = r;
    this->g = g;
    this->b = b;
  }
};

uint8_t cvaluesForRAndB[3] = {0, 24, 178};
uint8_t cvaluesForG[4] = {0, 24, 104, 178};

// 我的KDE终端默认颜色
RGB terminalColors[8] = {{0, 0, 0}, {178, 24, 24}, {24, 178, 24}, {178, 104, 24}, {24, 24, 178}, {178, 24, 178}, {24, 178, 178}, {178, 178, 178}};

bool compareRGB(RGB a, RGB b)
{
  return a.r == b.r && a.g == b.g && a.b == b.b;
}

int foo(std::string hex)
{
  std::string vals[3] = splitWithLength(2, (hex[0] == '#') ? hex.substr(1, 6) : hex); // splitWithLength会按指定长度分割字符串,比如splitWithLength(2, "000cba")返回{"00", "0c", "ba"}

  uint8_t uintVals[3];
  for (uint8_t i = 0; i < 3; i++)
  {
    uintVals[i] = std::stoi(vals[i], nullptr, 16);
  }

  RGB res(findClosest(cvaluesForRAndB, 3, uintVals[0]), findClosest(cvaluesForG, 4, uintVals[1]), findClosest(cvaluesForRAndB, 3, uintVals[2]));

  for (uint8_t i = 0; i < 8; i++)
  {
    if (compareRGB(terminalColors[i], res))
    {
        return i;
    }
  }
  return 0;
}

(代码写在头文件里,质量很差)


解决方案

原代码的核心问题

  1. 近似匹配逻辑错误:你用findClosest把RGB分量分别匹配到固定值,再和终端预设颜色对比,但这种分量独立匹配的方式会导致生成的res可能根本不在terminalColors数组里,最后只能返回默认的0。比如示例中的#A400C6,转换后R匹配178、G匹配0、B匹配178,生成的(178,0,178)和terminalColors[5]的(178,24,178)G分量不同,匹配失败返回0,而非预期的5。
  2. 未实现真正的颜色相似度计算:应该直接计算输入RGB和每个终端预设颜色的颜色距离,选距离最小的那个,而非先强行映射分量再精确匹配。

改进后的实现

第一步:实现颜色距离计算

常用的颜色相似度计算可以用欧几里得距离,或者更贴合人眼感知的加权距离(给绿色更高权重,因为人眼对绿色更敏感)。这里先给出直观的欧几里得距离实现:

#include <cmath>
#include <string>
#include <cstdint>
#include <vector>

class RGB 
{
public:
  uint8_t r;
  uint8_t g;
  uint8_t b;

  RGB(uint8_t r, uint8_t g, uint8_t b) : r(r), g(g), b(b) {}
};

// 我的KDE终端默认颜色
RGB terminalColors[8] = {{0, 0, 0}, {178, 24, 24}, {24, 178, 24}, {178, 104, 24}, {24, 24, 178}, {178, 24, 178}, {24, 178, 178}, {178, 178, 178}};

// 计算两个RGB颜色的欧几里得距离
double rgbDistance(const RGB& a, const RGB& b) {
    double dr = a.r - b.r;
    double dg = a.g - b.g;
    double db = a.b - b.b;
    return sqrt(dr*dr + dg*dg + db*db);
}

第二步:修改foo函数逻辑

直接遍历所有终端预设颜色,计算输入颜色与每个颜色的距离,返回距离最小的颜色索引:

// 按指定长度分割字符串的健壮实现
std::vector<std::string> splitWithLength(size_t len, const std::string& s) {
    std::vector<std::string> res;
    for (size_t i = 0; i < s.size(); i += len) {
        res.push_back(s.substr(i, len));
    }
    return res;
}

int foo(const std::string& hex) {
    // 解析十六进制字符串
    std::string hexStr = hex;
    if (!hexStr.empty() && hexStr[0] == '#') {
        hexStr = hexStr.substr(1);
    }
    // 非法输入直接返回默认黑色
    if (hexStr.size() != 6) {
        return 0;
    }

    auto parts = splitWithLength(2, hexStr);
    uint8_t r = static_cast<uint8_t>(std::stoi(parts[0], nullptr, 16));
    uint8_t g = static_cast<uint8_t>(std::stoi(parts[1], nullptr, 16));
    uint8_t b = static_cast<uint8_t>(std::stoi(parts[2], nullptr, 16));
    RGB input(r, g, b);

    // 遍历找距离最小的颜色
    int closestIndex = 0;
    double minDistance = rgbDistance(input, terminalColors[0]);

    for (int i = 1; i < 8; ++i) {
        double dist = rgbDistance(input, terminalColors[i]);
        if (dist < minDistance) {
            minDistance = dist;
            closestIndex = i;
        }
    }

    return closestIndex;
}

第三步:优化细节

  • 如果想要更精准的人眼感知匹配,可以改用加权距离公式:
    double rgbDistance(const RGB& a, const RGB& b) {
        double dr = a.r - b.r;
        double dg = a.g - b.g;
        double db = a.b - b.b;
        // 加权距离,符合人眼对RGB的敏感度
        return sqrt(0.299*dr*dr + 0.587*dg*dg + 0.114*db*db);
    }
    
  • 增加了输入合法性检查,避免无效十六进制字符串导致的异常。

测试示例

对于输入#A400C6(RGB(164, 0, 198)),计算和terminalColors[5](RGB(178,24,178))的距离约为34.23,是所有预设颜色中最小的,因此会返回5,也就是COLOR_MAGENTA,符合预期。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 09:27:41