首页 > 解决方案 > RGB 到 HIS 为某些 RGB 值提供 NaN

问题描述

我有一个函数可以计算给定 rgb 值的色调。对于某些值,acos返回 NaN 因为参数略大于 1。这段代码遵循我在网上找到的大多数公式,但我不知道为什么会弹出 NaN。

例子是

40 28 28
40 28 28
40 28 28
49 25 25
46 34 34
40 28 28
42 24 24
42 24 24
40 22 22
40 22 22
#include <math.h>

double hue(unsigned char r, unsigned char g, unsigned char b) {
  double rn = (double) r / (r + g + b);
  double gn = (double) g / (r + g + b);
  double bn = (double) b / (r + g + b);

  if (rn == gn && gn == bn) {
    return 0;
  }

  double h = acos((rn - gn + rn - bn) / (2.0 * sqrt((rn - gn) * (rn - gn) + (rn - bn) * (gn - bn))));

  // issue with the argument of acos being just slightly bigger than 1. Approximate to 0
  if (isnan(h)) {
    h = 0;
  }

  if (b > g) {
    return (2 * M_PI - h) * (180.0 / M_PI);
  } else {
    return h * (180.0 / M_PI);
  }
}

标签: cnan

解决方案


我不明白为什么 NaN 会弹出

答案就在您的问题中:

因为参数略大于 1


在这种情况下,正确的问题是:

我应该如何确保参数acos不大于 1?

为此,您需要分析您的公式并查看问题出在哪里。和分工有可能sqrt发挥作用。

最简单的 hack(可能对您的应用程序不利)是首先验证参数是否大于 1,如果是,则将其截断为 1。


请注意,您失去了额外的精度计算rn,,,gnbn的参数sqrt可能更好地计算为:

a = (r-g)*(r-g)+(r-b)*(g-b);
b = (r+g+b)*(r+g+b);
argument = a/b;

玩它,看看会发生什么。


还有,顺序

// issue with the argument of acos being just slightly bigger than 1. Approximate to 0
if (isnan(h)) {
    h = 0;
}

应该在调用之前acos使用,并且使用(预先计算的)参数acos而不是计算的h


推荐阅读