Image Processing in iOS Part 1: Raw Bitmap Modification
Learn the basics of image processing on iOS via raw bitmap modification, Core Graphics, Core Image, and GPUImage in this 2-part tutorial series. By Jack Wu.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Image Processing in iOS Part 1: Raw Bitmap Modification
25 mins
Black and White
One last effect to go. Try implementing the black and white filter yourself. To do this, set each pixel's red, green and blue components to the average of the three channels in the original, just like how you printed out Ghosty's brightness in the beginning.
Write this code before the // Create a new UIImage
comment you added in the previous step.
Think you got it? Check your code here.
[spoiler title="Solution"]
// Convert the image to black and white
for (NSUInteger j = 0; j < inputHeight; j++) {
for (NSUInteger i = 0; i < inputWidth; i++) {
UInt32 * currentPixel = inputPixels + (j * inputWidth) + i;
UInt32 color = *currentPixel;
// Average of RGB = greyscale
UInt32 averageColor = (R(color) + G(color) + B(color)) / 3.0;
*currentPixel = RGBAMake(averageColor, averageColor, averageColor, A(color));
}
}
[/spoiler]
The very last step is to cleanup your memory. ARC cannot manage CGImageRefs
and CGContexts
for you. Add this to the end of the function before the return
statement:
// Cleanup!
CGColorSpaceRelease(colorSpace);
CGContextRelease(context);
CGContextRelease(ghostContext);
free(inputPixels);
free(ghostPixels);
Build and run. Be prepared to be spooked out by the result:
Where To Go From Here?
Congratulations! You just finished your first image-processing application. You can download a working version of the project at this point here.
That wasn't too hard, right? You can play around with the code inside the for
loops to create your own effects, try to see if you can implement these ones:
- Swap the red and blue channels of the image
- Increase the brightness of the image by 10%
- As a further challenge, try scaling Ghosty using only pixel-based methods. Here are the steps:
- Create a new CGContext with the target size for Ghosty.
- For each pixel in this new Context, calculate which pixel you should copy from in the original image.
- For extra coolness, try interpolating between nearby pixels if your calculations for the original coordinate lands in-between pixels. If you interpolate between the four nearest pixels, you have just implemented Bilinear scaling all on your own! What a boss!
- Create a new CGContext with the target size for Ghosty.
- For each pixel in this new Context, calculate which pixel you should copy from in the original image.
- For extra coolness, try interpolating between nearby pixels if your calculations for the original coordinate lands in-between pixels. If you interpolate between the four nearest pixels, you have just implemented Bilinear scaling all on your own! What a boss!
If you've completed the first project, you should have a pretty good grasp on the basic concepts of image processing. Now you can set out and explore simpler and faster ways to accomplish these same effects.
In the next part of the series, you replace -processUsingPixels:
with three new functions that will perform the same task using different libraries. Definitely check it out!
In the meantime, if you have any questions or comments about the series so far, please join the forum discussion below!