Reputation: 5348
I have some strange issue when trying to apply a conversion from HSI to RGB which I am trying to do as part of a homework assignment. To start off, here is my original image:
original image (sorry about the links, I don't have the rep to post images)
I am converting from an image with H,S,I values (0-255). Here is a display of that image in RGB colorspace (Hue=red, sat=green, inten=blue):
To me it looks about right... the white flowers (high intensity) are blue, the hues (red) seem to change with the different colored flowers.
So now I do some equalization on the intensity channel (blue in display) in some boxes, resulting in this:
HSI equalized image:
http://i.imgur.com/hgk9K.png
((you must copypasta these 'cause I don't have rep for >2 hyperlinks))
No big deal there. It doesn't look exactly right, but it's hard to say and everything outside the region-of-interest boxes is the same.
Now here comes the problem. After converting this back to RGB I get this result:
converted image:
http://i.imgur.com/6wEyw.png
No idea what the problem is here, the green looks okay, but some red/blue pixels seem to be maxed. The three boxes are there as expected, and they're contents seem pretty messed, but that's not the bigger issue here since that could be from my equalization function. Everything outside of those boxes should now be nearly identical to the original image, but somehow it has been jumbled.
I've gone over my code many times and added extra parentheses and data type casts just to be sure, but still can't find the issue. I am confident my formulas are correct, but I must be missing some problem in the way the pixel values are being calculated.
Here is the code I am using to convert from HSI to RGB. It is possible the error is outside of this method, but all the functions used here have been tested elsewhere and seem to work fine.
void colorSpace::HSItoRGB(image &src, image &tgt){
cout<<"HSI->RGB\n";
tgt.resize(src.getNumberOfRows(),src.getNumberOfColumns());
float pi = 3.14159265358979f;
for (int i=0; i<src.getNumberOfRows(); i++){ //for each pixel
for (int j=0; j<src.getNumberOfColumns(); j++){
//re-normalize h,s,i
float h = ((float)src.getPixel(i,j,H))*pi*2.0f/255.0f;//255/2 instead of 180
float s = ((float)src.getPixel(i,j,S))/255.0f;//255 instead of 100
float in= ((float)src.getPixel(i,j,I))/255.0f;
//compute x y z
float x = in*(1.0f-s);
float y = in*( 1.0f + (s*cos(h) / cos(pi/3.0f-h)) );
float z = 3.0f*in-(x+y);
float r,g,b; //set rgb
if(h<(2.0f*pi/3.0f)){
b = x;
r = y;
g = z;
}else if(h<(4.0f*pi/3.0f)){//&&2pi/3<=h
r = x;
g = y;
b = z;
}else{ //less than 2pi && 4pi/3<=h
g = x;
b = y;
r = z;
}
//convert normalized rgb to 0-255 range
int rr = (int)round(r*255.0f);
int gg = (int)round(g*255.0f);
int bb = (int)round(b*255.0f);
tgt.setPixel(i,j,RED,rr);
tgt.setPixel(i,j,GREEN,gg);
tgt.setPixel(i,j,BLUE,bb);
}
}
}
Does anybody see any trouble in the code or have any insights from looking at the images?
Upvotes: 1
Views: 1474
Reputation: 129
The basic idea here is the shift from 0 - 360 on the hue value which will result in rgb values. We also have saturation which is a value from 0.00 to 1.00 or anything in between and also the intensity which is also 0.00 to 1.00.
///I use this
// the function result will be the values of the array rgb[3] and will be the rgb values 0-255
///float H is values 0-360 because there are 360 degrees of color in hsi colorspace
///float S is 0.00 - 1.00 and aything in between
///float I is 0.00 - 1.00 and aything in between
///The input to our function is going to be hsi_to_rgb (Hue, Saturation, Intensity(brightness))
int rgb[3]; ///number of channels rgb = 3
void hsi_to_rgb(float H, float S, float I) {
int r, g, b;
if (H > 360) {
H = H - 360;
}
H = fmod(H, 360); // cycle H around to 0-360 degrees
H = 3.14159 * H / (float)180; // Convert to radians.
S = S > 0 ? (S < 1 ? S : 1) : 0; // clamp S and I to interval [0,1]
I = I > 0 ? (I < 1 ? I : 1) : 0;
if (H < 2.09439) {
r = 255 * I / 3 * (1 + S * cos(H) / cos(1.047196667 - H));
g = 255 * I / 3 * (1 + S * (1 - cos(H) / cos(1.047196667 - H)));
b = 255 * I / 3 * (1 - S);
} else if (H < 4.188787) {
H = H - 2.09439;
g = 255 * I / 3 * (1 + S * cos(H) / cos(1.047196667 - H));
b = 255 * I / 3 * (1 + S * (1 - cos(H) / cos(1.047196667 - H)));
r = 255 * I / 3 * (1 - S);
} else {
H = H - 4.188787;
b = 255 * I / 3 * (1 + S * cos(H) / cos(1.047196667 - H));
r = 255 * I / 3 * (1 + S * (1 - cos(H) / cos(1.047196667 - H)));
g = 255 * I / 3 * (1 - S);
}
//set the output to the array
rgb[0] = r;
rgb[1] = g;
rgb[2] = b;
}
Upvotes: 2
Reputation: 2622
The h values need to be adjusted for the three cases prior to calculating the cos values dependent on them. i.e.:
if(h<(2.0f*pi/3.0f)){
y = in*( 1.0f + (s*cos(h) / cos(pi/3.0f-h)) );
b = x;
r = y;
g = z;
}else if(h<(4.0f*pi/3.0f)){//&&2pi/3<=h
h -= 2*pi/3;
y = in*( 1.0f + (s*cos(h) / cos(pi/3.0f-h)) );
r = x;
g = y;
b = z;
}else{ //less than 2pi && 4pi/3<=h
h -= 4*pi/3;
y = in*( 1.0f + (s*cos(h) / cos(pi/3.0f-h)) );
g = x;
b = y;
r = z;
}
You will also need to make sure that none of the rr,gg,bb values end up outside the 0..255 interval:
if (rr < 0) rr = 0;
if (rr > 255) rr = 255;
... etc
Upvotes: 1