直播預覽層添加濾鏡效果
原理,在顯示之前,提前對圖片進行濾鏡處理,把處理后的圖片展示出來就好了.
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;
});
}
}