iOS AR之视频特效挂件(GPUImage)
来源:互联网 发布:哈尔滨停车软件 编辑:程序博客网 时间:2024/04/29 04:22
在苹果开发者大会之后,苹果要在iOS 11 、Xcode9中添加ARKit框架,似乎AR没有那么神秘,我们早就用过了,比如QQ的视频挂件、花椒的礼物动画、还有支付宝的扫福都应该属于AR技术。今天我就浅谈视频特效挂件。
思路
- 1.通过摄像头捕获数据
- 2.回调数据CMSampleBufferRef
- 3.进行物体识别(人脸识别)这里用的是CoreImage的人脸识别CIDetector、也可用OpenCV等。
- 4.显示特效(视频、GIF、图片、文字等等)
- 5.视频本地写入
涉及到的技术
- 1.GPUImageVideoCamera的使用
- 2.GPUImageUIElement的使用
- 3.FLAnimatedImageView的使用
- 4.GPUImageMovie的使用
- 5.GPUImageFilter的使用
- 6.CIDetector的使用
我做的是显示GIF特效。效果图: 请忽略我的模样\( ̄︶ ̄)/
Demo没有做美颜,可查看我GPUImage其他博客、应该会有收获
完整Demo地址:
https://coding.net/u/Xoxo_x/p/VideoAndAudio/git/blob/master/GPUImage%E7%9B%B8%E6%9C%BA%E7%89%B9%E6%95%88.zip
主要步骤:
[self initGPUImageView];//初始化GPUImageView //初始化滤镜GPUImageAlphaBlendFilter,主要用来做半透明的混合的 [self initFilter]; [self initCamera];//初始化相机
GPUImageUIElement 是GPUImage提供的可以将我们的普通UI转化为纹理输出到视频中
- (UIView *)elementView { if (!_elementView) { gifImageView = [[FLAnimatedImageView alloc] init]; gifImageView.frame = CGRectMake(0, 0, 160, 160); [self.view addSubview:gifImageView]; NSData *gifImageData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle]pathForResource:[NSString stringWithFormat:@"hudie"] ofType:@"gif" inDirectory:nil]]; [self animatedImageView:gifImageView data:gifImageData]; [_elementView addSubview:gifImageView]; } return _elementView;}
FLAnimatedImageView 用于播放gif动画
GPUImageFilter* progressFilter = [[GPUImageFilter alloc] init]; [videoCamera addTarget:progressFilter];
将两个纹理输出到GPUImageView
[progressFilter addTarget:filter]; [pictureView addTarget:filter]; [filter addTarget:filterView];
设置处理回调
__strong typeof(self) strongSelf = self; [progressFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *output, CMTime time) { // update capImageView's frame CGRect rect = strongSelf.faceBounds; CGSize size = gifImageView.frame.size; [UIView animateWithDuration:0.2 animations:^{ gifImageView.frame = CGRectMake(rect.origin.x + (rect.size.width - size.width)/2, rect.origin.y - size.height, size.width, size.height); }]; [pictureView updateWithTimestamp:time]; [strongSelf->pictureView updateWithTimestamp:time]; }];
使用屏幕刷新频率
CADisplayLink * displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)]; [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
视频回调代理、获取原始数据
- (void)willOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer { if (!_faceThinking) { CFAllocatorRef allocator = CFAllocatorGetDefault(); CMSampleBufferRef sbufCopyOut; CMSampleBufferCreateCopy(allocator,sampleBuffer,&sbufCopyOut); [self performSelectorInBackground:@selector(grepFacesForSampleBuffer:) withObject:CFBridgingRelease(sbufCopyOut)]; }}
将CMSampleBufferRef进行图像转化识别、提取特征
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); CFDictionaryRef attachments = CMCopyDictionaryOfAttachments(kCFAllocatorDefault, sampleBuffer, kCMAttachmentMode_ShouldPropagate); CIImage *convertedImage = [[CIImage alloc] initWithCVPixelBuffer:pixelBuffer options:(__bridge NSDictionary *)attachments];
imageOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:exifOrientation] forKey:CIDetectorImageOrientation]; NSArray *features = [self.faceDetector featuresInImage:convertedImage options:imageOptions]; // get the clean aperture // the clean aperture is a rectangle that defines the portion of the encoded pixel dimensions // that represents image data valid for display. CMFormatDescriptionRef fdesc = CMSampleBufferGetFormatDescription(sampleBuffer); CGRect clap = CMVideoFormatDescriptionGetCleanAperture(fdesc, false /*originIsTopLeft == false*/);
进行识别
dispatch_async(dispatch_get_main_queue(), ^{ CGRect previewBox = self.view.frame; if (featureArray.count) { gifImageView.hidden = NO; } else {// gifImageView.hidden = YES; return ; } for ( CIFaceFeature *faceFeature in featureArray) { // find the correct position for the square layer within the previewLayer // the feature box originates in the bottom left of the video frame. // (Bottom right if mirroring is turned on) //Update face bounds for iOS Coordinate System CGRect faceRect = [faceFeature bounds]; // flip preview width and height CGFloat temp = faceRect.size.width; faceRect.size.width = faceRect.size.height; faceRect.size.height = temp; temp = faceRect.origin.x; faceRect.origin.x = faceRect.origin.y; faceRect.origin.y = temp; // scale coordinates so they fit in the preview box, which may be scaled CGFloat widthScaleBy = previewBox.size.width / clap.size.height; CGFloat heightScaleBy = previewBox.size.height / clap.size.width; faceRect.size.width *= widthScaleBy; faceRect.size.height *= heightScaleBy; faceRect.origin.x *= widthScaleBy; faceRect.origin.y *= heightScaleBy; faceRect = CGRectOffset(faceRect, previewBox.origin.x, previewBox.origin.y); //mirror CGRect rect = CGRectMake(previewBox.size.width - faceRect.origin.x - faceRect.size.width, faceRect.origin.y, faceRect.size.width, faceRect.size.height); if (fabs(rect.origin.x - self.faceBounds.origin.x) > 5.0) { self.faceBounds = rect; // if (self.faceView) { // [self.faceView removeFromSuperview]; // self.faceView = nil; // } // // // create a UIView using the bounds of the face // self.faceView = [[UIView alloc] initWithFrame:self.faceBounds]; // // // add a border around the newly created UIView // self.faceView.layer.borderWidth = 1; // self.faceView.layer.borderColor = [[UIColor redColor] CGColor]; // // // add the new view to create a box around the face // [self.view addSubview:self.faceView]; } } });
然后再回到中更改蝴蝶的位置为头顶的位置
完整Demo地址:
https://coding.net/u/Xoxo_x/p/VideoAndAudio/git/blob/master/GPUImage%E7%9B%B8%E6%9C%BA%E7%89%B9%E6%95%88.zip
阅读全文
0 0
- iOS AR之视频特效挂件(GPUImage)
- iOS GPUImage之GPUImageMovie视频滤镜(1)
- iOS GPUImage之GPUImageMovie视频滤镜(2)
- GPUImage之视频流滤镜
- iOS GPUImage之自定义滤镜
- iOS-音视频采集 by GPUImage
- GPUImage--视频流处理之AVCaptureVideoDataOutputSampleBufferDelegate
- GPUImage学习日记(2)之视频录制
- iOS GPUImage之GPUImageStillCamera(2)
- iOS GPUImage之GPUImageVideoCamera(3)
- iOS GPUImage之头文件说明
- iOS上用GPUImage给视频加滤镜
- ios GPUImage简单滤镜 -- 录制视频(保存+聚焦)
- iOS上用GPUImage给视频加滤镜
- iOS GPUImage研究三:视频采集并添加实时滤镜
- iOS 使用GPUImage为本地视频添加滤镜
- iOS GPUImage研究五:短视频拍摄(滤镜、文件写入)
- iOS GPUImage研究六:为视频添加图片水印
- Dining POJ
- JAVA枚举类状态机 与 Java枚举策略模式
- [python基础教程第二部]第二章
- 算法设计与应用基础系列18
- Roads in the North 【树的直径】
- iOS AR之视频特效挂件(GPUImage)
- 设计模式(Design Pattern)
- Oracle优化新常态
- Android 从源码分析BLE连接错误分析
- python中list删除方法比较
- 数据库连接池
- jq写无缝轮播
- 二、创建Django工程
- Python/matlab实现KNN算法