美文网首页多媒体图像
iOS高斯模糊的两种方法

iOS高斯模糊的两种方法

作者: 小冰山口 | 来源:发表于2018-11-21 00:28 被阅读0次

    本人有若干成套学习视频, 可试看! 可试看! 可试看, 重要的事情说三遍 包含Java, 数据结构与算法, iOS, 安卓, python, flutter等等, 如有需要, 联系微信tsaievan.

    网上有很多类似的文章了, 但还是想自己总结一下.
    UIBlurEffect貌似效果一般, 并不能满足需求, UIBlurEffect的原理是生成一个模糊的蒙版view盖在原来的view上.

    而我现在在项目中使用的方法是直接对图片进行高斯模糊

    高斯模糊后
    高斯模糊前

    思路就是: 首先把固定区域的view转换成图片, 然后将图片进行高斯模糊, 盖在原来的view上.

    • 第一步: 将固定区域的view转换成图片
    + (UIImage *)tg_makeImageWithView:(UIView *)view withSize:(CGSize)size {
        // 下面方法,第一个参数表示区域大小。第二个参数表示是否是非透明的。如果需要显示半透明效果,需要传NO,否则传YES。第三个参数就是屏幕密度了,关键就是第三个参数 [UIScreen mainScreen].scale。
        UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
        [view.layer renderInContext:UIGraphicsGetCurrentContext()];
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return image;
    }
    

    这里我写了一个分类方法: 两个参数, 一个传入想转换成图片的view, 另一个传想转成图片的size.

    • 第二步, 将图片进行高斯模糊: 有两种方法
      • 一种是vImage:
    + (UIImage *)tg_blurryImage:(UIImage *)image withBlurLevel:(CGFloat)blur {
         if(image==nil){
            return nil;
        }
        int boxSize = blur;
        if (blur<1||blur>100) {
            boxSize=25;
        }
        boxSize = boxSize - (boxSize % 2) + 1;
    
        CGImageRef img = image.CGImage;
    
        vImage_Buffer inBuffer, outBuffer, rgbOutBuffer;
        vImage_Error error;
    
        void *pixelBuffer, *convertBuffer;
    
        CGDataProviderRef inProvider = CGImageGetDataProvider(img);
        CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);
    
        convertBuffer = malloc( CGImageGetBytesPerRow(img) * CGImageGetHeight(img) );
        rgbOutBuffer.width = CGImageGetWidth(img);
        rgbOutBuffer.height = CGImageGetHeight(img);
        rgbOutBuffer.rowBytes = CGImageGetBytesPerRow(img);
        rgbOutBuffer.data = convertBuffer;
    
        inBuffer.width = CGImageGetWidth(img);
        inBuffer.height = CGImageGetHeight(img);
        inBuffer.rowBytes = CGImageGetBytesPerRow(img);
        inBuffer.data = (void *)CFDataGetBytePtr(inBitmapData);
    
        pixelBuffer = malloc( CGImageGetBytesPerRow(img) * CGImageGetHeight(img) );
    
        if (pixelBuffer == NULL) {
            NSLog(@"No pixelbuffer");
        }
    
        outBuffer.data = pixelBuffer;
        outBuffer.width = CGImageGetWidth(img);
        outBuffer.height = CGImageGetHeight(img);
        outBuffer.rowBytes = CGImageGetBytesPerRow(img);
    
        void *rgbConvertBuffer = malloc( CGImageGetBytesPerRow(img) * CGImageGetHeight(img) );
        vImage_Buffer outRGBBuffer;
        outRGBBuffer.width = CGImageGetWidth(img);
        outRGBBuffer.height = CGImageGetHeight(img);
        outRGBBuffer.rowBytes = CGImageGetBytesPerRow(img);//3
        outRGBBuffer.data = rgbConvertBuffer;
    
        error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
        //    error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
    
        if (error) {
            NSLog(@"error from convolution %ld", error);
        }
        const uint8_t mask[] = {2, 1, 0, 3};
    
        vImagePermuteChannels_ARGB8888(&outBuffer, &rgbOutBuffer, mask, kvImageNoFlags);
    
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGContextRef ctx = CGBitmapContextCreate(rgbOutBuffer.data,
                                                 rgbOutBuffer.width,
                                                 rgbOutBuffer.height,
                                                 8,
                                                 rgbOutBuffer.rowBytes,
                                                 colorSpace,
                                                 kCGImageAlphaNoneSkipLast);
        CGImageRef imageRef = CGBitmapContextCreateImage(ctx);
        UIImage *returnImage = [UIImage imageWithCGImage:imageRef];
    
        //clean up
        CGContextRelease(ctx);
    
        free(pixelBuffer);
        free(convertBuffer);
        free(rgbConvertBuffer);
        CFRelease(inBitmapData);
    
        CGColorSpaceRelease(colorSpace);
        CGImageRelease(imageRef);
    
        return returnImage;
    }
    

    这代码就是我copy过来的, 繁杂的很, 高斯模糊的效果一般.

    • 另一种是利用CGImage:
    + (UIImage *)tg_blurryImage:(UIImage *)image withBlurLevel:(CGFloat)blur {
        if (image == nil) {
            return nil;
        }
        CIContext *context = [CIContext contextWithOptions:nil];
        CIImage *ciImage = [CIImage imageWithCGImage:image.CGImage];
        CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
        [filter setValue:ciImage forKey:kCIInputImageKey];
        //设置模糊程度
        [filter setValue:@(blur) forKey: @"inputRadius"];
        CIImage *result = [filter valueForKey:kCIOutputImageKey];
        CGImageRef outImage = [context createCGImage: result fromRect:ciImage.extent];
        UIImage * blurImage = [UIImage imageWithCGImage:outImage];
        CGImageRelease(outImage);
        return blurImage;
    }
    

    这个代码就简洁的多了, 并且步骤可以理得很清楚:
    先将UIImage转换成CIImage, 然后设置滤镜, 给滤镜的@"inputRadius"的值设置value进行高斯模糊, 将CIImage转换成UIImage返回.

    • 拿到已经完成高斯模糊的图片盖在原来的view上即可.

    PS. 本人有若干成套学习视频, 包含Java, 数据结构与算法, iOS, 安卓, python, flutter等等, 如有需要, 联系微信tsaievan.

    相关文章

      网友评论

        本文标题:iOS高斯模糊的两种方法

        本文链接:https://www.haomeiwen.com/subject/qtmxqqtx.html