AVCaptureStillImageOutput获取静态图像

透过 AVCaptureStillImageOutput 做静态影像的撷取

2013/09/23 juluren

转载自:http://iteches.com/archives/34497

 

在 iOS 6 SDK(iOS 5 SDK 以上)中捕捉摄影机的静态拍摄画面,制作类似「录像同时拍照的效果」可以透果很多方式,像是透过 
UIImagePickerController 的方式,呼叫 iOS SDK 所提供的 API 来捕捉画面,或是透过 
AVFoundation 的
方式,建立影像的 AVCaptureSession,并且设定对应的 Input 与 Output。而本篇文章所采用的方法属于后者,我们使用
AVCaptureStillImageOutput 来当做 AVCaptureSession 的 Output 端,输出静态影像。

在开始之前请先替您的项目加上 AVFoundation.framework,并且在对应的类别中引用此头文件。替项目加入 F ramework 的方法请参考
Xcode 4 新增 Framework 的方法 一文。

建立 AVCaptureSession

在这部份中我们要在类别的 @interface 区段中宣告一个 AVCaptureSession 型态的全局变量,方便之后的作业。
AVCaptureSession *myCaptureSession;

在建立 AVCaptureSession 的部份,其实并没有太多的设定,唯一要注意的是 setSessionPreset:
这个方法函式,它决定了摄影机捕获影像的分辨率大小,你可以使用 AVCaptureSessionPreset 的关键词来查阅各种分辨率的定义。
//建立 AVCaptureSession
myCaptureSession = [[AVCaptureSession alloc] init];
[myCaptureSession setSessionPreset:AVCaptureSessionPresetPhoto];

建立 AVCaptureDeviceInput

在建立好 AVCaptureSession 之后,接下来我们要对他的输入端做设定,你可以透过下列程序代码来取得装置上具有输入特性的硬件装置和他们实际的装置名称。
//建立 AVCaptureDeviceInput
NSArray *myDevices = [AVCaptureDevice devices];

for (AVCaptureDevice *device in myDevices) {
    if ([device position] == AVCaptureDevicePositionBack) {
        NSLog(@"后摄影机硬件名称: %@", [device localizedName]);
    }

if ([device position] == AVCaptureDevicePositionFront) {
        NSLog(@"前摄影机硬件名称: %@", [device localizedName]);
    }

    if ([device hasMediaType:AVMediaTypeAudio]) {
        NSLog(@"麦克风硬件名称: %@", [device localizedName]);
    }
}

装置上具有输入特性的硬件名称

下列我们就以后置镜头为例,制作 AVCaptureSession 的输入端。

//使用后置镜头当做输入
NSError *error = nil;
for (AVCaptureDevice *device in myDevices) {
    if ([device position] == AVCaptureDevicePositionBack) {

AVCaptureDeviceInput *myDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];

        if (error) {
            //装置取得失败时的处理程序
        } else {
            [myCaptureSession addInput:myDeviceInput];
        }
    }
}

建立 AVCaptureVideoPreviewLayer

在建立 AVCaptureSession 与设定对应的 Input
之后,我们就可以透过 AVCaptureVideoPreviewLayer 来取得摄影机所捕捉的连续画面,在
此,AVCaptureVideoPreviewLayer
所呈现的画面是连续的,并非单张的静态影像,当然你也可以略过设定 AVCaptureVideoPreviewLayer
的步骤,不显示摄影机所拍摄到的画面,这并不会有任何影响。
//建立 AVCaptureVideoPreviewLayer
AVCaptureVideoPreviewLayer *myPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:myCaptureSession];
[myPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];

CGRect rect = CGRectMake(160, 180, 320, 240);
[myPreviewLayer setBounds:rect];

UIView *myView = [[UIView alloc]initWithFrame:rect];
[myView.layer addSublayer:myPreviewLayer];

[self.view addSubview:myView];

//启用摄影机
[myCaptureSession startRunning];

在上述程序代码中,
我们透过 AVCaptureSession 来建立 AVCaptureVideoPreviewLayer,并且设定它的 VideoGravity
属性为
AVLayerVideoGravityResizeAspectFill,表示所取得的影像必须以等比例的方式缩放来填满我们所指定的大小
(CGRect rect)。

到目前为止,我们还并未对 AVCaptureSession 做 Output 的设定,但是已经可以透过 AVCaptureVideoPreviewLayer 在画面上看到摄影机所拍摄的影像。下面,我们将针对静态影像的撷取来制作对应的 Output。

建立 AVCaptureStillImageOutput

要使用单张静态影像的撷取,就可以考虑使用 AVCaptureStillImageOutput 来制作你的 Output
端,否则最好是使用 AVCaptureVideoDataOutput 来当做输出端,这两个不同类型的 Output 可以做的事情也不尽相同,关于
AVCaptureVideoDataOutput 可以参考
透过 AVCaptureVideoDataOutput 做连续影像片段的撷取一文,来获得更多信息,下面我们只针对 AVCaptureStillImageOutput 做说明。

在这部份中我们要在类别的 @interface 区段中宣告一个 AVCaptureStillImageOutput 型态的全局变量,方便之后的作业。
AVCaptureStillImageOutput *myStillImageOutput;

接着,在根据以下程序代码对 AVCaptureStillImageOutput 做设定,并将此 Output 与 AVCaptureSession 做连接。
//建立 AVCaptureStillImageOutput
myStillImageOutput = [[AVCaptureStillImageOutput alloc] init];
NSDictionary *myOutputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey,nil];
[myStillImageOutput setOutputSettings:myOutputSettings];

[myCaptureSession addOutput:myStillImageOutput];

在设定 AVCaptureStillImageOutput 上,我们将所撷取到的影像做 JPEG 的编码以节省空间,虽然说使用
AVVideoCodec 这个关键词时,你可以看到 AVVideoCodecH264 的选项,但是他并不是静态影像的编码方式,而是使用在
Video 上的一种压缩编码,所以无法使用。

撷取单张静态影像

在成功建立好 AVCaptureSession 的 Output 之后,接下来就是制作静态影像撷取,你可以透过下列的方法函式,来与拍照的按钮做互动,取得静态影像。
AVCaptureConnection *myVideoConnection = nil;

//从 AVCaptureStillImageOutput 中取得正确类型的 AVCaptureConnection
for (AVCaptureConnection *connection in myStillImageOutput.connections) {
    for (AVCaptureInputPort *port in [connection inputPorts]) {
        if ([[port mediaType] isEqual:AVMediaTypeVideo]) {

myVideoConnection = connection;
            break;
        }
    }
}

//撷取影像(包含拍照音效)
[myStillImageOutput
captureStillImageAsynchronouslyFromConnection:myVideoConnection
completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError
*error) {

//完成撷取时的处理程序(Block)
    if (imageDataSampleBuffer) {
        NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];

//取得的静态影像
         UIImage *myImage = [[UIImage alloc] initWithData:imageData];
         [self setImage:myImage];

//取得影像数据(需要ImageIO.framework 与 CoreMedia.framework)
         CFDictionaryRef myAttachments = CMGetAttachment(imageDataSampleBuffer, kCGImagePropertyExifDictionary, NULL);
         NSLog(@"影像属性: %@", myAttachments);

    }
}];

在上述程序代码中,
我们必须先从 AVCaptureStillImageOutput 中取得正确类型的
AVCaptureConnection,接着,才利用此 AVCaptureConnection
做影像的撷取,另外,如果你希望改变撷取影像时的方向,也可以对 AVCaptureConnection 做
setVideoOrientation: 旋转影像,或 setVideoMirrored: 镜射影像。

另外,在撷影像时会包含拍照的音效,无法消除,这是基于 iOS SDK 安全条款的使用原则,如果你是想制作每秒撷取 N 张静态影像的话,最好还是使用 AVCaptureVideoDataOutput 来当做输出,避免产生连续的拍照音效。

最后,我们也可以使用 CMGetAttachment 来取得该影像的其他属性,但是这必须使用 ImageIO 与 CoreMedia 两个 Framework 才行。


使用 CMGetAttachment 所取的的影像属性
时间: 2024-10-19 21:14:26

AVCaptureStillImageOutput获取静态图像的相关文章

在C#中使用WIA获取扫描仪数据

WIA(Windows Image Acquire,最新版本2.0)是Windows中一组从设备中捕获图像的标准API集合,它可以从设备(例如扫描仪.数码相机)中获取静态图像,以及管理这些设备.它既是API,又是DDI(Device Driver Interface).因此,只要是满足这个规范的设备,都能够利用WIA直接和应用程序交互,而不是通过驱动.WIA甚至提供了统一的对话框来获取图片. WIA是基于Com的,有两种使用方式: c++:使用WIA自定义接口 其他:使用WIAAL(WIA Au

人脸表情识别相关研究

1. 国内外研究人脸表情识别的公司与产品介绍 现在,国内外都有人脸识别的相关产品,尤其在美国,已经能够通过机器人识别人脸表情,还能推断人的年龄等.而在国内,以杭州热知科技为代表的主要是生产人脸识别和表情识别的嵌入式设备. 国外: 1.美国汉森机器人公司 爱因斯坦机器人Einstein 图1 美国汉森机器人公司的爱因斯坦机器人 Einstein是美国汉森机器人公司的机器人专家大卫·汉森设计的一款类人机器人.它不仅能识别喜怒哀乐.恐惧.迷茫等数以百计的面部表情,推断人的年龄和性别,还能做出相应表情回

人脸表情识别综述

一.人脸表情识别技术目前主要的应用领域包括人机交互.安全.机器人制造.医疗.通信和汽车领域等 二.1971年,心理学家Ekman与Friesen的研究最早提出人类有六种主要情感,每种情感以唯一的表情来反映人的一种独特的心理活动.这六种情感被称为基本情感,由愤怒(anger).高兴(happiness).悲伤 (sadness).惊讶(surprise).厌恶(disgust)和恐惧(fear)组成 人脸面部表情运动的描述方法---人脸运动编码系统FACS (Facial Action Codin

Android学习(五)

学号 20189214 <Java程序设计>第十周学习总结 教材学习内容总结 偏好 在sharedPreferences包含一个键值对,可以使用contains方法,来判断指定的键是否存在.可以使用getAll方法对所有的键值对获取为一个Map. SettingFragment类是PreferenceFragment类的一个子类.它是一个简单的类,直接调用了addPreferences FromResource方法来加载3个Preference子类的布局xml文档. 操作文件 Android设

获取图片中指定区域图片

转载自   http://blog.csdn.net/whf727/article/details/14522635 最近在搞直接一个类似于二维码的东西,同样也是需要获取其中某个区域的图片.直接上最为主要的一些代码吧. 下面这个是初始化AV部分,这样就可以将图像在view上面展示了.这里简单的阐述一下在这其中碰到的问题和解决方法. 1.如果在layer上面搞出一个“洞 ”,就是真正的裁剪区域,在这里用的是CAShapeLayer,利用fillMode,这样就可以通过mask方式作用在将覆盖在pe

【API】高德地图API JS实现获取坐标和回显点标记

1.搜索+选择+获取经纬度和详细地址 2.回显数据并点标记 3.实现 第一步:引入资源文件 <!--引入高德地图JSAPI --><script src="//webapi.amap.com/maps?v=1.3&key=在官网申请一个key"></script><!--引入UI组件库(1.0版本) --><script src="//webapi.amap.com/ui/1.0/main.js">

微信开发 网页授权获取用户基本信息

微信公众平台最近新推出微信认证,认证后可以获得高级接口权限,其中一个是OAuth2.0网页授权,很多朋友在使用这个的时候失败了或者无法理解其内容,希望我出个教程详细讲解一下,于是便有了这篇文章. 一.什么是OAuth2.0 官方网站:http://oauth.net/   http://oauth.net/2/ 权威定义:OAuth is An open protocol to allow secure authorization in a simple and standard method

easyui-textbox 和 easyui-validatebox 设置值和获取值

表单作如下定义:该input使用easyui的"easyui-textbox" 1 <input id="addSnumber" style="width: 200px; height: 30px;" class="easyui-textbox" type="text" name="snumber" data-options="required:true, missing

jsp获取当前项目跟路径

在jsp中获取当前项目的根路径: <% String basePath = request.getScheme() + "://"+ request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/";%> 可以使用${basePath}获取.