So what I am trying to do is make a totally new image from processed RGB pixel values. I plan to do this by using a UInt8 pointer. here is my current code:
(i took a lot of unnecesary stuff out to keep it short)
Code:
unsigned char red;
UInt8 * m_PixelBuf = (UInt8 *) CFDataGetBytePtr(m_DataRef);
red = (int)*(pixels + (y*with + x)*1); //i have a for loop that gets RGB values from each pixel in an image. this is just showing the equation/format
for (int index = 0; index < length; index += 4)
{
m_PixelBuf[index + 1] = red; //each RGB value does into one index
m_PixelBuf[index + 2] = green;
m_PixelBuf[index + 3] = blue;
}
Would this work? I tried testing it out...Doesn't seem to work. Can someone help me?
Thanks in advance
Last edited by cowgod2007; 08-18-2010 at 11:50 AM.
The weird thing is with .jpg images (which I am testing the debugger with), it never crashes. It just turns a hue of red (which its not supposed to do). However, when I run it in debugger mode, it crashes on that count4 line. This is very puzzling...
EDIT: Nvm...apparently I added a breakpoint? Now I just need to figure out why my image is turning a red-ish color instead of the modifications I made (smoothening out the image while retaining the same general colors and textures)
Last edited by cowgod2007; 08-17-2010 at 02:57 PM.
Have you tried writing this code so that it creates an exact copy of the image, rather than a modified version? That could ensure that you've got your byte ordering working correctly. Also, should you be working with the alpha channel data as well?
Have you tried writing this code so that it creates an exact copy of the image, rather than a modified version? That could ensure that you've got your byte ordering working correctly. Also, should you be working with the alpha channel data as well?
What I have been doing is taking RGB data from the original image, then creating a totally new image with the same dimensions as the original (height and width). Then, I just go row by row and insert the RGB values for each pixel. And I do not need any alpha channel data, as I am only converting RGB values to YUV values to make the image smoother.
What I have been doing is taking RGB data from the original image, then creating a totally new image with the same dimensions as the original (height and width). Then, I just go row by row and insert the RGB values for each pixel. And I do not need any alpha channel data, as I am only converting RGB values to YUV values to make the image smoother.
I can kind of gather that that's what you're doing, but you're seeing unexpected results in your "modified" image. What I am suggesting is that you remove all of the code that modifies the source pixels, and simply write unmodified data to the target image. Why? Because if you get an exact copy of the source image, then you at least know your code is putting the RGB values into the correct place in the target image. If the target image looks different from the source, then you know you're doing something wrong as you move pixels from the source to target. Perhaps something as simple as swapping R for B, etc.
I can kind of gather that that's what you're doing, but you're seeing unexpected results in your "modified" image. What I am suggesting is that you remove all of the code that modifies the source pixels, and simply write unmodified data to the target image. Why? Because if you get an exact copy of the source image, then you at least know your code is putting the RGB values into the correct place in the target image. If the target image looks different from the source, then you know you're doing something wrong as you move pixels from the source to target. Perhaps something as simple as swapping R for B, etc.
Oh...as in for testing/debugging. lol. Will try this and post results/findings.
EDIT: Just tried it. I now get a grainy (carpety look) turquise image. So obviously something is wrong with even just accessing the data. That was why I was wondering if there is any loss of data going from unsigned char to UInt8 without casting.
can anyone help? I checked all my code and loops. Nothing is wrong when I'm transferring data. Red goes to red and blue goes to blue and so forth...Its just that the resulting image is not the same thing as the original image when I just set the new values equal to the original values.
can anyone help? I checked all my code and loops. Nothing is wrong when I'm transferring data. Red goes to red and blue goes to blue and so forth...Its just that the resulting image is not the same thing as the original image when I just set the new values equal to the original values.
I don't speak for anyone else, but at this point I think we've exhausted all of the "theoretical" options. If your code isn't working correctly, the only way to determine what's happening is to look at the actual code.
Ok. here is my WHOLE method for getting an image from a UIImagePicker, getting its pixel data, then storing it, processing it (i skip this step because for now, i am just letting the processed values = to the original value like kalimba told me to do). I will try to comment it as best as i can. Please ask me if something is unclear. I have a lot of code that is used to process the image, but like kalimba told me, I am just trying to create a secondary image from the original one with same exact RGB values (which isn't working for me)
Code:
-(IBAction)getPixels{
CGDataProviderRef dataProvider = CGImageGetDataProvider(mycgImage);
CFDataRef imageData = CGDataProviderCopyData(dataProvider);
UInt8 *pixels = (UInt8 *)CFDataGetBytePtr(imageData);
unsigned char red; //from orig image
unsigned char green;
unsigned char blue;
unsigned char red2; //processed data
unsigned char green2;
unsigned char blue2;
//unsigned char alpha;
unsigned char yValue; //for YUV values
unsigned char vValue;
unsigned char uValue;
int count1=0; //counters
int count2=0;
int with = CGImageGetWidth(mycgImage); //width and height of orig image)
int hite = CGImageGetHeight(mycgImage);
//unsigned char redAround[with][hite];
unsigned char redAll[hite][with]; //matrix for storing all the RGB values of the orig image
unsigned char greenAll[hite][with];
unsigned char blueAll[hite][with];
unsigned char yAll[hite][with];
unsigned char red2All[(hite-1)*(with-1)]; //matrix for processed RGB values (NOTE I DO NOT WANT THE EDGE PIXELS)
unsigned char green2All[(hite-1)*(with-1)];
unsigned char blue2All[(hite-1)*(with-1)];
unsigned char redAround[2][2]; //to process a center pixel, I will get the 8 pixels surrounding it and average their yValues and then convert back to RGB
unsigned char greenAround[2][2];
unsigned char blueAround[2][2];
unsigned char yAround[2][2];
unsigned char yProcess[hite][with];
int averageOf9 = 0;
for(int y=0; y<hite;y++){ //for loops to go through height and width, every pixel of picture
for(int x=0; x<with;x++){
//averageOf9 = 0;
red = (int)*(pixels + (y*with + x)*1); //calculates RGB values and stores them
//NSLog(@"%i", red);
green = (int)*(pixels + (y*with + x)*2);
blue = (int)*(pixels + (y*with + x)*3);
yValue=0.299*red + 0.587*green + 0.114*blue;
uValue =(blue - yValue)*0.565;
vValue = (red-yValue)*0.713;
/* Equations I based my processing on
Y = 0.299R + 0.587G + 0.114B
U'= (B-Y)*0.565
V'= (R-Y)*0.713
*/
//NSLog(@"%i", red);
redAll[y][x]=red; //storing my data into the matrix
greenAll[y][x]=green;
blueAll[y][x]=blue;
yAll[y][x] = yValue;
/* Equations I based off of
Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
Cr = V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128
*/
}
}
//stuff to find the pixels around and average hte 9
//int count3 = (hite-1)*(with-1);
int count4=0;
for(int y=0; y<hite;y++){ //for loops to go through height and width, every pixel of picture
for(int x=0; x<with;x++){
averageOf9 = 0;
count1=0;
count2=0;
if(y!=0 && y!=hite-1 && x!=0 && x!=with-1){ //DO NOT WANT EDGE PIXELS
for(int i=y-1;i<y+1;i++){ //for loops to get the 8 surrounding pixels of middle one. Can ignore this for now
for(int z=x-1;z<x+1;z++){
redAround[count1][count2]=redAll[i][z];
greenAround[count1][count2]=greenAll[i][z];
blueAround[count1][count2]=blueAll[i][z];
yAround[count1][count2]=yAll[i][z];
//NSLog(@"i, %i, z, %i", i,z);
//NSLog(@"%i", yAll[i][z]);
//NSLog(@"%i", redAll[1][2]);
///NSLog(@"%i, count, %i, %i", redAround[count1][count2], count1,count2);
count2++;}
count2=0;
count1++;
}
//int averageOf9 = 0; //averaging of 9
for(int s=0; s<=2;s++){
for(int p = 0;p<=2;p++){
averageOf9+=yAround[s][p];
}
}
averageOf9 = averageOf9/9;
red2 = averageOf9 + 1.403 * vValue; //converting YUV values back to RGB
green2=averageOf9- 0.344 * uValue - 0.714 * vValue;
blue2 = averageOf9+ 1.770 * uValue;
red2All[count4]=red2;
green2All[count4]=green2;
blue2All[count4]=blue2;
count4++;
/*
R = Y + 1.403V'
G = Y - 0.344U' - 0.714V'
B = Y + 1.770U'
*/
//NSLog(@"%i", averageOf9);
//NSLog(@"%i, %i",count3,count4);
}
}
}
//stuff for making a completely new CGImage with processed RGB values
CGImageRef inImage = mycgImage;
CGContextRef ctx;
int count5 = 0;
CFDataRef m_DataRef;
m_DataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage));
UInt8 * m_PixelBuf = (UInt8 *) CFDataGetBytePtr(m_DataRef);
// Byte tmpByte;
int length = CFDataGetLength(m_DataRef);
for (int index = 0; index < length; index += 4)
{
//Setting the PixelBuf thing to ORIGINAL RGB values (redAll = orig, red2All = processed)
m_PixelBuf[index+1] = redAll[count5];
m_PixelBuf[index +2] = greenAll[count5];
m_PixelBuf[index + 3] = blueAll[count5];
count5++;
}
//creating new BitmapContext for second image
ctx = CGBitmapContextCreate(m_PixelBuf,
CGImageGetWidth( inImage ),
CGImageGetHeight( inImage ),
CGImageGetBitsPerComponent(inImage),
CGImageGetBytesPerRow( inImage ),
CGImageGetColorSpace( inImage ),
CGImageGetBitmapInfo(inImage) );
CGImageRef imageRef = CGBitmapContextCreateImage (ctx);
UIImage* rawImage = [UIImage imageWithCGImage:imageRef];
theimageView.image = rawImage; //setting processed image as imageview
CGContextRelease(ctx);
}
Thanks for anyone who looks at this code and thanks to kalimba.
UInt8 * m_PixelBuf = (UInt8 *) CFDataGetBytePtr(m_DataRef);
// Byte tmpByte;
int length = CFDataGetLength(m_DataRef);
for (int index = 0; index < length; index+=4)
{
m_PixelBuf[index+1] =0;//redAll[count5];
m_PixelBuf[index +2] =0;//greenAll[count5];
m_PixelBuf[index + 3] =0;// blueAll[count5];
count5++;
}
Even when I set all the values to 0, it turns a redish color. When I change the length +=4 to +=5, there are black lines. Is this even the correct way to insert pixel data into an image?
Ok. here is my WHOLE method for getting an image from a UIImagePicker, getting its pixel data, then storing it, processing it (i skip this step because for now, i am just letting the processed values = to the original value like kalimba told me to do). I will try to comment it as best as i can. Please ask me if something is unclear. I have a lot of code that is used to process the image, but like kalimba told me, I am just trying to create a secondary image from the original one with same exact RGB values (which isn't working for me)
Thanks for anyone who looks at this code and thanks to kalimba.
I didn't put your code under a microscope, but here are a couple of things that jump out at me:
Here you're retrieving the source RGB values. I'm not positive, but it appears like you're getting the G and B values incorrectly. Are you sure you shouldn't be adding the byte offset ("+1", "+2", "+3") instead of multiplying by it ("*1", "*2", "*3")?
Code:
...
red = (int)*(pixels + (y*with + x)*1); //calculates RGB values and stores them
//NSLog(@"%i", red);
green = (int)*(pixels + (y*with + x)*2);
blue = (int)*(pixels + (y*with + x)*3);
...
Here where you're trying to write the target image from your source arrays (redAll, blueAll, greenAll), you're treating a 2-dimensional array as if it's 1-dimensional. The compiler may be OK with this, and the code may actually work just fine, but it could be doing something unexpected based on how the compiler actually stores a 2-dimensional array. I'd try changing this so that you're actually using 2-dimensional array notation.
Code:
...
//Setting the PixelBuf thing to ORIGINAL RGB values (redAll = orig, red2All = processed)
m_PixelBuf[index+1] = redAll[count5];
m_PixelBuf[index +2] = greenAll[count5];
m_PixelBuf[index + 3] = blueAll[count5];
count5++;
}
...
UInt8 * m_PixelBuf = (UInt8 *) CFDataGetBytePtr(m_DataRef);
// Byte tmpByte;
int length = CFDataGetLength(m_DataRef);
for (int index = 0; index < length; index+=4)
{
m_PixelBuf[index+1] =0;//redAll[count5];
m_PixelBuf[index +2] =0;//greenAll[count5];
m_PixelBuf[index + 3] =0;// blueAll[count5];
count5++;
}
Even when I set all the values to 0, it turns a redish color. When I change the length +=4 to +=5, there are black lines. Is this even the correct way to insert pixel data into an image?
So byte ordering might be the issue. Frankly, I don't have much experience with UIKit, so I'm not sure what the actual order is. It's possible that index + 0 is R, index + 1 is G, index + 2 is B, and index + 3 is alpha.
I didn't put your code under a microscope, but here are a couple of things that jump out at me:
Here you're retrieving the source RGB values. I'm not positive, but it appears like you're getting the G and B values incorrectly. Are you sure you shouldn't be adding the byte offset ("+1", "+2", "+3") instead of multiplying by it ("*1", "*2", "*3")?
Code:
...
red = (int)*(pixels + (y*with + x)*1); //calculates RGB values and stores them
//NSLog(@"%i", red);
green = (int)*(pixels + (y*with + x)*2);
blue = (int)*(pixels + (y*with + x)*3);
...
This is what I am also confused on if its *1 or +1 or if even these are the correct equations.
This is what I am also confused on if its *1 or +1 or if even these are the correct equations.
Hmm... I was under the impression that this was either code you had written yourself, or you at least had a fair understanding of what it was doing.
That being said, I believe you want to be adding byte offsets to get the color data for the various RGB channels. The pixel color information is most likely a 32-bit value (4 consecutive bytes) with each channel of RGBA having an 8-byte chunk. The order of the individual channels I do not know, since I don't work with UIKit, etc. I suspect it is probably R in the first byte, G in the second, B in the third, A in the fourth (keep in mind that the "first byte" of a buffer is accessed by adding 0, not 1).
A quick test with an image of pure green would probably help determine the byte arrangement. The result of this test could be further verified with a tests on pure blue and pure red images.
Hmm... I was under the impression that this was either code you had written yourself, or you at least had a fair understanding of what it was doing.
That being said, I believe you want to be adding byte offsets to get the color data for the various RGB channels. The pixel color information is most likely a 32-bit value (4 consecutive bytes) with each channel of RGBA having an 8-byte chunk. The order of the individual channels I do not know, since I don't work with UIKit, etc. I suspect it is probably R in the first byte, G in the second, B in the third, A in the fourth (keep in mind that the "first byte" of a buffer is accessed by adding 0, not 1).
A quick test with an image of pure green would probably help determine the byte arrangement. The result of this test could be further verified with a tests on pure blue and pure red images.
I just totally rewrote my code. Instead of using the equations and the pointers I used in the beginning to get my RGB data, I just used my method of setting to accurately get the RGB values. And the 4th value is alpha, so it goes +0=r, +1=g, +2=b, and +3 = alpha. Thanks for the help!