22

According to the documentation it should support blurring, note the "Available in iOS 5.0 and later":

CIFilter Class Reference

But according to the device, it doesn't:

[CIFilter filterNamesInCategory:kCICategoryBlur];

returns nothing.

According to the following only these filters are available on my iPhone and Simulator (which are both running 5.0):

[CIFilter filterNamesInCategory:kCICategoryBuiltIn]

CIAdditionCompositing,
CIAffineTransform,
CICheckerboardGenerator,
CIColorBlendMode,
CIColorBurnBlendMode,
CIColorControls,
CIColorCube,
CIColorDodgeBlendMode,
CIColorInvert,
CIColorMatrix,
CIColorMonochrome,
CIConstantColorGenerator,
CICrop,
CIDarkenBlendMode,
CIDifferenceBlendMode,
CIExclusionBlendMode,
CIExposureAdjust,
CIFalseColor,
CIGammaAdjust,
CIGaussianGradient,
CIHardLightBlendMode,
CIHighlightShadowAdjust,
CIHueAdjust,
CIHueBlendMode,
CILightenBlendMode,
CILinearGradient,
CILuminosityBlendMode,
CIMaximumCompositing,
CIMinimumCompositing,
CIMultiplyBlendMode,
CIMultiplyCompositing,
CIOverlayBlendMode,
CIRadialGradient,
CISaturationBlendMode,
CIScreenBlendMode,
CISepiaTone,
CISoftLightBlendMode,
CISourceAtopCompositing,
CISourceInCompositing,
CISourceOutCompositing,
CISourceOverCompositing,
CIStraightenFilter,
CIStripesGenerator,
CITemperatureAndTint,
CIToneCurve,
CIVibrance,
CIVignette,
CIWhitePointAdjust
lms
  • 14,269
  • 12
  • 64
  • 113
  • 2
    The documentation says that the `kCICategoryBlur` constant is available, which it is. You used it successfully in `[CIFilter filterNamesInCategory:kCICategoryBlur];`. Which told you there were no blur filters available at that time. – idz May 24 '13 at 09:14
  • 1
    @idz That made me laugh, thanks! – lms May 24 '13 at 09:56

8 Answers8

31

While Core Image on iOS 5.0 lacks blur filters, there is still a way to get GPU-accelerated blurs of images and video. My open source GPUImage framework has multiple blur types, including Gaussian (using the GPUImageGaussianBlurFilter for a general Gaussian or the GPUImageFastBlurFilter for a hardware-optimized 9-hit Gaussian), box (using a GPUImageBoxBlurFilter), median (using a GPUImageMedianFilter), and a bilateral blur (using a GPUImageBilateralBlurFilter).

I describe the shaders used to pull off the hardware-optimized Gaussian blur in this answer, and you can examine the code I use for the rest within the framework. These filters run tens of times faster than any CPU-bound routine I've tried yet.

I've also incorporated these blurs into multi-stage processing effects, like unsharp masking, tilt-shift filtering, Canny edge detection, and Harris corner detection, all of which are available as filters within this framework.

Community
  • 1
  • 1
Brad Larson
  • 168,330
  • 45
  • 388
  • 563
25

Again, in an attempt to save all iOS blur isses, here is my contribution:

https://github.com/tomsoft1/StackBluriOS

A simple blur library based on Stack Blur. Stack Blur is very similar to Gaussian Blur, but much faster (see http://incubator.quasimondo.com/processing/fast_blur_deluxe.php )

use it like this:

UIImage *newIma=[sourceIma stackBlur:radius]

Hope this help

tomsoft
  • 4,100
  • 5
  • 25
  • 32
  • I've implemented my own and the app is already out on the app store, but I will keep that in mind for future reference. Thanks for the tip! – lms Feb 07 '12 at 14:05
  • The StackBlur iOS rotates the image 90 degrees. I think it should be fixed – ppaulojr Jun 25 '12 at 20:13
  • @ppaulojr are you sure of the rotation issue? It should keep all other parameters identicals. If you still have the problem, please provide a sample image which have the problem with the test code – tomsoft Jul 06 '12 at 07:02
  • iOS 6.0 :- `m_PixelBuf[offset]=dv[rsum];` gives `EXC_BAD_ACCESS`(code=2, addres=******` – thesummersign Oct 11 '12 at 04:53
  • It seems the library has some issue with odd sizes – Vinzius May 14 '13 at 09:41
  • My bad, it's not a problem about the size. I'm investigating but there is an issue with some sizes and so the blur deform the image too. I'll debug the lib but this may be related to the warnings during the "analyse" process on Xcode on the lib. – Vinzius May 16 '13 at 08:41
24

I too was disappointed to find that Core Image in iOS doesn't support blurs. Here's the function I wrote to do a 9-tap Gaussian blur on a UIImage. Call it repeatedly to get stronger blurs.

@interface UIImage (ImageBlur)
- (UIImage *)imageWithGaussianBlur9;
@end

@implementation UIImage (ImageBlur)
- (UIImage *)imageWithGaussianBlur9 {
    float weight[5] = {0.2270270270, 0.1945945946, 0.1216216216, 0.0540540541, 0.0162162162};
    // Blur horizontally
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height) blendMode:kCGBlendModePlusLighter alpha:weight[0]];
    for (int x = 1; x < 5; ++x) {
        [self drawInRect:CGRectMake(x, 0, self.size.width, self.size.height) blendMode:kCGBlendModePlusLighter alpha:weight[x]];
        [self drawInRect:CGRectMake(-x, 0, self.size.width, self.size.height) blendMode:kCGBlendModePlusLighter alpha:weight[x]];
    }
    UIImage *horizBlurredImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    // Blur vertically
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    [horizBlurredImage drawInRect:CGRectMake(0, 0, self.size.width, self.size.height) blendMode:kCGBlendModePlusLighter alpha:weight[0]];
    for (int y = 1; y < 5; ++y) {
        [horizBlurredImage drawInRect:CGRectMake(0, y, self.size.width, self.size.height) blendMode:kCGBlendModePlusLighter alpha:weight[y]];
        [horizBlurredImage drawInRect:CGRectMake(0, -y, self.size.width, self.size.height) blendMode:kCGBlendModePlusLighter alpha:weight[y]];
    }
    UIImage *blurredImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    //
    return blurredImage;
}

Just call it on an existing image like this:

UIImage *blurredImage = [originalImage imageWithGaussianBlur9];

and repeat it to get stronger blurring, like this:

blurredImage = [blurredImage imageWithGaussianBlur9];
John Stephen
  • 7,300
  • 2
  • 28
  • 41
5

Unfortunately, it does not support any blurs. For that, you'll have to roll your own.

akaru
  • 6,021
  • 8
  • 58
  • 99
4

UPDATE: As of iOS 6 [CIFilter filterNamesInCategory:kCICategoryBlur]; returns CIGaussianBlur meaning that this filter is available on the device. Even though this is true, you (probably) will get better performance and more flexibility using GPUImage.

idz
  • 11,341
  • 1
  • 26
  • 37
  • I have found CIFilter blur to be very unstable. Occasionally, it causes an extremely weird crash on my iPad that locks the screen, but I can tell the iPad is still functional because I can hear sound when it responds to touches. I have to hard-reset to fix it. Anyway, the drop-in replacement by John Stephan above was a great solution. – Shaun Budhram Jul 30 '14 at 08:06
1

Here is the link to our tutorial on making blur effect in iOS application with different approaches. http://blog.denivip.ru/index.php/2013/01/blur-effect-in-ios-applications/?lang=en

Denis
  • 11
  • 1
0

If you can use OpenGL ES in your iOS app, this is how you calculate the median in a pixel neighborhood radius of your choosing (the median being a type of blur, of course):

kernel vec4 medianUnsharpKernel(sampler u) {
vec4 pixel = unpremultiply(sample(u, samplerCoord(u)));
vec2 xy = destCoord();
int radius = 3;
int bounds = (radius - 1) / 2;
vec4 sum  = vec4(0.0);
for (int i = (0 - bounds); i <= bounds; i++)
{
    for (int j = (0 - bounds); j <= bounds; j++ )
    {
        sum += unpremultiply(sample(u, samplerTransform(u, vec2(xy + vec2(i, j)))));
    }
}
vec4 mean = vec4(sum / vec4(pow(float(radius), 2.0)));
float mean_avg = float(mean);
float comp_avg = 0.0;
vec4 comp  = vec4(0.0);
vec4 median  = mean;
for (int i = (0 - bounds); i <= bounds; i++)
{
    for (int j = (0 - bounds); j <= bounds; j++ )
    {
        comp = unpremultiply(sample(u, samplerTransform(u, vec2(xy + vec2(i, j)))));
        comp_avg = float(comp);
        median = (comp_avg < mean_avg) ? max(median, comp) : median;
    }
}

return premultiply(vec4(vec3(abs(pixel.rgb - median.rgb)), 1.0)); 
}

A brief description of the steps 1. Calculate the mean of the values of the pixels surrounding the source pixel in a 3x3 neighborhood; 2. Find the maximum pixel value of all pixels in the same neighborhood that are less than the mean. 3. [OPTIONAL] Subtract the median pixel value from the source pixel value for edge detection.

If you're using the median value for edge detection, there are a couple of ways to modify the above code for better results, namely, hybrid median filtering and truncated media filtering (a substitute and a better 'mode' filtering). If you're interested, please ask.

James Bush
  • 1,347
  • 11
  • 17
0

Because I'm using Xamarin, I converted John Stephen's answer to C#:

    private UIImage ImageWithGaussianBlur9(UIImage image)
    {
        var weight = new nfloat[]
        {
            0.2270270270f, 0.1945945946f, 0.1216216216f, 0.0540540541f, 0.0162162162f
        };

        var width = image.Size.Width;
        var height = image.Size.Height;
        // Blur horizontally
        UIGraphics.BeginImageContextWithOptions(image.Size, false, 1f);

        image.Draw(new CGRect(0f, 0f, width, height), CGBlendMode.PlusLighter, weight[0]);

        for (int x = 1; x < 5; ++x)
        {
            image.Draw(new CGRect(x, 0, width, height), CGBlendMode.PlusLighter, weight[x]);
            image.Draw(new CGRect(-x, 0, width, height), CGBlendMode.PlusLighter, weight[x]);
        }

        var horizBlurredImage = UIGraphics.GetImageFromCurrentImageContext();
        UIGraphics.EndImageContext();

        // Blur vertically
        UIGraphics.BeginImageContextWithOptions(image.Size, false, 1f);

        horizBlurredImage.Draw(new CGRect(0, 0, width, height), CGBlendMode.PlusLighter, weight[0]);

        for (int y = 1; y < 5; ++y)
        {
            horizBlurredImage.Draw(new CGRect(0, y, width, height), CGBlendMode.PlusLighter, weight[y]);
            horizBlurredImage.Draw(new CGRect(0, -y, width, height), CGBlendMode.PlusLighter, weight[y]);
        }

        var blurredImage = UIGraphics.GetImageFromCurrentImageContext();
        UIGraphics.EndImageContext();

        return blurredImage;
    }
Wes
  • 891
  • 9
  • 18