File: fasthue.txt
Name: Quick hue Color Ring Calculation
Author: zyl910
Blog: http://blog.csdn.net/zyl910/
Version: v1.00
Updata: 2006-11-3
Download (note the modified extension)
1. HSV Color Space
H: hue ). Value Range: [0,360)
0 degrees: Red, RGB :( 255, 0, 0), 255: R, 0: B, G +
60 degrees: yellow, RGB: (255,255, 0), 255: G, 0: B, R-
120 degrees: Green, RGB :( 0,255, 0), 255: G, 0: R, B +
180 degrees: cyan, RGB :( 0,255,255), 255: B, 0: R, G-
240 degrees: blue, RGB :( 0, 0,255), 255: B, 0: G, R +
300 degrees: Purple, RGB :( 255, 0,255), 255: R, 0: G, B-
360 degrees: Red, RGB :( 255, 0, 0), 255: R, 0: B, G +
Colors between these standard color values are obtained through linear interpolation. For example, if the color is 30 degrees orange, it is the color between 0 degrees red and 60 degrees yellow, so its RGB value is (255, 0, 0) * 50% + (255,255, 0) * 50% = (255,127.5, 0 ).
Because the color values in the same 60-degree interval have only one component, you only need to perform linear interpolation for one component.
S: saturation ). Value Range: [0%, 100%]. Is the ratio of the color to the white mixture represented by H.
Assume that the H component of a color is 30, the S component is 80% (and the V component is 100%), and its RGB value is (255,127.5, 0) * 80% + (255,255,255) * 20% = (255,153, 51)
V: brightness (value or brightness, so it is also called HSB ). Value Range: [0%, 100%]. It is the ratio of the mixed color and black represented by H and S.
Assume that the H component of a color is 30, the S component is 80%, and the V component is 60%. Its RGB value is (255,153, 51) * 60% + (, 0) * 40% = (255,153, 51) * 60% = (153, 91.8, 30.6)
That is to say, the calculation step is: first calculate the solid color value based on h, then mix the result with white according to S, and then mix the result with black according to v.
Ii. Quick hue Color Ring Calculation
2.1 Analysis [) Interval
Let's first observe the color value in the [) range:
0: r = 255, B = 0, G = 0*255/60 = 0/60 = 0 + 0/60
1: r = 255, B = 0, G = 1*255/60 = 255/60 = 4 + 15/60
2: r = 255, B = 0, G = 2*255/60 = 510/60 = 8 + 30/60
3: r = 255, B = 0, G = 3*255/60 = 765/60 = 12 + 45/60
4: r = 255, B = 0, G = 4*255/60 = 1020/60 = 17 + 0/60
...
56: r = 255, B = 0, G = 56*255/60 = 14280/60 = 238 + 0/60
57: r = 255, B = 0, G = 57*255/60 = 14535/60 = 242 + 15/60
58: r = 255, B = 0, G = 58*255/60 = 14790/60 = 246 + 30/60
59: r = 255, B = 0, G = 59*255/60 = 15045/60 = 250 + 45/60
60: r = 255, B = 0, G = 60*255/60 = 15300/60 = 255 + 0/60
The maximum value of RGB is 255 and the interval is 60. Therefore, the formula is G = I * 255/60.
The final result is written in the fractional form, because this form is easier to understand-the integer part is the RGB value. As for the score, you can use rounding, but I personally think it is more average to not perform rounding.
It can be seen that, due to linear interpolation, the next one is 255/60 (or 4 + 15/60) more than the previous one ). When the value reaches 60, the integer part is 255, and the score part is 0.
So we get this algorithm:
Integer = 0
Score part = 0
While (integer part <255 ){
Draw pixels (RGB (255, integer, 0 ))
Integer + = 4 // 255/60 = 4 + 15/60
Score + = 15
If (score part> = 60 ){
Score part-= 60
Integer +
}
}
Is it a bit like the bresenham algorithm. I realized that I started to understand rational numbers only when I understood the bresenham algorithm. Rational numbers are the ratios of two numbers (numerator and denominator). It is the easiest to understand them in the form of false scores or scores. the commonly used decimal Writing Method in life may block the thinking.
2.2 analysis [60,120) Interval
The G component of the previous [60,120) interval is increasing. What should I do if the r component of the [) interval is reduced?
Let's observe:
60: g = 255, B = 0, r = 255-(60-60) * 255/60 = 255-0*255/60 = 255-0/60 = 255-(0 + 0/60)
61: g = 255, B = 0, r = 255-(61-60) * 255/60 = 255-1*255/60 = 255-255/60 = 255-(4 + 15/60)
62: g = 255, B = 0, r = 255-(62-60) * 255/60 = 255-2*255/60 = 255-510/60 = 255-(8 + 30/60)
63: g = 255, B = 0, r = 255-(63-60) * 255/60 = 255-3*255/60 = 255-765/60 = 255-(12 + 45/60)
64: g = 255, B = 0, r = 255-(64-60) * 255/60 = 255-4*255/60 = 255-1020/60 = 255-(17 + 0/60)
...
116: g = 255, B = 0, r = 255-(116-60) * 255/60 = 255-56*255/60 = 255-14280/60 = 255-(238 + 0/60)
117: g = 255, B = 0, r = 255-(117-60) * 255/60 = 255-57*255/60 = 255-14535/60 = 255-(242 + 15/60)
118: g = 255, B = 0, r = 255-(118-60) * 255/60 = 255-58*255/60 = 255-14790/60 = 255-(246 + 30/60)
119: g = 255, B = 0, r = 255-(119-60) * 255/60 = 255-59*255/60 = 255-15045/60 = 255-(250 + 45/60)
120: g = 255, B = 0, r = 255-(120-60) * 255/60 = 255-60*255/60 = 255-15300/60 = 255-(255 + 0/60)
Since it is now in the [60,120) interval and is now reduced, so the formula is: r = (I-60) * 255/60 = (120-I) * 255/60
It can be seen that the method for calculating the score is the same, but the r component is "255-with score" when being drawn.
2.3 Algorithm for Processing Arbitrary width
We have analyzed the hue color rings in the [60,120) and [) intervals. For other intervals, the method for calculating the color value is the same, except that the filled RGB component is different. Therefore, we should consider writing a complete method for calculating the hue color ring.
If we simply generate an hue color ring with a width of 360, we don't need to write a program. We just need to use an array with 360 elements to look up the table, so we need an algorithm that can process any width. Because the Color Ring Width you enter is not necessarily a multiple of 6, the length of each interval is not an integer.
First, let's look back at the [255) interval and say, "the formula is G = I * 255/60 because the maximum value of the RGB component is and the size of the interval is 60 ". If we increase these two coefficients by 6 times at the same time, then the formula becomes "G = I * (255*6)/360 ". According to the proportional nature, the result is the same as the original formula. Therefore, the formula for any width is: g = I * (255*6)/huesize.
Then we will consider how to design functions. Because windows is very popular, I want the program to directly output the Dib (device-independent Bitmap) bitmap data in real color. To adapt to different situations (24-bit or 32-bit), I also provided the cbpixel parameter to know that each pixel occupies a byte.
The final code is:
// Calculate the hue Color Ring
// Return: the return value is not 0. If the return value is successful, the return value is 0.
// ARGs:
// Lpbuf: Real-color DIB bitmap data buffer
// Cbpixel: bytes occupied by one pixel
// Huesize: the width of the hue Color Ring
Bool makehue (lpvoid lpbuf, int cbpixel, int huesize)
{
Int value, fract; // (255*6)/huesize integer part and score part
Int I, ifract; // Current Value
Lpbyte PBY = (lpbyte) lpbuf;
ASSERT(lpBuf != 0);
ASSERT(huesize > 0);
// (255*6)/huesize integer part and score part
Value = (255*6)/huesize;
Fract = (255*6) % huesize;
I = ifract = 0;
// red ~ yellow: [0, 60)
while(i < 255) {
// Draw
pby[2] = 0xff;
pby[1] = i;
pby[0] = 0x00;
pby += cbPixel;
// Next
i += value;
ifract += fract;
if (ifract >= huesize)
{
ifract -= huesize;
i++;
}
};
i -= 255;
// yellow ~ green: [60, 120)
while(i < 255) {
// Draw
pby[2] = 0xff - i;
pby[1] = 0xff;
pby[0] = 0x00;
pby += cbPixel;
// Next
i += value;
ifract += fract;
if (ifract >= huesize)
{
ifract -= huesize;
i++;
}
};
i -= 255;
// green ~ cyan: [120, 180)
while(i < 255) {
// Draw
pby[2] = 0x00;
pby[1] = 0xff;
pby[0] = i;
pby += cbPixel;
// Next
i += value;
ifract += fract;
if (ifract >= huesize)
{
ifract -= huesize;
i++;
}
};
i -= 255;
// cyan ~ blue: [180, 240)
while(i < 255) {
// Draw
pby[2] = 0x00;
pby[1] = 0xff - i;
pby[0] = 0xff;
pby += cbPixel;
// Next
i += value;
ifract += fract;
if (ifract >= huesize)
{
ifract -= huesize;
i++;
}
};
i -= 255;
// blue ~ magenta: [240, 300)
while(i < 255) {
// Draw
pby[2] = i;
pby[1] = 0x00;
pby[0] = 0xff;
pby += cbPixel;
// Next
i += value;
ifract += fract;
if (ifract >= huesize)
{
ifract -= huesize;
i++;
}
};
i -= 255;
// magenta ~ red: [300, 360)
while(i < 255) {
// Draw
pby[2] = 0xff;
pby[1] = 0x00;
pby[0] = 0xff - i;
pby += cbPixel;
// Next
i += value;
ifract += fract;
if (ifract >= huesize)
{
ifract -= huesize;
i++;
}
};
//i -= 255;
return FALSE;
}
I admit that this code is not concise enough, because the method for calculating I is the same, but the code for drawing RGB values is different, so the differences can be completely solved through the lookup table. However, doing so is not conducive to compilation optimization (the index is dynamic) and affects the speed.
3. quickly generate the hue color ring under the specified saturation and brightness
Since saturation and brightness are specified, the final color value needs to be calculated based on S and V.
Note that each RGB component is calculated separately, that is, each component is transformed as follows:
F (x) = (x * s + 255 * (1-s) * V
= (255 + (x-255) * s) * V
= (255-(255-x) * s) * V
Because floating point operations are slow, we need an integer algorithm. Windows is a 32-bit operating system, so the integer is 32-bit. The RGB component is 8 bits (32-8)/2 = 24/2 = 12, so s and V can have 12 bits:
Is = (DWORD) (S * 1 <12)
IV = (DWORD) (V * 1 <12)
F (x) = (255-(255-x) * Is/(1 <12) * IV/(1 <12)
= (255 <12-(255-x) * Is)/(1 <12) * IV/(1 <12)
= (255 <12-(255-x) * Is) * IV/(1 <24)
= (255 <12-(255-x) * Is) * iv)> 24
Because the value range of the RGB component is [0,255], we can optimize the table.
Final code:
// Hue Color Ring for calculating the specified saturation and brightness
// Return: the return value is not 0. If the return value is successful, the return value is 0.
// ARGs:
// Lpbuf: Real-color DIB bitmap data buffer
// Cbpixel: bytes occupied by one pixel
// Huesize: the width of the hue Color Ring
// FS: saturation, [0, 1]. Saturation processing of Values
// FV: brightness, [0, 1]. Saturation processing of Values
Bool makehueex (lpvoid lpbuf, int cbpixel, int huesize, float FS, float FV)
{
Byte TBL [0x100]; // color value ing table
DWORD is, IV; // 12-bit precision saturation and brightness
Int value, fract; // (255*6)/huesize integer part and score part
Int I, ifract; // Current Value
Lpbyte PBY = (lpbyte) lpbuf;
ASSERT(lpBuf != 0);
ASSERT(huesize >= 6);
// 12-bit precision saturation and brightness
If (FS <0) FS = 0;
Else if (FS> 1) FS = 1;
If (FV <0) FV = 0;
Else if (FV> 1) FV = 1;
Is = (DWORD) (FS * (1 <12 ));
IV = (DWORD) (FV * (1 <12 ));
// Brightness 0 -- black
If (IV = 0)
{
While (huesize> 0)
{
PBY [2] = 0;
PBY [1] = 0;
PBY [0] = 0;
PBY + = cbpixel;
Huesize --;
}
Return true;
}
// Calculate the color value ing table
For (I = 0; I <= 0xff; I ++)
{
TBL [I] = (byte) (255 <12)-(255-i) * Is) * iv + (1 <23)> 24 ); // "+ 1 <23" is for rounding
}
// (255*6)/huesize integer part and score part
Value = (255*6)/huesize;
Fract = (255*6) % huesize;
I = ifract = 0;
// red ~ yellow: [0, 60)
do{
// Draw
pby[2] = tbl[0xff];
pby[1] = tbl[i];
pby[0] = tbl[0x00];
pby += cbPixel;
// Next
i += value;
ifract += fract;
if (ifract >= huesize)
{
ifract -= huesize;
i++;
}
}while(i < 255);
i -= 255;
// yellow ~ green: [60, 120)
do{
// Draw
pby[2] = tbl[0xff - i];
pby[1] = tbl[0xff];
pby[0] = tbl[0x00];
pby += cbPixel;
// Next
i += value;
ifract += fract;
if (ifract >= huesize)
{
ifract -= huesize;
i++;
}
}while(i < 255);
i -= 255;
// green ~ cyan: [120, 180)
do{
// Draw
pby[2] = tbl[0x00];
pby[1] = tbl[0xff];
pby[0] = tbl[i];
pby += cbPixel;
// Next
i += value;
ifract += fract;
if (ifract >= huesize)
{
ifract -= huesize;
i++;
}
}while(i < 255);
i -= 255;
// cyan ~ blue: [180, 240)
do{
// Draw
pby[2] = tbl[0x00];
pby[1] = tbl[0xff - i];
pby[0] = tbl[0xff];
pby += cbPixel;
// Next
i += value;
ifract += fract;
if (ifract >= huesize)
{
ifract -= huesize;
i++;
}
}while(i < 255);
i -= 255;
// blue ~ magenta: [240, 300)
do{
// Draw
pby[2] = tbl[i];
pby[1] = tbl[0x00];
pby[0] = tbl[0xff];
pby += cbPixel;
// Next
i += value;
ifract += fract;
if (ifract >= huesize)
{
ifract -= huesize;
i++;
}
}while(i < 255);
i -= 255;
// magenta ~ red: [300, 360)
do{
// Draw
pby[2] = tbl[0xff];
pby[1] = tbl[0x00];
pby[0] = tbl[0xff - i];
pby += cbPixel;
// Next
i += value;
ifract += fract;
if (ifract >= huesize)
{
ifract -= huesize;
i++;
}
}while(i < 255);
i -= 255;
return FALSE;
}