300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > iOS 相机实时滤镜效果

iOS 相机实时滤镜效果

时间:2020-09-21 18:16:52

相关推荐

iOS 相机实时滤镜效果

前言

项目Demo,实现了实时滤镜、拍照、录像功能。

最近玩了哈实时滤镜,学到挺多东西的。笔者长得丑,看看有没有机会没那么丑。只挑了几种滤镜,笔者是个钢铁直男,没有美颜效果。

原理

设备获取图像输入流后,经过对该帧处理形成新图像,最后刷新UI

实现

苹果有简单的UIImagePickerController,但扩展性差。所以笔者采用的是AVFoundation框架。其涉及到输入流和输出流,方便我们对每一帧进行处理,显示出来

如果你对输入和输出相关的类不了解,应该也不影响你理解本文。但笔者还是建议你先看哈苏沫离的博客。比如,OC之输入管理AVCaptureInput,OC之输出管理 AVCaptureOutput。

有一个类AVCaptureMovieFile,直接把音频和图像结合起来。但由于要处理画面,所以又得拆分开。所以笔者采用的是AVCaptureAudioDataOutputAVCaptureVideoDataOutput,处理完图像再拼。

1. 获取输入流

输入流要通过相关设备初始化。

// 图像_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];_cameraDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:self.device error:nil];// 音频AVCaptureDevice *micDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];_microphoneDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:micDevice error:nil];复制代码

2. 初始化输出流

_queue = dispatch_queue_create("VideoDataOutputQueue", DISPATCH_QUEUE_SERIAL);// 图像_videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];_videoDataOutput.videoSettings = @{(id)kCVPixelBufferPixelFormatTypeKey : [NSNumber numberWithInteger:kCVPixelFormatType_32BGRA]};_videoDataOutput.alwaysDiscardsLateVideoFrames = YES;[_videoDataOutput setSampleBufferDelegate:self queue:_queue];// 音频_audioDataOutput = [[AVCaptureAudioDataOutput alloc] init];[_audioDataOutput setSampleBufferDelegate:self queue:_queue];复制代码

创建了一个串行队列,以确保每一帧按顺序处理。输出流的回调方法为- (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection;

3. 创建会话,连接输入输出

AVCaptureSession会话起到中间层的作用。

_session = [[AVCaptureSession alloc] init];if ([_session canSetSessionPreset:AVCaptureSessionPreset1280x720]) {[_session setSessionPreset:AVCaptureSessionPreset1280x720];}{ // 把输入输出结合起来if ([_session canAddInput:_cameraDeviceInput]) {[_session addInput:_cameraDeviceInput];}if ([_session canAddOutput:_videoDataOutput]) {[_session addOutput:_videoDataOutput];}}复制代码

4. 开启会话

开启输入流,获取数据到输出流。

//开始启动[_session startRunning];复制代码

要注意的是,如果要修改输入流或者输出流,要在一次提交中完成。比如切换摄像头(修改输入流)。

//输入流AVCaptureDeviceInput *newInput = [AVCaptureDeviceInput deviceInputWithDevice:newCamera error:nil];if (newInput != nil) {[self.session beginConfiguration];//先移除原来的input[self.session removeInput:self.cameraDeviceInput];if ([self.session canAddInput:newInput]) {[self.session addInput:newInput];self.cameraDeviceInput = newInput;} else {[self.session addInput:self.cameraDeviceInput];}[self.session commitConfiguration];}复制代码

5. 输出流数据回调方法

// 在这里处理获取的图像,并且保存每一帧到self.outputImg- (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {@autoreleasepool {if (output == _audioDataOutput && [_audioWriterInput isReadyForMoreMediaData]) {// 处理音频[_audioWriterInput appendSampleBuffer:sampleBuffer];}if (output == self.videoDataOutput) { // 处理视频帧// 处理图片,保存到self.outputImg中[self imageFromSampleBuffer:sampleBuffer];}}}复制代码

在这一步,处理每一帧图像,加上滤镜。

6. 滤镜

这里用到了CIFilter,是苹果自带的CoreImage框架对图片进行处理的一个框架。其实现了上百种效果,笔者只选取了其中三种。感兴趣的可以去官方文档查看。

//1.创建基于CPU的CIContext对象 self.context = [CIContext contextWithOptions:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]forKey:kCIContextUseSoftwareRenderer]];//2.创建基于GPU的CIContext对象 self.context = [CIContext contextWithOptions: nil];//3.创建基于OpenGL优化的CIContext对象,可获得实时性能self.context = [CIContext contextWithEAGLContext:[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]];// 将UIImage转换成CIImageCIImage *ciImage = [[CIImage alloc] initWithImage:[UIImage imageNamed:@"WechatIMG1.jpeg"]];// 创建滤镜CIFilter *filter = [CIFilter filterWithName:_dataSourse[indexPath.row]keysAndValues:kCIInputImageKey, ciImage, nil];[filter setDefaults];// 获取绘制上下文CIContext *context = [CIContext contextWithOptions:nil];// 渲染并输出CIImageCIImage *outputImage = [filter outputImage];// 创建CGImage句柄CGImageRef cgImage = [self.context createCGImage:outputImagefromRect:[outputImage extent]];imageview.image = [UIImage imageWithCGImage:cgImage];// 释放CGImage句柄CGImageRelease(cgImage);复制代码

拍照和录像

在回调方法里,我们加完滤镜得到每一帧。当点下拍照按钮,把这一张图片保存到相册即完成了拍照功能。

对于录像,我们主要用到AVAssetWriter以及AVAssetWriterInputPixelBufferAdaptor

获取到图像和音频流后,我们将其放到缓冲区内。最终判断时间戳 ,AVAssetWriter将他们合成视频。

后记

遇到了一个问题,也记录一下吧。

前置摄像头镜像问题。网上大多思路都是iOS 前置摄像头镜像问题,但不能处理。原因可能是因为笔者项目对帧进行了处理,数据不是原生的图像。对图片再进行一次镜像处理即可。

if ([[self.cameraDeviceInput device] position] == AVCaptureDevicePositionFront) {// 前置要镜像result = [result imageByApplyingOrientation:UIImageOrientationUpMirrored];}复制代码

参考

iOS+Objective-C: Create a real time photo filter app

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。