web-dev-qa-db-fra.com

La formule la plus rapide pour obtenir la teinte de RVB

Si vous obtenez des valeurs rouges, vertes et bleues comprises entre 0 et 255, quel serait le calcul le plus rapide pour obtenir uniquement la valeur de teinte? Cette formule sera utilisée sur chaque pixel d'une image 640x480 à 30 ips (9,2 millions de fois par seconde), de sorte que chaque optimisation de la vitesse est utile.

J'ai vu d'autres formules mais je ne suis pas satisfait du nombre d'étapes qu'elles impliquent. Je cherche une formule réelle, pas une fonction de bibliothèque intégrée.

20
user3161533
  1. Convertissez les valeurs RVB dans la plage 0-1, en divisant la valeur par 255 pour une profondeur de couleur de 8 bits (les valeurs r, g, b - sont indiquées):

     R = r/255 = 0,09 
     G = g/255 = 0,38 
     B = b/255 = 0,46

  2. Trouvez les valeurs minimales et maximales de R, G et B.

  3. En fonction de quel canal de couleur RVB est la valeur maximale. Les trois formules différentes sont: If Red is max, then Hue = (G-B)/(max-min) If Green is max, then Hue = 2.0 + (B-R)/(max-min) If Blue is max, then Hue = 4.0 + (R-G)/(max-min)

La valeur de teinte que vous obtenez doit être multipliée par 60 pour la convertir en degrés sur le cercle de couleur. Si la teinte devient négative, vous devez ajouter 360 à, car un cercle a 360 degrés.

Voici article complet .

23
Umriyaev

En plus de la réponse d'Umriyaev:

Si seule la teinte est nécessaire, il n'est pas nécessaire de diviser les couleurs à plage 0-255 avec 255.

Le résultat de e.x. (green - blue) / (max - min) sera le même pour n'importe quelle plage (tant que les couleurs sont dans la même plage bien sûr).

Voici l'exemple de Java pour obtenir la teinte:

public int getHue(int red, int green, int blue) {

    float min = Math.min(Math.min(red, green), blue);
    float max = Math.max(Math.max(red, green), blue);

    if (min == max) {
        return 0;
    }

    float hue = 0f;
    if (max == red) {
        hue = (green - blue) / (max - min);

    } else if (max == green) {
        hue = 2f + (blue - red) / (max - min);

    } else {
        hue = 4f + (red - green) / (max - min);
    }

    hue = hue * 60;
    if (hue < 0) hue = hue + 360;

    return Math.round(hue);
}

Edit: ajouté vérifier si min et max sont les mêmes, puisque le reste du calcul n'est pas nécessaire dans ce cas, et pour éviter une division par 0 (voir commentaires)

Edit: erreur Java corrigée

15
Zarokka
// convert rgb values to the range of 0-1
var h;
r /= 255, g /= 255, b /= 255;

// find min and max values out of r,g,b components
var max = Math.max(r, g, b), min = Math.min(r, g, b);

if(max == r){
    // if red is the predominent color
    h = (g-b)/(max-min);
}
else if(max == g){
    // if green is the predominent color
    h = 2 +(b-r)/(max-min);
}
else if(max == b){
    // if blue is the predominent color
    h = 4 + (r-g)/(max-min);
}

h = h*60; // find the sector of 60 degrees to which the color belongs
// https://www.pathofexile.com/forum/view-thread/1246208/page/45 - hsl color wheel

if(h > 0){
    // h is a positive angle in the color wheel
    return Math.floor(h);
}
else{
    // h is a negative angle.
    return Math.floor(360 -h);
}
2
DTNPerera

Vous devez spécifier la langue dont vous avez besoin. C #, Java et C sont des langages très différents et peuvent fonctionner sur différentes plates-formes

La résolution 640x480 n’est pas très grande par rapport aux résolutions courantes actuelles. Vous devez essayer toutes les solutions possibles et les points de repère. Un algorithme à plusieurs étapes ne doit pas nécessairement être plus lent que le plus court, car le cycle d'instruction n'est pas fixe et de nombreux autres facteurs affectent les performances, tels que la cohérence du cache.

Pour l'algorithme Umriyaev mentionné ci-dessus, vous pouvez remplacer la division par 255 par une multiplication par 1.0/255, ce qui améliorera les performances avec une erreur un peu acceptable.

En C, vous pouvez le vectoriser pour l’améliorer encore plus. Vous pouvez également utiliser l'accélération matérielle.

En C # et Java, vous n'avez pas beaucoup d'options. Vous pouvez exécuter du code non sécurisé en C # ou, si vous utilisez Mono, vous pouvez utiliser le type de vecteur qui prend déjà en charge SSE. En Java, vous pouvez exécuter du code natif via JNI

0
phuclv