J'ai une fonction qui calcule la teinte pour une valeur RVB donnée. Pour certaines valeurs, le acos renvoie NaN car l'argument est légèrement supérieur à 1. Ce code suit la plupart des formules que j'ai trouvées en ligne, mais je ne peux pas comprendre pourquoi NaN apparaît.

Des exemples sont

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);
  }
}

c nan
0
Brady Dean 20 févr. 2020 à 09:31

1 réponse

Meilleure réponse

Je ne peux pas comprendre pourquoi NaN apparaît

Et la réponse est là dans ta question :

car l'argument est légèrement supérieur à 1


La bonne question serait dans ce cas :

Comment m'assurer que l'argument de acos n'est pas supérieur à 1 ?

Pour cela, vous devez analyser votre formule et voir d'où vient le problème. Il est possible que le sqrt et la division jouent un rôle.

Le hack le plus simple (peut-être mauvais pour votre application) est de vérifier d'abord si l'argument est supérieur à 1, et si oui, de le tronquer à 1.


Veuillez noter que vous perdez une précision supplémentaire en calculant rn, gn, bn. L'argument de sqrt pourrait mieux être calculé comme :

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

Jouez avec et voyez ce qui se passe.


Aussi, la séquence

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

Doit être utilisé avant d'appeler acos, et en utilisant l'argument (précalculé) de acos au lieu du h calculé.

0
virolino 20 févr. 2020 à 09:28