今天無(wú)意翻到了人臉識(shí)別,突然想在ios設(shè)備上實(shí)現(xiàn),這里我們主要用到了幾個(gè)類:CIContext瑰艘,CIDetector
CIContext
CIContext 是Core Image的一個(gè)對(duì)象窘行,Core Image是一個(gè)OS X和iOS的圖像處理框架。通過(guò)它Core Image可以繪制一個(gè)CIFilter產(chǎn)生的結(jié)果端考。一個(gè)Core Image Context可以基于CPU或GPU雅潭。
CIDetector
Core Image 已經(jīng)提供了 CIDetector 類。用它來(lái)做人臉檢測(cè)已經(jīng)相當(dāng)好了却特,并且它已經(jīng)被優(yōu)化過(guò)扶供,使用起來(lái)也很容易:
CIDetector *faceDetector = [CIDetector detectorOfType:CIDetectorTypeFace context:context options:@{CIDetectorAccuracy: CIDetectorAccuracyHigh}];NSArray *faces = [faceDetector featuresInImage:image];
從該圖片中檢測(cè)到的每一張面孔都在數(shù)組 faces 中保存著一個(gè) CIFaceFeature 實(shí)例。這個(gè)實(shí)例中保存著這張面孔的所處的位置和寬高裂明,除此之外椿浓,眼睛和嘴的位置也是可選的。
@interface CIFaceFeature : CIFeature
{
CGRect bounds;
BOOL hasLeftEyePosition;
CGPoint leftEyePosition;
BOOL hasRightEyePosition;
CGPoint rightEyePosition;
BOOL hasMouthPosition;
CGPoint mouthPosition;
BOOL hasTrackingID;
int trackingID;
BOOL hasTrackingFrameCount;
int trackingFrameCount;
BOOL hasFaceAngle;
float faceAngle;
BOOL hasSmile;
BOOL leftEyeClosed;
BOOL rightEyeClosed;
}
人臉監(jiān)測(cè)的步驟是:先獲取圖像,然后轉(zhuǎn)成CIImage格式扳碍,利用CIFeature特征提岔,使用探測(cè)器CIDetector拿到所有的人臉,然后在圖中圈出左腔,即可達(dá)到人臉識(shí)別的目的唧垦,關(guān)鍵代碼如下:
//獲取圖片
UIImage *image = self.imageview.image;
//轉(zhuǎn)成CIImage
CIImage *ciImage = [CIImage imageWithCGImage:image.CGImage];
//拿到所有的臉
NSArray <CIFeature *> *featureArray = [self.detector featuresInImage:ciImage];
if (featureArray.count == 0) {
NSLog(@"未檢測(cè)到人臉");
//初始化提示框;
UIAlertController *alert1 = [UIAlertController alertControllerWithTitle:@"提示" message:@"未檢測(cè)到人臉" preferredStyle: UIAlertControllerStyleAlert];
[alert1 addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action){
//點(diǎn)擊按鈕的響應(yīng)事件;
}]];
//彈出提示框;
[self presentViewController:alert1 animated:true completion:nil];
}else{
//遍歷
for (CIFeature *feature in featureArray){
//將image沿y軸對(duì)稱
CGAffineTransform transform = CGAffineTransformScale(CGAffineTransformIdentity, 1, -1);
//將image往上移動(dòng)
CGFloat imageH = ciImage.extent.size.height;
transform = CGAffineTransformTranslate(transform, 0, -imageH);
//在image上畫出方框
CGRect feaRect = feature.bounds;
//調(diào)整后的坐標(biāo)
CGRect newFeaRect = CGRectApplyAffineTransform(feaRect, transform);
//調(diào)整imageView的frame
CGFloat imageViewW = self.imageview.bounds.size.width;
CGFloat imageViewH = self.imageview.bounds.size.height;
CGFloat imageW = ciImage.extent.size.width;
//顯示
CGFloat scale = MIN(imageViewH / imageH, imageViewW / imageW);
//縮放
CGAffineTransform scaleTransform = CGAffineTransformMakeScale(scale, scale);
//修正
newFeaRect = CGRectApplyAffineTransform(newFeaRect, scaleTransform);
newFeaRect.origin.x += (imageViewW - imageW * scale ) / 2;
newFeaRect.origin.y += (imageViewH - imageH * scale ) / 2;
NSLog(@"xxx:%f",newFeaRect.origin.x);
//繪畫
UIView *breageView = [[UIView alloc] initWithFrame:newFeaRect];
breageView.layer.borderColor = [UIColor redColor].CGColor;
breageView.layer.borderWidth = 2;
[self.imageview addSubview:breageView];
}
}
上述圖像載入的時(shí)候,采用了一個(gè)用戶頭像上傳的demo液样,順道一起研究了振亮,選取圖像可以選擇兩種途徑,第一種是拍照識(shí)別鞭莽,第二種從個(gè)人相冊(cè)中載入坊秸,并且將載入后的圖像寫入沙盒中。
選取圖像
@property(nonatomic,strong) UIPopoverController *imagePickerPopover; //
需要注意的是 UIPopoverController 澎怒,是iPad開(kāi)發(fā)中常見(jiàn)的一種控制器(在iPhone上不允許使用)
跟其他控制器不一樣的是褒搔,它直接繼承自NSObject,并非繼承自UIViewController
它只占用部分屏幕空間來(lái)呈現(xiàn)信息喷面,而且顯示在屏幕的最前面星瘾,但是在IOS9的時(shí)候已經(jīng)被廢除。
可以選用IOS8提供的新特性 UIPresentationController惧辈,UIPresentationController是提供高級(jí)視圖切換的類琳状。它讓管理present ViewController的過(guò)程變得簡(jiǎn)單。
在iPad的設(shè)置頁(yè)面盒齿,可以通過(guò)popOver彈出一個(gè)UIViewController念逞,這個(gè)彈出的,可以和用戶交互的Controller叫做PresentedViewController边翁,而后面那個(gè)被部分遮擋的UIViewController叫做PresentingViewController翎承,而在UIPresentationController中,PresentedViewController是presentation的content符匾,而PresentingViewController叫做Chrome叨咖。
UIPopoverPresentationController
它在iOS8中替代了UIPopoverController,它在功能上與舊的controller完全等同啊胶,并且新增了一些內(nèi)置的適配特性芒澜,可以自動(dòng)適配iPad與iPhone。以下是新版與舊版接口的比較:UIPopoverController使用方法:
UIViewController *contentController = [[UIViewController alloc] init];
UIPopoverController *poc = [UIPopoverController alloc] initWithContentViewController:contentController];
[poc presentPopoverFromBarButtonItem:item permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
但是這個(gè)是ipad的類创淡,如果要?jiǎng)?chuàng)建一個(gè)在iPad與iPhone上通用的方法痴晦,那么需要以下的代碼:
UIViewController *contentController = [[UIViewController alloc] init];
if([[UIDevice currentDevice] userInterfaceIdim] == UIUserInterfaceIdiomPad){
UIPopoverController *poc = [UIPopoverController alloc] initWithContentViewController:contentController];
[poc presentPopoverFromBarButtonItem:item permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}else{
[self presentViewController:contentController animated:YES completion:nil];
}
然而我們?nèi)绻褂肬IPopoverPresentationController,那么就不再需要判斷設(shè)備,例如:
UIViewController *contentController = [[UIViewController alloc] init];
UIPopoverPresentationController *popVC = contentController.popoverPresentationController;
popVC.barButtonItem = item;
popVC.permittedArrowDirections = UIPopoverArrowDirectionAny;
popVC.delegate = self;
[self presentViewController:contentController animated:YES completion:nil];
- 將UIViewController的modalPresentationStyle設(shè)置成UIModalPresentationPopover琳彩,這個(gè)值用來(lái)實(shí)現(xiàn)popover效果誊酌,并且各個(gè)平臺(tái)自動(dòng)適應(yīng)部凑。第二行中,通過(guò)popoverPresentationController屬性來(lái)獲取它的popoverPresentationController碧浊,而不是創(chuàng)建一個(gè)新的涂邀。然后設(shè)置它的一些界面屬性,最后調(diào)用presentViewController方法來(lái)顯示這個(gè)controller箱锐。這樣就可以在iPad與iPhone顯示自動(dòng)適應(yīng)的popover效果了比勉。
其中,iPhone上的自適應(yīng)是在delegate中實(shí)現(xiàn)的:
- (UIModalPresentationStyle)adaptivePresentationStyleForPresemtatopmController:(UIPresentationController * controller)
{
return UIModalPresentationFullScreen;
}
- (UIViewController *)presentationController:(UIPresentationController *)controller viewControllerForAdaptivePresentationStyle:(UIModalPresentationStyle)style
{
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller.presentedViewController];
return navController;
}
-
UIImagePickerController
UIImagePickerController 是系統(tǒng)提供的用來(lái)獲取圖片和視頻的接口,用UIImagePickerController 類來(lái)獲取圖片視頻驹止,大體分為以下幾個(gè)步驟:
- 初始化UIImagePickerController 類浩聋;
- 設(shè)置UIImagePickerController 實(shí)例的數(shù)據(jù)來(lái)源類型;
- 設(shè)置設(shè)置代理臊恋;
- 如果需要做圖片修改的話設(shè)置allowsEditing =yes衣洁。
數(shù)據(jù)來(lái)源類型一共有三種:
enum {
UIImagePickerControllerSourceTypePhotoLibrary ,//來(lái)自圖庫(kù)
UIImagePickerControllerSourceTypeCamera ,//來(lái)自相機(jī)
UIImagePickerControllerSourceTypeSavedPhotosAlbum //來(lái)自相冊(cè)
};
在用這些來(lái)源的時(shí)候最好檢測(cè)以下設(shè)備是否支持;
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
NSLog(@"支持相機(jī)");
}
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary])
{
NSLog(@"支持圖庫(kù)");
}
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeSavedPhotosAlbum])
{
NSLog(@"支持相片庫(kù)");
}
調(diào)用攝像頭來(lái)獲取資源
- (void)viewDidLoad {
[super viewDidLoad];
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker = [[UIImagePickerController alloc]init];
picker.view.backgroundColor = [UIColor orangeColor];
UIImagePickerControllerSourceType sourcheType = UIImagePickerControllerSourceTypeCamera;
picker.sourceType = sourcheType;
picker.delegate = self;
picker.allowsEditing = YES;
}
上面只是實(shí)例了UIImagePickerController及其屬性 在需要獲取圖片的時(shí)候需要彈出窗口調(diào)用
[self presentViewController:picker animated:YES completion:nil];
完整的選取相冊(cè)代碼如下:
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"請(qǐng)選擇打開(kāi)方式" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
[alert addAction:[UIAlertAction actionWithTitle:@"打開(kāi)相機(jī)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action){
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
//創(chuàng)建UIPopoverController對(duì)象前先檢查當(dāng)前設(shè)備是不是ipad
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
self.imagePickerPopover = [[UIPopoverController alloc] initWithContentViewController:imagePicker];
self.imagePickerPopover.delegate = self;
[self.imagePickerPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}else{
[self presentViewController:imagePicker animated:YES completion:nil];
}
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"我的相冊(cè)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action){
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
//創(chuàng)建UIPopoverController對(duì)象前先檢查當(dāng)前設(shè)備是不是ipad
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
self.imagePickerPopover = [[UIPopoverController alloc] initWithContentViewController:imagePicker];
self.imagePickerPopover.delegate = self;
[self.imagePickerPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}else{
[self presentViewController:imagePicker animated:YES completion:nil];
}
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *_Nonnull action){
//取消
}]];
//彈出提示框
[self presentViewController:alert animated:YES completion:nil];
本文從人臉識(shí)別出發(fā)抖仅,記錄了ios設(shè)備進(jìn)行人臉識(shí)別時(shí)坊夫,使用的CIDetector類,順帶溫習(xí)了一下拉起相冊(cè)的相關(guān)知識(shí)撤卢,由UIPopoverController到UIPresentationController环凿,詳細(xì)記錄。