Fastest formula to get Hue from RGB

匿名 (未验证) 提交于 2019-12-03 02:46:02

问题:

If you are given red, green, and blue values that range from 0-255, what would be the fastest computation to get just the hue value? This formula will be used on every pixel of a 640x480 image at 30fps (9.2 million times a second) so every little bit of speed optimization helps.

I've seen other formulas but I'm not happy with how many steps they involve. I'm looking for an actual formula, not a built in library function.

回答1:

  1. Convert the RGB values to the range 0-1, this can be done by dividing the value by 255 for 8-bit color depth (r,g,b - are given values):

     R = r / 255 = 0.09 G = g / 255 = 0.38 B = b / 255 = 0.46
  2. Find the minimum and maximum values of R, G and B.

  3. Depending on what RGB color channel is the max value. The three different formulas are: 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)

The Hue value you get needs to be multiplied by 60 to convert it to degrees on the color circle. If Hue becomes negative you need to add 360 to, because a circle has 360 degrees.

Here is full article.



回答2:

In addition to Umriyaev's answer:

If only the hue is needed, it is not required to divide the 0-255 ranged colours with 255.

The result of e.x. (green - blue) / (max - min) will be the same for any range (as long as the colours are in the same range of course).

Here is the java example to get the Hue:

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: added check if min and max are the same, since the rest of the calculation is not needed in this case, and to avoid division by 0 (see comments)



回答3:

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


回答4:

You must specify which language you need. C#, Java and C are very different languages and may runs on different platforms

640x480 is not very large compared to current common resolutions. You must try all the possible solutions and benchmark. An algorithm that has many steps doesn't necessarily slower than a shorter one because instruction cycle are not fixed and there are many other factors that affect performance such as cache coherency.

For the algorithm Umriyaev mentioned above, you can replace the division by 255 with a multiplication by 1.0/255, that'll improve performance with a bit acceptable error.

In C you can do vectorize it to improve it even more. You can also use hardware acceleration.

In C# and Java you don't have many options. You can run unsafe code in C#, or if you're using Mono you can use the vector type that has already support for SSE. In Java you can run native code through JNI



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!