直播预览层添加滤镜效果
原理,在显示之前,提前对图片进行滤镜处理,把处理后的图片展示出来就好了.
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;
});
- 注意点:有个地方需要自己管理内存,否则程序会闪退,报下列错误
CGImageRef imgRef = [ctx createCGImage:ciImage fromRect:ciImage.extent];
UIImage *image = [UIImage imageWithCGImage:imgRef];
// 用完了及时清空,否则内存溢出,造成程序崩溃.使用C语言的时候,需要特别注意内存管理.
CGImageRelease(imgRef);
- 注意点:会报坏内存访问,原因有些对象销毁了,没有及时清空,再次用到就坏内存访问
- 测试:不需要添加滤镜效果,容易测试出来,报下列错误
- 解决:把一个周期的代码,放入一个自动释放池里管理,下一个运行循环,会自动清空已经销毁的对象。
- 自动释放池:可以用来管理一段代码中对象的生命周期。
@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;
});
}
}