直播预览层添加滤镜效果(CIFilter使用场景)

直播预览层添加滤镜效果

  • 原理,在显示之前,提前对图片进行滤镜处理,把处理后的图片展示出来就好了.

  • CIFiter(滤镜类):给图片添加特殊效果(模糊,高亮等等).

  • CIFiter滤镜分类(一个滤镜可能属于多个分类)

    • kCICategoryDistortionEffect 扭曲效果,比如bump、旋转、hole
    • kCICategoryGeometryAdjustment 几何开着调整,比如仿射变换、平切、透视转换
    • kCICategoryCompositeOperation 合并,比如源覆盖(source over)、最小化、源在顶(source atop)、色彩混合模式
    • kCICategoryHalftoneEffect Halftone效果,比如screen、line screen、hatched
    • kCICategoryColorAdjustment 色彩调整,比如伽马调整、白点调整、曝光
    • kCICategoryColorEffect 色彩效果,比如色调调整、posterize
    • kCICategoryTransition 图像间转换,比如dissolve、disintegrate with mask、swipe
    • kCICategoryTileEffect 瓦片效果,比如parallelogram、triangle
    • kCICategoryGenerator 图像生成器,比如stripes、constant color、checkerboard
    • kCICategoryGradient 渐变,比如轴向渐变、仿射渐变、高斯渐变
    • kCICategoryStylize 风格化,比如像素化、水晶化
    • kCICategorySharpen 锐化、发光
    • kCICategoryBlur 模糊,比如高斯模糊、焦点模糊、运动模糊
    • kCICategoryStillImage 能用于静态图像
    • kCICategoryVideo 能用于视频
    • kCICategoryInterlaced 能用于交错图像
    • kCICategoryNonSquarePixels 能用于非矩形像素
    • kCICategoryHighDynamicRange 能用于HDR
    • kCICategoryBuiltIn 获取所有滤镜
  • 常用图片处理滤镜:

    
    // 怀旧 --> CIPhotoEffectInstant                         单色 --> CIPhotoEffectMono
    // 黑白 --> CIPhotoEffectNoir                            褪色 --> CIPhotoEffectFade
    // 色调 --> CIPhotoEffectTonal                           冲印 --> CIPhotoEffectProcess
    // 岁月 --> CIPhotoEffectTransfer                        铬黄 --> CIPhotoEffectChrome
    
    
  • 自动处理滤镜,通过CIImage获取,CIImage会自动对图片进行滤镜处理

    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
        
    // 转换为CIImage
    CIImage *ciImage = [CIImage imageWithCVImageBuffer:imageBuffer];
        
        
    NSArray *fiters = [ciImage autoAdjustmentFilters];
        
    NSLog(@"%@",fiters);
  • 常有的自动滤镜

        CIRedEyeCorrection:修复因相机的闪光灯导致的各种红眼
        CIFaceBalance:调整肤色
        CIVibrance:在不影响肤色的情况下,改善图像的饱和度
        CIToneCurve:改善图像的对比度
        CIHighlightShadowAdjust:改善阴影细节      
    
  • 滤镜对象创建(也可以使用coreImage自动处理滤镜,就不需要自己创建)

  • 滤镜属性可以通过inputKeys属性获取

  • 滤镜工作原理,给滤镜传入一个图片,滤镜有个方法,可以获取处理完成的图片outputImage.

        CIFilter *fiter = [CIFilter filterWithName:@"CIPhotoEffectInstant"];
        
        [fiter setValue:ciImage forKey:@"inputImage"];
        
        ciImage = fiter.outputImage;

直播预览层添加滤镜效果步骤

  • 取出捕获到的帧(CMSampleBufferRef) -> 获取帧里面图片信息(CVImageBufferRef) -> CIFiter滤镜处理 ->转换成UIImage -> 设置为UIImageView的image就能实时显示捕获的画面
if (_videoConnection == connection) {
        // 获取图片信息
        CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
        
        // 转换为CIImage
        CIImage *ciImage = [CIImage imageWithCVImageBuffer:imageBuffer];
        
        // 创建滤镜
        CIFilter *fiter = [CIFilter filterWithName:@"CIFaceBalance"];
        
        [fiter setValue:ciImage forKey:@"inputImage"];
        [fiter setValue:@100 forKey:@"inputStrength"];
        ciImage = fiter.outputImage;
        
        // 转换UIImage
        UIImage *image = [UIImage imageWithCIImage:ciImage];
        
        dispatch_sync(dispatch_get_main_queue(), ^{
            
            self.imageView.image = image;
            
        });
    }

通过GPU渲染图片显示

  • 只有OpenGL才能操控GPU,需要用到OpenGL才行
  • CIContext:通过这个上下文的方法渲染图片(createCGImage)
  • CIContext:通过OpenGL的上下文创建,就能用GPU渲染图片,处理图片效率高.(contextWithEAGLContext)
  // 获取图片信息
            CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
            
            // 转换为CIImage
            CIImage *ciImage = [CIImage imageWithCVImageBuffer:imageBuffer];
            
            // 创建滤镜
            CIFilter *fiter = [CIFilter filterWithName:@"CIPhotoEffectInstant"];
            
            [fiter setValue:ciImage forKey:@"inputImage"];
            
            ciImage = fiter.outputImage;
            
            EAGLContext *openglCtx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
            CIContext *ctx = [CIContext contextWithEAGLContext:openglCtx];
            
            CGImageRef imgRef = [ctx createCGImage:ciImage fromRect:ciImage.extent];
            
            UIImage *image = [UIImage imageWithCGImage:imgRef];
        
            // 用完了及时清空,否则内存溢出,造成程序崩溃.使用C语言的时候,需要特别注意内存管理.
            CGImageRelease(imgRef);
        
            // 转换UIImage
            
            dispatch_sync(dispatch_get_main_queue(), ^{
                
                self.imageView.image = image;
                
                
            });
  • 注意点:有个地方需要自己管理内存,否则程序会闪退,报下列错误
内存溢出bug.png
CGImageRef imgRef = [ctx createCGImage:ciImage fromRect:ciImage.extent];
            
UIImage *image = [UIImage imageWithCGImage:imgRef];
        
// 用完了及时清空,否则内存溢出,造成程序崩溃.使用C语言的时候,需要特别注意内存管理.
CGImageRelease(imgRef);
  • 注意点:会报坏内存访问,原因有些对象销毁了,没有及时清空,再次用到就坏内存访问
  • 测试:不需要添加滤镜效果,容易测试出来,报下列错误
坏内存访问.png
  • 解决:把一个周期的代码,放入一个自动释放池里管理,下一个运行循环,会自动清空已经销毁的对象。
  • 自动释放池:可以用来管理一段代码中对象的生命周期。
 @autoreleasepool {
            // 获取图片信息
            CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
            
            // 转换为CIImage
            CIImage *ciImage = [CIImage imageWithCVImageBuffer:imageBuffer];
            
            // 创建滤镜
            CIFilter *fiter = [CIFilter filterWithName:@"CIPhotoEffectInstant"];
            
            [fiter setValue:ciImage forKey:@"inputImage"];
            
            ciImage = fiter.outputImage;
        
            EAGLContext *openglCtx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
            CIContext *ctx = [CIContext contextWithEAGLContext:openglCtx];
            
            CGImageRef imgRef = [ctx createCGImage:ciImage fromRect:ciImage.extent];
            
            UIImage *image = [UIImage imageWithCGImage:imgRef];
        
            // 用完了及时清空,否则内存溢出,造成程序崩溃.使用C语言的时候,需要特别注意内存管理.
            CGImageRelease(imgRef);
        
            // 转换UIImage
            
            dispatch_sync(dispatch_get_main_queue(), ^{
                
                self.imageView.image = image;
                
            });

        }
        
    }

推荐阅读更多精彩内容