UIImagePickerController
UIImagePickerController
類用于管理可定制的忱详,基于系統(tǒng)支持的用戶界面,用于在支持的設(shè)備上拍攝照片和視頻,并且在你的 app 中為用戶保存照片和視頻匣吊。 圖像選擇器控制器管理用戶交互并將這些交互的結(jié)果傳遞給委托對(duì)象。
UIImagePickerController
繼承于 UINavigationController
,歸屬于 UIKit
框架色鸳,可以實(shí)現(xiàn)圖片選取社痛、拍照、錄制視頻等功能命雀,使用起來十分方便蒜哀。
使用方式
需要導(dǎo)入框架:import <MobileCoreServices/MobileCoreServices.h>
;
拍攝視頻需要導(dǎo)入包:#import <AssetsLibrary/AssetsLibrary.h>
需要遵循的協(xié)議:<UINavigationControllerDelegate
,UIImagePickerControllerDelegate>
;
注:需要導(dǎo)入 <MobileCoreServices/MobileCoreServices.h>
框架是因?yàn)?kUTTypeImage
和 kUTTypeMovie
被定義在其中吏砂。
注:實(shí)際上我們不會(huì)實(shí)現(xiàn) UINavigationControllerDelegate
中定義的任何協(xié)議方法撵儿,但由于 UIImagePickerController
繼承自 UINavigationController
,并且改變了 UINavigationController
的行為狐血。因此淀歇,我們?nèi)匀恍枰鲃?dòng)聲明我們的視圖控制器遵守 UINavigationControllerDelegate
協(xié)議。
1. 創(chuàng)建 UIImagePickerController 圖片選擇器對(duì)象
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
2. 設(shè)置 sourceType 媒體數(shù)據(jù)源類型
UIImagePickerControllerSourceType
是一個(gè)枚舉類型匈织,用于設(shè)置要跳轉(zhuǎn)到哪個(gè)界面(相機(jī)拍照浪默、照片圖庫、相冊(cè)) :
typedef NS_ENUM(NSInteger, UIImagePickerControllerSourceType) {
UIImagePickerControllerSourceTypePhotoLibrary API_DEPRECATED("Will be removed in a future release, use PHPicker.", ios(2, API_TO_BE_DEPRECATED)), // 照片庫
UIImagePickerControllerSourceTypeCamera, // 系統(tǒng)內(nèi)置像機(jī)
UIImagePickerControllerSourceTypeSavedPhotosAlbum API_DEPRECATED("Will be removed in a future release, use PHPicker.", ios(2, API_TO_BE_DEPRECATED)), // 相冊(cè)
} API_UNAVAILABLE(tvos);
?? 查看 Apple 的源碼可以發(fā)現(xiàn)缀匕,部分類型已經(jīng)被標(biāo)注為 API_DEPRECATED纳决,意味著該屬性即將被廢棄,推薦使用 PHPicker 代替乡小。
設(shè)置示例:
// 驗(yàn)證設(shè)備是否能夠從所需的來源獲取內(nèi)容
BOOL isSourceTypeAvailable = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera];
if (!isSourceTypeAvailable) {
// 可能是權(quán)限未打開阔加,也可能是手機(jī)硬件不支持相機(jī)功能。
NSLog(@"啟動(dòng)相機(jī)失敗,您的相機(jī)功能未開啟满钟,請(qǐng)轉(zhuǎn)到手機(jī)設(shè)置中開啟相機(jī)權(quán)限!");
}else{
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
}
3. 設(shè)置攝像頭捕捉模式
如果設(shè)置了 sourceType
媒體數(shù)據(jù)源類型為 UIImagePickerControllerSourceTypeCamera
掸哑,那你還需要設(shè)置是打開相機(jī)的拍照還是錄制視頻功能。
UIImagePickerControllerCameraCaptureMode
是一個(gè)枚舉類型:
UIImagePickerControllerCameraCaptureModePhoto, // 拍照模式零远,默認(rèn)
UIImagePickerControllerCameraCaptureModeVideo // 視頻錄制模式
拍攝圖片:
// 設(shè)定拍攝的媒體類型:圖片
imagePicker.mediaTypes = @[(NSString *)kUTTypeImage];
// 設(shè)置攝像頭捕捉模式為捕捉圖片苗分,默認(rèn)
imagePicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
拍攝視頻:
// 設(shè)定拍攝的媒體類型:視頻
imagePicker.mediaTypes = @[(NSString *)kUTTypeMovie];
// 設(shè)置攝像頭捕捉模式為捕捉視頻
imagePicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
4. 攝像頭設(shè)備
UIImagePickerControllerCameraDevice
是一個(gè)枚舉類型,代表前置/后置攝像頭:
UIImagePickerControllerCameraDeviceRear, //后置攝像頭牵辣,默認(rèn)
UIImagePickerControllerCameraDeviceFront //前置攝像頭
設(shè)置示例:
// 設(shè)置前置攝像頭
if ([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront]) {
imagePicker.cameraDevice = UIImagePickerControllerCameraDeviceFront;
}
5. 設(shè)置錄制視頻質(zhì)量
UIImagePickerControllerQualityType
是一個(gè)枚舉類型摔癣,設(shè)置返回圖片的質(zhì)量:
UIImagePickerControllerQualityTypeHigh // 高清
UIImagePickerControllerQualityTypeMedium // 中等,適合 WiFi 傳輸
UIImagePickerControllerQualityTypeLow // 低質(zhì)量纬向,適合蜂窩網(wǎng)傳輸
UIImagePickerControllerQualityType640x480 // VGA 質(zhì)量择浊,640*480
UIImagePickerControllerQualityTypeIFrame1280x720 // 1280*720
UIImagePickerControllerQualityTypeIFrame960x540 // 960*540
設(shè)置示例:
imagePicker.videoQuality = UIImagePickerControllerQualityTypeLow;
6. 設(shè)置閃光燈模式
在調(diào)用攝像頭的時(shí)候我們可以選擇使用閃光燈,但是默認(rèn)條件下對(duì)視頻有 10 分鐘的限制逾条,需要用 videoMaximumDuration
屬性更改默認(rèn)時(shí)間琢岩。
UIImagePickerControllerCameraFlashMode
是一個(gè)枚舉類型,用于設(shè)置閃光燈關(guān)閉师脂、自動(dòng)担孔、打開江锨。
UIImagePickerControllerCameraFlashModeOff = -1,
UIImagePickerControllerCameraFlashModeAuto = 0,默認(rèn)
UIImagePickerControllerCameraFlashModeOn = 1
設(shè)置示例:
imagePicker.cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto
7. 遵循協(xié)議
imagePicker.delegate = self;
8. 是否顯示系統(tǒng)自帶的攝像頭控制面板,默認(rèn)YES
// 顯示標(biāo)準(zhǔn)相機(jī) UI糕篇,
imagePicker.showsCameraControls = NO;
9. 設(shè)置自定義覆蓋圖層
UIImageView *overlayImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
overlayImageView.image = [UIImage imageNamed:@"circle3.png"];
UIView *cameraOverlay = overlayImageView;
imagePicker.cameraOverlayView = cameraOverlay
10. 以模態(tài)形式顯示 UIImagePickerController 對(duì)象
[self presentViewController:imagePicker animated:YES completion:nil];
11. 遵守并實(shí)現(xiàn) UIImagePickerControllerDelegate 協(xié)議中的方法
你需要關(guān)注協(xié)議中的這兩個(gè)方法:
// 媒體項(xiàng)(圖片或視頻)選擇完成后調(diào)用
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info;
// 取消選擇媒體項(xiàng)調(diào)用
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker;
擴(kuò)展函數(shù)啄育,用于保存到相簿:
/* 保存圖片到相簿 */
void UIImageWriteToSavedPhotosAlbum(
UIImage *image,//保存的圖片UIImage
id completionTarget,//回調(diào)的執(zhí)行者
SEL completionSelector, //回調(diào)方法
void *contextInfo//回調(diào)參數(shù)信息
);
//上面一般保存圖片的回調(diào)方法為:
- (void)image:(UIImage *)image
didFinishSavingWithError:(NSError *)error
contextInfo:(void *)contextInfo;
/* 判斷是否能保存視頻到相簿 */
BOOL UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(NSString *videoPath);
/* 保存視頻到相簿 */
void UISaveVideoAtPathToSavedPhotosAlbum(
NSString *videoPath, //保存的視頻文件路徑
id completionTarget, //回調(diào)的執(zhí)行者
SEL completionSelector,//回調(diào)方法
void *contextInfo//回調(diào)參數(shù)信息
);
//上面一般保存視頻的回調(diào)方法為:
- (void)video:(NSString *)videoPath
didFinishSavingWithError:(NSError *)error
contextInfo:(void *)contextInfo;
示例代碼:
#pragma mark - 完成選擇圖片
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
NSLog(@"%s",__func__);
// 從info取出此時(shí)攝像頭的媒體類型
NSString *mediaType = info[UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
// 【拍照模式】
// 通過info字典獲取選擇的照片
UIImage *image = info[UIImagePickerControllerOriginalImage];
// 將照片放入U(xiǎn)IImageView對(duì)象顯示在UI界面
self.imageView.image = image;
// 保存圖像到相簿
UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}else if ([mediaType isEqualToString:(NSString *)kUTTypeMovie]) {
// 【錄像模式】
NSURL *url = info[UIImagePickerControllerMediaURL];
NSString *path = url.path;
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(path)) {
// 保存視頻到相簿
UISaveVideoAtPathToSavedPhotosAlbum(path, self, @selector(video:didFinishSavingWithError:contextInfo:), nil);
}
}
// 關(guān)閉UIImagePickerController對(duì)象
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark 取消拍照
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
NSLog(@"%s",__func__);
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - 保存圖像或視頻完成的回調(diào)
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
NSLog(@"保存圖片完成");
}
- (void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
NSLog(@"保存視頻完成");
}
封裝使用
VideoCaptureDemo 中將 UIImagePickerController 封裝成了一個(gè)Object 類使用,可以參考:
IDImagePickerCoordinator.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
/**
圖片選擇協(xié)調(diào)器
*/
@interface IDImagePickerCoordinator : NSObject
#pragma mark - getter 方法
- (UIImagePickerController *)cameraVC;
@end
IDImagePickerCoordinator.m
#import "IDImagePickerCoordinator.h"
#import <MobileCoreServices/MobileCoreServices.h>
#import <AssetsLibrary/AssetsLibrary.h>
@interface IDImagePickerCoordinator () <UINavigationControllerDelegate, UIImagePickerControllerDelegate>
@property (nonatomic, strong) UIImagePickerController *camera;
@end
@implementation IDImagePickerCoordinator
#pragma mark - Init methods
- (instancetype)init
{
self = [super init];
if(self){
_camera = [self setupImagePicker];
}
return self;
}
- (UIImagePickerController *)cameraVC
{
return _camera;
}
#pragma mark - Private methods
- (UIImagePickerController *)setupImagePicker
{
UIImagePickerController *camera;
if([self isVideoRecordingAvailable]){
camera = [UIImagePickerController new];
camera.sourceType = UIImagePickerControllerSourceTypeCamera;
camera.mediaTypes = @[(NSString *)kUTTypeMovie];
camera.delegate = self;
}
return camera;
}
- (BOOL)isVideoRecordingAvailable
{
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){
NSArray *availableMediaTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];
if([availableMediaTypes containsObject:(NSString *)kUTTypeMovie]){
return YES;
}
}
return NO;
}
- (BOOL)setFrontFacingCameraOnImagePicker:(UIImagePickerController *)picker
{
if([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront]){
[picker setCameraDevice:UIImagePickerControllerCameraDeviceFront];
return YES;
}
return NO;
}
- (void)configureCustomUIOnImagePicker:(UIImagePickerController *)picker
{
UIView *cameraOverlay = [[UIView alloc] init];
picker.showsCameraControls = NO;
picker.cameraOverlayView = cameraOverlay;
}
#pragma mark - UIImagePickerControllerDelegate methods
// 完成選擇圖片
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(nullable NSDictionary<NSString *,id> *)editingInfo NS_DEPRECATED_IOS(2_0, 3_0) {
}
// 完成選擇視頻
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
NSURL *recordedVideoURL= [info objectForKey:UIImagePickerControllerMediaURL];
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:recordedVideoURL]) {
[library writeVideoAtPathToSavedPhotosAlbum:recordedVideoURL
completionBlock:^(NSURL *assetURL, NSError *error){}
];
}
[picker dismissViewControllerAnimated:YES completion:nil];
}
// 取消選擇
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[picker dismissViewControllerAnimated:YES completion:nil];
}
@end
使用時(shí)先導(dǎo)入頭文件拌消,設(shè)置屬性:
@property (nonatomic, strong) IDImagePickerCoordinator *imagePickerCoordinator;
再調(diào)用:
self.imagePickerCoordinator = [IDImagePickerCoordinator new];
[self presentViewController:[_imagePickerCoordinator cameraVC] animated:YES completion:nil];
AVFoundation
HQLAVFoundationViewController.h
#import <UIKit/UIKit.h>
/**
使用AVFoundation類拍照
*/
@interface HQLAVFoundationViewController : UIViewController
@end
HQLAVFoundationViewController.m
#import "HQLAVFoundationViewController.h"
#import <AVFoundation/AVFoundation.h>
#define ThemeColor [UIColor colorWithDisplayP3Red:81/255.0 green:136/255.0 blue:247/255.0 alpha:1.0]
@interface HQLAVFoundationViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UIButton *openCaptureBtn;
@property (weak, nonatomic) IBOutlet UIButton *canptureBtn;
@property (strong, nonatomic) AVCaptureSession *session; //媒體管理會(huì)話
@property (strong, nonatomic) AVCaptureDeviceInput *captureInput; //輸入數(shù)據(jù)對(duì)象
@property (strong, nonatomic) AVCaptureStillImageOutput *imageOutput; //輸出數(shù)據(jù)對(duì)象
@property (strong, nonatomic) AVCaptureVideoPreviewLayer *captureLayer; //視頻預(yù)覽圖層
@end
@implementation HQLAVFoundationViewController
#pragma mark - Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[self setNavigationControllerAppearance];
// 初始化攝像頭
[self initCaptureSession];
self.openCaptureBtn.hidden = NO;
self.canptureBtn.hidden = YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Custom Accessors
- (void)setNavigationControllerAppearance {
// 設(shè)置導(dǎo)航欄標(biāo)題&字體&顏色
self.navigationItem.title = @"AVFoundation拍照";
[self.navigationController.navigationBar setTitleTextAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:17],NSForegroundColorAttributeName:ThemeColor}];
}
#pragma mark 初始化攝像頭
- (void)initCaptureSession {
/*
1?? AVCaptureSession
媒體捕捉會(huì)話挑豌,管理輸入與輸出之間的數(shù)據(jù)流,以及在出現(xiàn)問題時(shí)生成運(yùn)行時(shí)錯(cuò)誤墩崩。
負(fù)責(zé)把捕獲到的音頻視頻數(shù)據(jù)輸出到輸出設(shè)備上氓英,一個(gè)會(huì)話可以有多個(gè)輸入輸入。
*/
// 1.創(chuàng)建媒體管理會(huì)話
AVCaptureSession *captureSession = [[AVCaptureSession alloc] init];
self.session = captureSession;
// 判斷分辨率是否支持 1280*720鹦筹,支持就設(shè)置為:1280*720
if ([captureSession canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
captureSession.sessionPreset = AVCaptureSessionPreset1280x720;
}
/*
2?? AVCaptureDevice
關(guān)于相機(jī)硬件的接口债蓝。它被用于控制硬件特性,諸如鏡頭的位置盛龄、曝光饰迹、閃光燈等。
*/
// 2.獲取后置攝像頭
AVCaptureDevice *captureDevice = nil;
NSArray *cameras = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for (AVCaptureDevice *camera in cameras) {
if (camera.position == AVCaptureDevicePositionBack) {
// 獲得后置攝像頭
captureDevice = camera;
}
}
if (!captureDevice) {
NSLog(@"2.取得后置攝像頭錯(cuò)誤余舶!");
return;
}
// 取得前置攝像頭
// AVCaptureDevice *frontCaptureDevice = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInWideAngleCamera mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionFront];
/*
3?? AVCaptureDeviceInput
設(shè)備輸入數(shù)據(jù)管理對(duì)象啊鸭,管理輸入數(shù)據(jù)
*/
// 3.創(chuàng)建輸入數(shù)據(jù)對(duì)象
NSError *error = nil;
AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
if (error) {
NSLog(@"3.創(chuàng)建輸入數(shù)據(jù)對(duì)象錯(cuò)誤");
return;
}
self.captureInput = captureInput;
/*
4?? AVCaptureOutput
設(shè)備輸出數(shù)據(jù)管理對(duì)象,管理輸出數(shù)據(jù)匿值,通常使用它的子類:
AVCaptureAudioDataOutput //輸出音頻管理對(duì)象赠制,輸出數(shù)據(jù)為NSData
AVCaptureStillImageDataOutput //輸出圖片管理對(duì)象,輸出數(shù)據(jù)為NSData
AVCaptureVideoDataOutput //輸出視頻管理對(duì)象挟憔,輸出數(shù)據(jù)為NSData
AVCaptureFileOutput
輸出文件管理對(duì)象钟些,輸出數(shù)據(jù)以文件形式輸出
{//子類
AVCaptureAudioFileOutput //輸出是音頻文件
AVCaptureMovieFileOutput //輸出是視頻文件
}
*/
// 4.創(chuàng)建輸出數(shù)據(jù)對(duì)象
AVCaptureStillImageOutput *imageOutpot = [[AVCaptureStillImageOutput alloc] init];
NSDictionary *setting = @{
AVVideoCodecKey:AVVideoCodecJPEG
};
[imageOutpot setOutputSettings:setting];
self.imageOutput = imageOutpot;
// 5?? 5.添加【輸入數(shù)據(jù)對(duì)象】和【輸出對(duì)象】到會(huì)話中
if ([captureSession canAddInput:captureInput]) {
[captureSession addInput:captureInput];
}
if ([captureSession canAddOutput:imageOutpot]) {
[captureSession addOutput:imageOutpot];
}
/*
6?? AVCaptureVideoPreviewLayer
實(shí)時(shí)預(yù)覽圖層
AVCaptureVideoPreviewLayer 是 CALayer 的子類,可被用于自動(dòng)顯示相機(jī)產(chǎn)生的實(shí)時(shí)圖像绊谭。它還有幾個(gè)工具性質(zhì)的方法政恍,可將 layer 上的坐標(biāo)轉(zhuǎn)化到設(shè)備上。它看起來像輸出达传,但其實(shí)不是篙耗。另外,它擁有 session (outputs 被 session 所擁有)宪赶。
*/
// 6.創(chuàng)建實(shí)時(shí)預(yù)覽圖層
AVCaptureVideoPreviewLayer *previewlayer = [AVCaptureVideoPreviewLayer layerWithSession:captureSession];
self.view.layer.masksToBounds = YES;
previewlayer.frame = self.view.bounds;
previewlayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
// 【預(yù)覽圖層】插入在【拍照按鈕】的下方
[self.view.layer insertSublayer:previewlayer below:self.canptureBtn.layer];
self.captureLayer = previewlayer;
}
#pragma mark - IBAction
#pragma mark 打開攝像頭
- (IBAction)takePhoto:(UIButton *)sender {
self.captureLayer.hidden = NO;
self.canptureBtn.hidden = NO;
self.openCaptureBtn.hidden = YES;
[self.session startRunning]; //開始捕捉
}
#pragma mark 拍照
- (IBAction)takeMedia:(id)sender {
// 根據(jù)設(shè)備輸出獲得連接
AVCaptureConnection *connection = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
// 通過連接獲得設(shè)備的輸出數(shù)據(jù)
[self.imageOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
// 獲取輸出的JPG圖片
NSData *imgData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [UIImage imageWithData:imgData];
self.imageView.image = image;
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil); //保存到相冊(cè)
self.captureLayer.hidden = YES;
self.canptureBtn.hidden = YES;
self.openCaptureBtn.hidden = NO;
[self.session stopRunning];
}];
}
@end
關(guān)于 AVFoundation 視頻錄制的使用推薦閱讀:ctolib:在 iOS 上捕獲 視頻
以及源碼:VideoCaptureDemo
配合使用 CoreImage 實(shí)現(xiàn)人臉識(shí)別
人臉識(shí)別過程分3個(gè)步驟:
- 首先建立人臉的【面紋數(shù)據(jù)庫】;
- 獲取當(dāng)前人臉面像圖片;
- 用當(dāng)前的面紋編碼與數(shù)據(jù)庫中的面紋編碼進(jìn)行比對(duì)宗弯。
CIDetector 是 CoreImage 中的一個(gè)特征識(shí)別濾鏡。它可以找到圖片中的人臉搂妻,但是是誰無法判斷蒙保,需要數(shù)據(jù)庫。要想識(shí)別可以看 OpenCV 和 Face.com欲主。
#pragma mark - 識(shí)別人臉
/**
識(shí)別人臉?biāo)惴?
@param image 輸入的圖片
*/
- (void)faceDetectWithImage:(UIImage *)image {
NSDictionary *imageOptions = [NSDictionary dictionaryWithObject:@(5) forKey:CIDetectorImageOrientation];
// 將圖像轉(zhuǎn)換為CIImage
CIImage *personciImage = [CIImage imageWithCGImage:image.CGImage];
// 設(shè)置識(shí)別參數(shù)
NSDictionary *opts = [NSDictionary dictionaryWithObject:
CIDetectorAccuracyHigh forKey:CIDetectorAccuracy];
CIContext *context = [CIContext contextWithOptions:nil];
//聲明一個(gè)CIDetector邓厕,并設(shè)定識(shí)別器類型為人臉識(shí)別
CIDetector *faceDetector=[CIDetector detectorOfType:CIDetectorTypeFace context:context options:opts];
// 識(shí)別出人臉數(shù)組
// featuresInImage:方法 識(shí)別器會(huì)找到所給圖像中的人臉逝嚎,最后返回一個(gè)人臉數(shù)組
NSArray *features = [faceDetector featuresInImage:personciImage options:imageOptions];
// 得到圖片的尺寸
CGSize inputImageSize = [personciImage extent].size;
// 利用仿射變換將image沿Y軸對(duì)稱
CGAffineTransform transform = CGAffineTransformScale(CGAffineTransformIdentity, 1, -1);
// 將圖片上移
transform = CGAffineTransformTranslate(transform, 0, -inputImageSize.height);
// 遍歷識(shí)別到的人臉
for (CIFaceFeature *faceFeature in features) {
// 獲取人臉的frame
CGRect faceViewBounds = CGRectApplyAffineTransform(faceFeature.bounds, transform);
CGSize viewSize = _imageView.bounds.size;
CGFloat scale = MIN(viewSize.width / inputImageSize.width,
viewSize.height / inputImageSize.height);
CGFloat offsetX = (viewSize.width - inputImageSize.width * scale) / 2;
CGFloat offsetY = (viewSize.height - inputImageSize.height * scale) / 2;
// 縮放
CGAffineTransform scaleTransform = CGAffineTransformMakeScale(scale, scale);
// 修正
faceViewBounds = CGRectApplyAffineTransform(faceViewBounds, scaleTransform);
faceViewBounds.origin.x += offsetX;
faceViewBounds.origin.y += offsetY;
// 描繪人臉區(qū)域
UIView *faceView = [[UIView alloc] initWithFrame:faceViewBounds];
faceView.layer.borderWidth = 2;
faceView.layer.borderColor = [UIColor redColor].CGColor;
[_imageView addSubview:faceView];
// 判斷是否有左眼位置
if(faceFeature.hasLeftEyePosition){}
// 判斷是否有右眼位置
if(faceFeature.hasRightEyePosition){}
// 判斷是否有嘴位置
if(faceFeature.hasMouthPosition){}
// 判斷是否微笑
if (faceFeature.hasSmile){}
}
// 裁剪識(shí)別到的人臉
if ([features count]>0) {
CIImage *image = [personciImage imageByCroppingToRect:[[features objectAtIndex:0] bounds]];
UIImage *face = [UIImage imageWithCGImage:[context createCGImage:image fromRect:image.extent]];
// 顯示裁剪后的人臉
_imageView.image = face;
NSLog(@"識(shí)別人臉數(shù)::%lu",(unsigned long)[features count]);
}
}
關(guān)于拍照完成后使用人臉識(shí)別并裁剪,顯示的人臉圖片方向自動(dòng)逆時(shí)針旋轉(zhuǎn)90°顯示的問題:
原因:iPhone 默認(rèn)的方向是HOME 鍵位于左邊的方向邑狸,故豎屏情況原始圖像被拍攝后的EXIF方向值是6,被裁剪后方向信息會(huì)被刪除涤妒,置為1单雾。
解決方法:在人像識(shí)別之前先修改圖像的EXIF信息為1,再進(jìn)行人像識(shí)別她紫,CIDetectorImageOrientation 值也需要改為1硅堆。
參考
libfacedetection – ?? 9.8 k,C++ 人臉識(shí)別 包含正面和多視角人臉檢測(cè)兩個(gè)算法.優(yōu)點(diǎn):速度快(OpenCV haar+adaboost的2-3倍), 準(zhǔn)確度高 (FDDB非公開類評(píng)測(cè)排名第二)贿讹,能估計(jì)人臉角度
-
GitHub: PBJVision ?? 1.9 k
iOS Media Capture - 具有觸摸錄制視頻渐逃、慢動(dòng)作和攝影的功能。
PBJVision 是一個(gè)適用于 iOS 的相機(jī)庫民褂,它可以輕松地在你的 iOS 應(yīng)用中集成特殊的捕捉功能茄菊,定制相機(jī)界面。
GitHub: TGCameraViewController:?? 1.4 k-(已不再維護(hù))基于 AVFoundation 的自定義相機(jī)赊堪。樣式漂亮面殖,輕量并且可以很容易地集成到 iOS 項(xiàng)目中。
GitHub: RSKImageCropper ?? 2.3 k-適用于iOS的圖片裁剪器哭廉,類似Contacts app脊僚,可上下左右移動(dòng)圖片選取最合適的區(qū)域