- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章iOS开发技巧之自定义相机由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
最近公司的项目中用到了相机,由于不用系统的相机,UI给的相机切图,必须自定义才可以。就花时间简单研究了一下相机的自定义.
相机属于系统硬件,这就需要我们来手动调用iPhone的相机硬件,分为以下步骤:
1、首先声明以下对象 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#import <AVFoundation/AVFoundation.h>
//捕获设备,通常是前置摄像头,后置摄像头,麦克风(音频输入)
@property (nonatomic, strong) AVCaptureDevice *device;
//AVCaptureDeviceInput 代表输入设备,他使用AVCaptureDevice 来初始化
@property (nonatomic, strong) AVCaptureDeviceInput *input;
//输出图片
@property (nonatomic ,strong) AVCaptureStillImageOutput *imageOutput;
//session:由他把输入输出结合在一起,并开始启动捕获设备(摄像头)
@property (nonatomic, strong) AVCaptureSession *session;
//图像预览层,实时显示捕获的图像
@property (nonatomic ,strong) AVCaptureVideoPreviewLayer *previewLayer;
|
2、初始化各个对象 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
- (
void
)cameraDistrict
{
// AVCaptureDevicePositionBack 后置摄像头
// AVCaptureDevicePositionFront 前置摄像头
self.device = [self cameraWithPosition:AVCaptureDevicePositionFront];
self.input = [[AVCaptureDeviceInput alloc] initWithDevice:self.device error:nil];
self.imageOutput = [[AVCaptureStillImageOutput alloc] init];
self.session = [[AVCaptureSession alloc] init];
// 拿到的图像的大小可以自行设定
// AVCaptureSessionPreset320x240
// AVCaptureSessionPreset352x288
// AVCaptureSessionPreset640x480
// AVCaptureSessionPreset960x540
// AVCaptureSessionPreset1280x720
// AVCaptureSessionPreset1920x1080
// AVCaptureSessionPreset3840x2160
self.session.sessionPreset = AVCaptureSessionPreset640x480;
//输入输出设备结合
if
([self.session canAddInput:self.input]) {
[self.session addInput:self.input];
}
if
([self.session canAddOutput:self.imageOutput]) {
[self.session addOutput:self.imageOutput];
}
//预览层的生成
self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
self.previewLayer.frame = CGRectMake(0, 64, SCREEN_WIDTH, SCREEN_HEIGHT-64);
self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.view.layer addSublayer:self.previewLayer];
//设备取景开始
[self.session startRunning];
if
([_device lockForConfiguration:nil]) {
//自动闪光灯,
if
([_device isFlashModeSupported:AVCaptureFlashModeAuto]) {
[_device setFlashMode:AVCaptureFlashModeAuto];
}
//自动白平衡,但是好像一直都进不去
if
([_device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeAutoWhiteBalance]) {
[_device setWhiteBalanceMode:AVCaptureWhiteBalanceModeAutoWhiteBalance];
}
[_device unlockForConfiguration];
}
}
|
根据前后置位置拿到相应的摄像头:
1
2
3
4
5
6
7
8
|
- (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position{
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for
( AVCaptureDevice *device in devices )
if
( device.position == position ){
return
device;
}
return
nil;
}
|
3、拍照拿到相应图片:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
- (
void
)photoBtnDidClick
{
AVCaptureConnection *conntion = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
if
(!conntion) {
NSLog(@
"拍照失败!"
);
return
;
}
[self.imageOutput captureStillImageAsynchronouslyFromConnection:conntion completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
if
(imageDataSampleBuffer == nil) {
return
;
}
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
self.image = [UIImage imageWithData:imageData];
[self.session stopRunning];
[self.view addSubview:self.cameraImageView];
}
|
4、保存照片到相册:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#pragma - 保存至相册
- (
void
)saveImageToPhotoAlbum:(UIImage*)savedImage
{
UIImageWriteToSavedPhotosAlbum(savedImage, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
}
// 指定回调方法
- (
void
)image: (UIImage *) image didFinishSavingWithError: (NSError *) error contextInfo: (
void
*) contextInfo
{
NSString *msg = nil ;
if
(error != NULL){
msg = @
"保存图片失败"
;
}
else
{
msg = @
"保存图片成功"
;
}
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@
"保存图片结果提示"
message:msg
delegate:self
cancelButtonTitle:@
"确定"
otherButtonTitles:nil];
[alert show];
}
|
5、前后置摄像头的切换 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
- (
void
)changeCamera{
NSUInteger cameraCount = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] count];
if
(cameraCount > 1) {
NSError *error;
//给摄像头的切换添加翻转动画
CATransition *animation = [CATransition animation];
animation.duration = .5f;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.type = @
"oglFlip"
;
AVCaptureDevice *newCamera = nil;
AVCaptureDeviceInput *newInput = nil;
//拿到另外一个摄像头位置
AVCaptureDevicePosition position = [[_input device] position];
if
(position == AVCaptureDevicePositionFront){
newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];
animation.subtype = kCATransitionFromLeft;
//动画翻转方向
}
else
{
newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];
animation.subtype = kCATransitionFromRight;
//动画翻转方向
}
//生成新的输入
newInput = [AVCaptureDeviceInput deviceInputWithDevice:newCamera error:nil];
[self.previewLayer addAnimation:animation forKey:nil];
if
(newInput != nil) {
[self.session beginConfiguration];
[self.session removeInput:self.input];
if
([self.session canAddInput:newInput]) {
[self.session addInput:newInput];
self.input = newInput;
}
else
{
[self.session addInput:self.input];
}
[self.session commitConfiguration];
}
else
if
(error) {
NSLog(@
"toggle carema failed, error = %@"
, error);
}
}
}
|
6、相机的其它参数设置 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
//AVCaptureFlashMode 闪光灯
//AVCaptureFocusMode 对焦
//AVCaptureExposureMode 曝光
//AVCaptureWhiteBalanceMode 白平衡
//闪光灯和白平衡可以在生成相机时候设置
//曝光要根据对焦点的光线状况而决定,所以和对焦一块写
//point为点击的位置
- (
void
)focusAtPoint:(CGPoint)point{
CGSize size = self.view.bounds.size;
CGPoint focusPoint = CGPointMake( point.y /size.height ,1-point.x/size.width );
NSError *error;
if
([self.device lockForConfiguration:&error]) {
//对焦模式和对焦点
if
([self.device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
[self.device setFocusPointOfInterest:focusPoint];
[self.device setFocusMode:AVCaptureFocusModeAutoFocus];
}
//曝光模式和曝光点
if
([self.device isExposureModeSupported:AVCaptureExposureModeAutoExpose ]) {
[self.device setExposurePointOfInterest:focusPoint];
[self.device setExposureMode:AVCaptureExposureModeAutoExpose];
}
[self.device unlockForConfiguration];
//设置对焦动画
_focusView.center = point;
_focusView.hidden = NO;
[UIView animateWithDuration:0.3 animations:^{
_focusView.transform = CGAffineTransformMakeScale(1.25, 1.25);
}completion:^(
BOOL
finished) {
[UIView animateWithDuration:0.5 animations:^{
_focusView.transform = CGAffineTransformIdentity;
} completion:^(
BOOL
finished) {
_focusView.hidden = YES;
}];
}];
}
}
|
7、遇到的一些坑和解决办法 。
1) 前后置摄像头的切换 。
前后值不能切换,各种尝试找了半天没找到有原因。后来发现我在设置图片尺寸的时候设置为1080P [self.session canSetSessionPreset: AVCaptureSessionPreset1920x1080] ,前置摄像头并不支持这么大的尺寸,所以就不能切换前置摄像头。我验证了下 前置摄像头最高支持720P,720P以内可自由切换。 。
当然也可以在前后置摄像头切换的时候,根据前后摄像头来设置不同的尺寸,这里不在赘述.
2)焦点位置 。
CGPoint focusPoint = CGPointMake( point.y /size.height ,1-point.x/size.width ); setExposurePointOfInterest:focusPoint 函数后面Point取值范围是取景框左上角(0,0)到取景框右下角(1,1)之间。官方是这么写的:
The value of this property is a CGPoint that determines the receiver's focus point of interest, if it has one. A value of (0,0) indicates that the camera should focus on the top left corner of the image, while a value of (1,1) indicates that it should focus on the bottom right. The default value is (0.5,0.5). 。
我也试了按这个来但位置就是不对,只能按上面的写法才可以。前面是点击位置的y/PreviewLayer的高度,后面是1-点击位置的x/PreviewLayer的宽度 。
3)对焦和曝光 。
我在设置对焦是 先设置了模式setFocusMode,后设置对焦位置,就会导致很奇怪的现象,对焦位置是你上次点击的位置。所以一定要先设置位置,再设置对焦模式。 曝光同上 。
8、写在最后 。
附上demo:photographDemo 。
常用到的基本就这么多,写的并不完善,有什么不对的,欢迎大家批评指正,共同学习.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
原文链接:https://blog.csdn.net/vkooy/article/details/60867268 。
最后此篇关于iOS开发技巧之自定义相机的文章就讲到这里了,如果你想了解更多关于iOS开发技巧之自定义相机的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
好的,所以我编辑了以下... 只需将以下内容放入我的 custom.css #rt-utility .rt-block {CODE HERE} 但是当我尝试改变... 与 #rt-sideslid
在表格 View 中,我有一个自定义单元格(在界面生成器中高度为 500)。在该单元格中,我有一个 Collection View ,我按 (10,10,10,10) 固定到边缘。但是在 tablev
对于我的无能,我很抱歉,但总的来说,我对 Cocoa、Swift 和面向对象编程还很陌生。我的主要来源是《Cocoa Programming for OS X》(第 5 版),以及 Apple 的充满
我正在使用 meta-tegra 为我的 NVIDIA Jetson Nano 构建自定义图像。我需要 PyTorch,但没有它的配方。我在设备上构建了 PyTorch,并将其打包到设备上的轮子中。现
在 jquery 中使用 $.POST 和 $.GET 时,有没有办法将自定义变量添加到 URL 并发送它们?我尝试了以下方法: $.ajax({type:"POST", url:"file.php?
Traefik 已经默认实现了很多中间件,可以满足大部分我们日常的需求,但是在实际工作中,用户仍然还是有自定义中间件的需求,为解决这个问题,官方推出了一个 Traefik Pilot[1] 的功
我想让我的 CustomTextInputLayout 将 Widget.MaterialComponents.TextInputLayout.OutlinedBox 作为默认样式,无需在 XML 中
我在 ~/.emacs 中有以下自定义函数: (defun xi-rgrep (term) (grep-compute-defaults) (interactive "sSearch Te
我有下表: 考虑到每个月的权重,我的目标是在 5 个月内分散 10,000 个单位。与 10,000 相邻的行是我最好的尝试(我在这上面花了几个小时)。黄色是我所追求的。 我试图用来计算的逻辑如下:计
我的表单中有一个字段,它是文件类型。当用户点击保存图标时,我想自然地将文件上传到服务器并将文件名保存在数据库中。我尝试通过回显文件名来测试它,但它似乎不起作用。另外,如何将文件名添加到数据库中?是在模
我有一个 python 脚本来发送电子邮件,它工作得很好,但问题是当我检查我的电子邮件收件箱时。 我希望该用户名是自定义用户名,而不是整个电子邮件地址。 最佳答案 发件人地址应该使用的格式是: You
我想减小 ggcorrplot 中标记的大小,并减少文本和绘图之间的空间。 library(ggcorrplot) data(mtcars) corr <- round(cor(mtcars), 1)
GTK+ noob 问题在这里: 是否可以自定义 GtkFileChooserButton 或 GtkFileChooserDialog 以删除“位置”部分(左侧)和顶部的“位置”输入框? 我实际上要
我正在尝试在主页上使用 ajax 在 magento 中使用 ajax 显示流行的产品列表,我可以为 5 或“N”个产品执行此操作,但我想要的是将分页工具栏与结果集一起添加. 这是我添加的以显示流行产
我正在尝试使用 PasswordResetForm 内置函数。 由于我想要自定义表单字段,因此我编写了自己的表单: class FpasswordForm(PasswordResetForm):
据我了解,新的 Angular 7 提供了拖放功能。我搜索了有关 DnD 的 Tree 组件,但没有找到与树相关的内容。 我在 Stackblitz 上找到的一个工作示例.对比drag'ndrop功能
我必须开发一个自定义选项卡控件并决定使用 WPF/XAML 创建它,因为我无论如何都打算学习它。完成后应该是这样的: 到目前为止,我取得了很好的进展,但还有两个问题: 只有第一个/最后一个标签项应该有
我要定制xtable用于导出到 LaTeX。我知道有些问题是关于 xtable在这里,但我找不到我要找的具体东西。 以下是我的表的外观示例: my.table <- data.frame(Specif
用ejs在这里显示日期 它给我结果 Tue Feb 02 2016 16:02:24 GMT+0530 (IST) 但是我需要表现为 19th January, 2016 如何在ejs中执行此操作?
我想问在 JavaFX 中使用自定义对象制作 ListView 的最佳方法,我想要一个每个项目如下所示的列表: 我搜了一下,发现大部分人都是用细胞工厂的方法来做的。有没有其他办法?例如使用客户 fxm
我是一名优秀的程序员,十分优秀!