GPUImage
Here at NSHipster, we’re all about diving into the darker corners of Objective-C to learn something new about the systems we interact with every day. Often, this means sifting through Apple frameworks or language features (it is, after all, a lot of what it means to work in Objective-C). However, on occasion, it’s nice to take a look to the burgeoning landscape of third-party libraries and frameworks (and there are some truly remarkable ones) for a glimpse of what’s new and great outside of Cupertino.
This week, we’ll be taking a look at one of the most impressive open source projects you’ll find: GPUImage. Buckle up, NSHipsters—if you’re not careful, you may well end up creating a camera app by the end of the article.
GPUImage is a BSD-licensed iOS library written by Brad Larson that lets you apply GPU-accelerated filters and other effects to images, live camera video, and movies.
GPU vs. CPU
Every iPhone ships with two processors: a CPU, or Central Processing Unit and a GPU, or Graphics Processing Unit. Each processor has its own strengths, and modern chip architecture (like in the iPhone’s A4) integrate the CPU and GPU onto the same physical die.
When you write C or Objective-C code in Xcode, you’re generating instructions that will be handled almost exclusively by the CPU. The GPU, by contrast, is a specialized chip that is especially well-suited for computation that can be split out into many small, independent operations, such as graphics rendering. The kinds of instructions understood by the GPU are quite different from that of the CPU, and as such, we write this code in a different language: OpenGL (or specifically, OpenGL ES on the iPhone & iPad).
Check out Jeff LaMarche’s GLProgram OpenGL ES 2.0 book for a great introduction to OpenGL ES and the rendering pipeline.
Comparing the performance of GPU-based rendering to CPU rendering for something like video, the differences are staggering:
Calculation | GPU FPS | CPU FPS | Δ |
---|---|---|---|
Thresholding ⨉ 1 | 60.00 | 4.21 | 14.3⨉ |
Thresholding ⨉ 2 | 33.63 | 2.36 | 14.3⨉ |
Thresholding ⨉ 100 | 1.45 | 0.05 | 28.7⨉ |
Oh, so it’s like Instagram?
Let me put it this way:
Instagram : GPUImage :: Disposable Camera : NASA Space Optics Manufacturing Center
To put it another way, within GPUImage’s APIs lay thousands of camera apps, just waiting for the right combination of filters and a little spark of imagination.
Here’s a table of the 125 (!) filters that come with GPUImage:
Color Adjustments | Image Processing | Blending Modes | Visual Effects |
---|---|---|---|
|
|
|
|
Seriously, the Filter Showcase Example App that comes bundled in the repository could easily retail on the AppStore for $3.99, as-is. Add Twitter integration and a few sound effects, and you could bump that up to a respectable$6.99.
Rendering Pipeline
GPUImage is, at its core, an Objective-C abstraction around a rendering pipeline. Source images from the camera, network, or disk are loaded and manipulated according to a chain of filters, and finally outputted either a view, graphics context, or data stream.
For example, images from the video camera could have a Color Levels filter applied to simulate different types of color blindness and displayed in a live view.
GPUImage Video Camera *video Camera = [[GPUImage Video Camera alloc]
init With Session Preset:AVCapture Session Preset640x480
camera Position:AVCapture Device Position Back];
video Camera.output Image Orientation = UIInterface Orientation Portrait;
GPUImage Filter *filter = [[GPUImage Levels Filter alloc] init With Fragment Shader From File:@"Custom Shader"];
[filter set Red Min:0.299 gamma:1.0 max:1.0 min Out:0.0 max Out:1.0];
[filter set Green Min:0.587 gamma:1.0 max:1.0 min Out:0.0 max Out:1.0];
[filter set Blue Min:0.114 gamma:1.0 max:1.0 min Out:0.0 max Out:1.0];
[video Camera add Target:filter];
GPUImage View *filtered Video View = [[GPUImage View alloc] init With Frame:self.view.bounds];
[filter add Target:filtered Video View];
[self.view add Subview:filtered Video View];
[video Camera start Camera Capture];
Or, combining various color blending modes, image effects, and adjustments, you could transform still images into something worthy of sharing with your hipster friends (example taken from FilterKit, which is built on GPUImage):
GPUImage Filter Group *filter = [[GPUImage Filter Group alloc] init];
GPUImage Saturation Filter *saturation Filter = [[GPUImage Saturation Filter alloc] init];
[saturation Filter set Saturation:0.5];
GPUImage Monochrome Filter *monochrome Filter = [[GPUImage Monochrome Filter alloc] init];
[monochrome Filter set Color:(GPUVector4){0.0f, 0.0f, 1.0f, 1.0f}];
[monochrome Filter set Intensity:0.2];
GPUImage Vignette Filter *vignette Filter = [[GPUImage Vignette Filter alloc] init];
[vignette Filter set Vignette End:0.7];
GPUImage Exposure Filter *exposure Filter = [[GPUImage Exposure Filter alloc] init];
[exposure Filter set Exposure:0.3];
[filter add GPUFilter:exposure Filter];
[filter add GPUFilter:monochrome Filter];
[filter add GPUFilter:saturation Filter];
[filter add GPUFilter:vignette Filter];
Looking through all of what GPUImage can do, one can’t help but get excited. Easy enough to get started immediately (without needing to know anything about OpenGL) yet performant enough to power whatever you dream up. And not just that, but it also comes with a dizzying number of building blocks—all of the color adjustments, blending modes, and visual effects you could ever want (or never knew you needed).
GPUImage is a rare treat for the open source community, and we as Mac & iOS developers are lucky to have it at our disposal. Use it to make something great, and show others the world in a whole new way.