RGB 到 HIS 为某些 RGB 值提供 NaN

RGB to HIS giving NaN for certain RGB values

我有一个函数可以计算给定 rgb 值的色调。对于某些值,acos returns 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);
  }
}

I can't figure out why NaN is popping up

答案就在你的问题中:

because the argument is slightly larger than 1


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

How should I make sure that the argument to acos is not bigger than 1?

为此,您需要分析您的公式,看看问题出在哪里。有可能是sqrt和除法起作用了。

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


请注意,您在计算 rngnbn 时失去了额外的精度。 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.