简体   繁体   English

RGB 到 HIS 为某些 RGB 值提供 NaN

[英]RGB to HIS giving NaN for certain RGB values

I have a function that calculates hue for a given rgb value.我有一个函数可以计算给定 rgb 值的色调。 For some values, the acos returns NaN because the argument is slightly larger than 1. This code follows most of the formulas I found online but I can't figure out why NaN is popping up.对于某些值, acos返回 NaN,因为参数略大于 1。此代码遵循我在网上找到的大多数公式,但我不知道为什么会弹出 NaN。

Examples are例子是

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我不明白为什么 NaN 会出现

And the answer is there in your question:答案就在您的问题中:

because the argument is slightly larger than 1因为参数略大于 1


The correct question would be in this case:在这种情况下,正确的问题是:

How should I make sure that the argument to acos is not bigger than 1?我应该如何确保acos的参数不大于 1?

For that, you need to analyze your formula and see where the problem comes from.为此,您需要分析您的公式并查看问题出在哪里。 It is possible that the sqrt and the division play a role. sqrt和除法有可能起作用。

The easiest hack (might be bad for your application) is to verify first if the argument is bigger than 1, and if yes, truncate it to 1.最简单的技巧(可能对您的应用程序不利)是首先验证参数是否大于 1,如果是,则将其截断为 1。


Please notice that you loose extra precision calculating rn , gn , bn .请注意,您失去了计算rngnbn额外精度。 The argument to sqrt might better be calculated as: sqrt的参数最好计算为:

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

Play with it and see what happens.玩它,看看会发生什么。


Also, the sequence另外,序列

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

should be used before calling acos , and using the (precalculaed) argument of acos instead of the calculated h .应该在调用之前使用acos ,以及使用的(precalculaed)参数acos代替计算h

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM