How to implement a box or gaussian blur on iOS
I found a really fast pretty crappy way for iOS3.2+ apps
UIView *myView = [self view]; CALayer *layer = [myView layer]; [layer setRasterizationScale:0.25]; [layer setShouldRasterize:YES];
This rasterizes the view down to 4x4 pixel chunks then scales it back up using bilinear filtering... it's EXTREMELY fast and looks ok if you are just wanting to blur a background view under a modal view.
To undo it, just set the rasterization scale back to 1.0 or turn off rasterization.
From how-do-i-create-blurred-text-in-an-iphone-view:
Take a look at Apple's GLImageProcessing iPhone sample. It does some blurring, among other things.
The relevant code includes:
static void blur(V2fT2f *quad, float t) // t = 1{ GLint tex; V2fT2f tmpquad[4]; float offw = t / Input.wide; float offh = t / Input.high; int i; glGetIntegerv(GL_TEXTURE_BINDING_2D, &tex); // Three pass small blur, using rotated pattern to sample 17 texels: // // .\/.. // ./\\/ // \/X/\ rotated samples filter across texel corners // /\\/. // ../\. // Pass one: center nearest sample glVertexPointer (2, GL_FLOAT, sizeof(V2fT2f), &quad[0].x); glTexCoordPointer(2, GL_FLOAT, sizeof(V2fT2f), &quad[0].s); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor4f(1.0/5, 1.0/5, 1.0/5, 1.0); validateTexEnv(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // Pass two: accumulate two rotated linear samples glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); for (i = 0; i < 4; i++) { tmpquad[i].x = quad[i].s + 1.5 * offw; tmpquad[i].y = quad[i].t + 0.5 * offh; tmpquad[i].s = quad[i].s - 1.5 * offw; tmpquad[i].t = quad[i].t - 0.5 * offh; } glTexCoordPointer(2, GL_FLOAT, sizeof(V2fT2f), &tmpquad[0].x); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glActiveTexture(GL_TEXTURE1); glEnable(GL_TEXTURE_2D); glClientActiveTexture(GL_TEXTURE1); glTexCoordPointer(2, GL_FLOAT, sizeof(V2fT2f), &tmpquad[0].s); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glBindTexture(GL_TEXTURE_2D, tex); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_PRIMARY_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR); glColor4f(0.5, 0.5, 0.5, 2.0/5); validateTexEnv(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // Pass three: accumulate two rotated linear samples for (i = 0; i < 4; i++) { tmpquad[i].x = quad[i].s - 0.5 * offw; tmpquad[i].y = quad[i].t + 1.5 * offh; tmpquad[i].s = quad[i].s + 0.5 * offw; tmpquad[i].t = quad[i].t - 1.5 * offh; } glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // Restore state glDisableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, Half.texID); glDisable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA); glActiveTexture(GL_TEXTURE0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glDisable(GL_BLEND);}
If you always or at least often use the same blur settings you might gain speed by doing the filtering in frequency domain instead of the spatial domain.
- Precaclulate your filter image G(u,v), which is a 2D gaussian
- Apply fourier transform to your input image f(x,y)->F(u,v)
- Filter by multiplication: H(u,v) = F(u,v) .* G(u,v) (pixelwise multiplication, not matrix multiplication)
- Transform your filtered image back into the spatial domain by inverse fourier transform: H(u,v) -> h(x,y)
The pros of this approach is that pixel-wise multiplication should be pretty fast compared to averaging a neighborhood. So if you process a lot of images this might help.
The downside is that I have no idea how fast you can do fourier transforms on the iPhone so this might very well be much slower than other implementations.
Other than that I guess since the iPhone has OpenGL support you could maybe use its texturing functions/drawing to do it. Sorry to say though that I am no OpenGL expert and can't really give any practical advice as how that is done.