OliveappLivenessDetectionViewController.m 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. //
  2. // ViewController.m
  3. // AnimationTestApp
  4. //
  5. // Created by kychen on 16/12/30.
  6. // Copyright © 2016年 keyu.chen. All rights reserved.
  7. //
  8. #import <Foundation/Foundation.h>
  9. #import "OliveappCameraPreviewController.h"
  10. #import "OliveappViewUpdateEventDelegate.h"
  11. #import "OliveappLivenessDetectionViewController.h"
  12. #import "OliveappVerificationControllerFactory.h"
  13. #import "GifView.h"
  14. #import "OliveappStructLivenessFrameResult.h"
  15. #import "RMDisplayLabel.h"
  16. #import "RMDownloadIndicator.h"
  17. #import "OliveappLivenessDataType.h"
  18. #import "OliveappViewUpdateEventDelegate.h"
  19. #import "LRMacroDefinitionHeader.h"
  20. #import "OliveappApplicationParameter.h"
  21. #import "OliveappTimeUtility.h"
  22. #import "OliveappFileManager.h"
  23. #import "OliveappLivenessDetectionViewController.h"
  24. #import "OliveappDeviceHelper.h"
  25. #import "OliveappEyeLayer.h"
  26. #import "OliveappYellowFrame.h"
  27. #import "OliveappHintView.h"
  28. //#import "ShareData.h"
  29. #import "OliveappLivenessDetectionViewController+Animation.h"
  30. #import <QuartzCore/QuartzCore.h>
  31. #import "OliveappImageUtility.h"
  32. @interface OliveappLivenessDetectionViewController () <AVAudioPlayerDelegate,OliveappViewUpdateEventDelegate,OliveappCameraImageCaptureDelegate>
  33. //UI
  34. @property (weak, nonatomic) IBOutlet UIView * mCameraPreview;
  35. @property (weak, nonatomic) IBOutlet UILabel *mCountDownUILabel;
  36. @property CGSize mScreenSize;
  37. //设备类型和用户设置的屏幕方向
  38. @property OliveappDeviceOrientation mDeviceOrientation;
  39. @property (strong, nonatomic) UIImage * myImage;
  40. //语音播放控制器
  41. @property (strong, nonatomic) AVAudioPlayer * mAudioPlayer;
  42. //结果回调
  43. @property (weak) id<OliveappLivenessResultDelegate> mLivenessResultDelegate;
  44. //摄像头对象
  45. @property (strong) OliveappCameraPreviewController* mCameraController;
  46. //流程控制器
  47. @property VerificationControllerType mVerificationControllerType;
  48. @property (strong) id mVerificationController;
  49. //动作提示语
  50. @property (strong) NSDictionary *mActionHintTextDict;
  51. // 音频对应字典
  52. @property (strong) NSDictionary *mAudioDict;
  53. //定时循环播放声音
  54. @property (strong, nonatomic) NSTimer * mPreTimer;
  55. @property (strong, nonatomic) NSTimer * mAnimationTimer;
  56. @property (strong, nonatomic) NSString * mCurrentVoiceFile;
  57. @property int mCurrentActionType;
  58. @property (strong, nonatomic) NSArray * mLocationArray;
  59. //帧率显示,实际使用时可隐藏
  60. @property (weak, nonatomic) IBOutlet UILabel *mFrameLabel;
  61. //帧数,用于帧率计算
  62. @property int mFrameNumber;
  63. //用于统计帧率的计时器
  64. @property long long mFrameTimer;
  65. //是否处于预检状态
  66. @property BOOL mIsInPrestart;
  67. @end
  68. //时间常量
  69. const int REPEAT_SECOND = 2;
  70. @implementation OliveappLivenessDetectionViewController
  71. //=============================生命周期函数================================//
  72. #pragma 生命周期相关函数
  73. - (void)viewDidLoad {
  74. [super viewDidLoad];
  75. _mDeviceOrientation = [OliveappDeviceHelper getFixedOrientation];
  76. [self initNeededConfig];
  77. [self constructUI];
  78. /**
  79. * 选择verification种类
  80. * WITH_PRESTART: 带有预检模式(推荐)
  81. * WITHOUT_PRESTART:不带预检模式
  82. */
  83. _mVerificationControllerType = WITH_PRESTART;
  84. _mIsInPrestart = (_mVerificationControllerType == WITH_PRESTART) ? YES : NO;
  85. }
  86. - (void) viewWillAppear:(BOOL)animated {
  87. NSLog(@"[BEGIN] LivenessDetectionViewController.viewWillAppear");
  88. [super viewWillAppear:animated];
  89. /**
  90. * 这里设置屏幕分辨率
  91. * 16:9(一般用于iPhone)
  92. * 4:3 (一般用于iPad)
  93. */
  94. if ([OliveappDeviceHelper deviceIsPad]) {
  95. [_mCameraController startCamera:AVCaptureDevicePositionBack
  96. withResolution:AVCaptureSessionPresetPhoto];
  97. } else {
  98. [_mCameraController startCamera:AVCaptureDevicePositionFront
  99. withResolution:AVCaptureSessionPresetHigh];
  100. }
  101. if (_mVerificationControllerType == WITH_PRESTART) {
  102. [self playBackgroundSoundEffect:@"oliveapp_step_hint_prestart"];
  103. }
  104. NSLog(@"[END] LivenessDetectionViewController.viewWillAppear");
  105. }
  106. - (void)viewDidLayoutSubviews {
  107. NSLog(@"[BEGIN][LivenessDetectionViewController] viewDidLayoutSubviews");
  108. [super viewDidLayoutSubviews];
  109. [_mCameraController setupPreview: _mCameraPreview];
  110. NSLog(@"[END][LivenessDetectionViewController] viewDidLayoutSubviews");
  111. }
  112. - (void) viewDidAppear:(BOOL)animated {
  113. NSLog(@"[BEGIN][LivenessDetectionViewController viewDidAppear]");
  114. /**
  115. * 循环播放提示动画
  116. */
  117. _mPreTimer = [NSTimer scheduledTimerWithTimeInterval:REPEAT_SECOND
  118. target:self
  119. selector:@selector(playPreHint)
  120. userInfo:nil
  121. repeats:YES];
  122. if (_mVerificationControllerType == WITH_PRESTART) {
  123. [self playAperture];
  124. }
  125. /**
  126. * 启动活体检测算法
  127. */
  128. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  129. NSError * error;
  130. [self startDetection:&error];
  131. });
  132. NSLog(@"[END][LivenessDetectionViewController viewDidAppear]");
  133. }
  134. - (void)viewWillDisappear:(BOOL)animated {
  135. [_mAudioPlayer stop];
  136. _mAudioPlayer = nil;
  137. [_mPreTimer invalidate];
  138. _mPreTimer = nil;
  139. [_mAnimationTimer invalidate];
  140. _mAnimationTimer = nil;
  141. }
  142. - (void)viewDidDisappear:(BOOL)animated {
  143. NSLog(@"[BEGIN][LivenessDetectionViewController] viewDidDisappear");
  144. [super viewDidDisappear:animated];
  145. [_mCameraController stopCamera];
  146. [_mVerificationController unInit];
  147. _mVerificationController = nil;
  148. [[UIApplication sharedApplication] endIgnoringInteractionEvents];
  149. NSLog(@"[END][LivenessDetectionViewController] viewDidDisappear");
  150. }
  151. - (void)didReceiveMemoryWarning {
  152. [super didReceiveMemoryWarning];
  153. // Dispose of any resources that can be recreated.
  154. }
  155. //=============================设置配置方法================================//
  156. #pragma 设置配置方法
  157. /**
  158. 初始化各种变量
  159. */
  160. - (void)initNeededConfig {
  161. if (_mCameraController == nil) {
  162. _mCameraController = [[OliveappCameraPreviewController alloc] init];
  163. }
  164. NSString *filePath = [[NSBundle bundleForClass:[self class]] pathForResource: @"ActionHintConstants"
  165. ofType: @"plist"];
  166. _mActionHintTextDict = [NSDictionary dictionaryWithContentsOfFile:filePath];
  167. //读取音频plist
  168. NSString *audioConstantsPath = [[NSBundle bundleForClass:[self class]] pathForResource: @"AudioConstants"
  169. ofType: @"plist"];
  170. _mAudioDict = [NSDictionary dictionaryWithContentsOfFile:audioConstantsPath];
  171. _mFrameNumber = 0;
  172. }
  173. #pragma mark -- 活体检测相关
  174. //=============================活检相关方法================================//
  175. - (BOOL) setConfigLivenessDetection: (id<OliveappLivenessResultDelegate>) delegate
  176. withError: (NSError **) error {
  177. // 设置参数
  178. _mLivenessResultDelegate = delegate;
  179. return YES;
  180. }
  181. /**
  182. 启动活体检测的方法
  183. @param error 错误码
  184. */
  185. - (void) startDetection:(NSError **) error {
  186. /**
  187. * 初始化算法对象VerificationController
  188. */
  189. _mVerificationController = [OliveappVerificationControllerFactory create:_mVerificationControllerType];
  190. OliveappSessionManagerConfig* config = [OliveappSessionManagerConfig new];
  191. [config usePredefinedConfig: 0]; // 这里配置检测步骤
  192. config = _cusConfig? : config;
  193. //如果超时时间设置过长,则不显示倒计时
  194. if (config.timeoutMs > 100000) {
  195. [self.mCountDownUILabel setHidden:YES];
  196. }
  197. /**
  198. * 配置算法对象VerificationController
  199. */
  200. __weak typeof(self) weakSelf = self;
  201. [_mVerificationController setConfig:config
  202. withDelegate:weakSelf
  203. withError:error];
  204. /**
  205. * 这里设置了检测人脸框的坐标和宽高,需要根据具体UI配置,详细请参考定制文档
  206. */
  207. // [_mVerificationController setFaceLocation:((_mBlueFrame.center.x - _mBlueFrame.bounds.size.width / 2)/ [UIScreen mainScreen].bounds.size.width)
  208. // withYpercent:((_mBlueFrame.center.y - _mBlueFrame.bounds.size.height / 2) / [UIScreen mainScreen].bounds.size.height)
  209. // withWidthPercent:(_mBlueFrame.bounds.size.width / [UIScreen mainScreen].bounds.size.width)
  210. // withHeightPercent:(_mBlueFrame.bounds.size.height / [UIScreen mainScreen].bounds.size.height)];
  211. [_mVerificationController setFaceLocation:0
  212. withYpercent:(0)
  213. withWidthPercent:(1)
  214. withHeightPercent:(1)];
  215. //设置摄像头回调
  216. [_mCameraController setCameraPreviewDelegate: _mVerificationController];
  217. [_mCameraController setCameraImageCaptureDelegate:weakSelf];
  218. //启动活体检测
  219. if ([_mVerificationController getCurrentStep] == STEP_READY) {
  220. NSLog(@"启动检测");
  221. [_mVerificationController nextVerificationStep];
  222. }
  223. }
  224. //=============================回调方法(全部都在UI线程回调)================================//
  225. #pragma 算法的回调
  226. /**
  227. * 预检成功回调
  228. *
  229. * @param detectedFrame 捕获到的图片
  230. * @param faceInfo 捕获到的人脸信息
  231. */
  232. - (void) onPrestartSuccess: (OliveappDetectedFrame*) detectedFrame
  233. withFaceInfo: (OliveappFaceInfo *)faceInfo{
  234. NSLog(@"[BEGIN][OliveappLivenessDetectionViewController]预检成功");
  235. assert([NSThread isMainThread] == 1);
  236. //停止动画
  237. [_mPreTimer invalidate];
  238. _mPreTimer = nil;
  239. //使用以下方法进入活体检测步骤
  240. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  241. _mIsInPrestart = NO;
  242. [_mVerificationController enterLivenessDetection];
  243. });
  244. NSLog(@"[END][OliveappLivenessDetectionViewController]预检成功");
  245. }
  246. /**
  247. * 预检失败回调
  248. */
  249. - (void) onPrestartFail {
  250. assert([NSThread isMainThread] == 1);
  251. // 处理预检失败事件(一般为超时)
  252. NSAssert(false, @"预检失败,现在的实现不应该运行到这里");
  253. }
  254. /**
  255. * 单帧回调
  256. *
  257. * @param remainingTimeoutMilliSecond 剩余时间
  258. */
  259. - (void) onFrameDetected: (int) remainingTimeoutMilliSecond
  260. withFaceInfo:faceInfo
  261. withErrorCodeOfInActionArray:(NSArray *)errorCodeOfInAction{
  262. assert([NSThread isMainThread] == 1);
  263. //计算帧率的代码
  264. // {
  265. // ++_mFrameNumber;
  266. // long long delta = [OliveappTimeUtility getTimeStampInMilliSec] - _mFrameTimer;
  267. // if (delta > 1000) {
  268. // [_mFrameLabel setText:[NSString stringWithFormat:@"帧率:%lld",_mFrameNumber * 1000 / delta]];
  269. // _mFrameNumber = 0;
  270. // _mFrameTimer = [OliveappTimeUtility getTimeStampInMilliSec];
  271. // }
  272. // }
  273. }
  274. /**
  275. * 活体检测成功的回调
  276. *
  277. * @param detectedFrame 活体检测抓取的图片
  278. * @param faceInfo 捕获到的人脸信息
  279. */
  280. - (void) onLivenessSuccess: (OliveappDetectedFrame*) detectedFrame
  281. withFaceInfo:(OliveappFaceInfo *)faceInfo{
  282. NSLog(@"[BEGIN] LivenessDetectionViewController::onLivenessSuccess");
  283. assert([NSThread isMainThread] == 1);
  284. assert(detectedFrame.frameData == nil);
  285. [[UIApplication sharedApplication] beginIgnoringInteractionEvents];
  286. [_mLivenessResultDelegate onLivenessSuccess:detectedFrame];
  287. [self.faceDelegate sendFaceImage:_myImage];
  288. NSLog(@"[END] LivenessDetectionViewController::onLivenessSuccess");
  289. }
  290. /**
  291. * 活体检测失败的回调
  292. *
  293. * @param sessionState session状态,用于区别超时还是动作不过关
  294. * @param detectedFrame 活体检测抓取的图片
  295. */
  296. - (void) onLivenessFail: (int) sessionState
  297. withDetectedFrame: (OliveappDetectedFrame *) detectedFrame{
  298. NSLog(@"[BEGIN] LivenessDetectionViewController::onLivenessFail");
  299. assert([NSThread isMainThread] == 1);
  300. // 回调给用户
  301. [[UIApplication sharedApplication] beginIgnoringInteractionEvents];
  302. [_mLivenessResultDelegate onLivenessFail:sessionState withDetectedFrame:detectedFrame];
  303. NSLog(@"[END] LivenessDetectionViewController::onLivenessFail");
  304. }
  305. /**
  306. * 活体检测取消回调
  307. */
  308. - (IBAction)touchCancelLiveness:(UIButton *)sender {
  309. [_mLivenessResultDelegate onLivenessCancel];
  310. }
  311. /**
  312. 每一帧结果的回调方法
  313. @param currentActionType 当前是什么动作
  314. @param actionState 当前动作的检测结果
  315. @param sessionState 整个Session是否通过
  316. @param faceInfo 检测到的人脸信息,可以用来做动画
  317. @param remainingTimeoutMilliSecond 剩余时间,以毫秒为单位
  318. @param errorCodeOfInAction 动作不过关的可能原因,可以用来做提示语
  319. */
  320. - (void) onFrameDetected: (int)currentActionType
  321. withActionState: (int)actionState
  322. withSessionState: (int)sessionState
  323. withFaceInfo:(OliveappFaceInfo *)faceInfo
  324. withRemainingTimeoutMilliSecond: (int)remainingTimeoutMilliSecond
  325. withErrorCodeOfInActionArray:(NSArray *)errorCodeOfInAction {
  326. NSLog(@"[BEGIN] LivenessDetectionViewController::onFrameDetected");
  327. assert([NSThread isMainThread] == 1);
  328. self.mCountDownUILabel.text = [NSString stringWithFormat:@"%d", remainingTimeoutMilliSecond / 1000 + 1];
  329. _mLocationArray = [self getLocation:_mCurrentActionType
  330. withFaceInfo:faceInfo];
  331. //计算帧率的代码
  332. // {
  333. // ++_mFrameNumber;
  334. // long long delta = [OliveappTimeUtility getTimeStampInMilliSec] - _mFrameTimer;
  335. // if (delta > 1000) {
  336. // [_mFrameLabel setText:[NSString stringWithFormat:@"帧率:%lld",_mFrameNumber * 1000 / delta]];
  337. // _mFrameNumber = 0;
  338. // _mFrameTimer = [OliveappTimeUtility getTimeStampInMilliSec];
  339. // }
  340. // }
  341. NSLog(@"[END] LivenessDetectionViewController::onFrameDetected");
  342. }
  343. /**
  344. 切换到下一个动作时的回调方法
  345. @param lastActionType 上一个动作类型
  346. @param lastActionResult 上一个动作的检测结果
  347. @param newActionType 当前新生成的动作类型
  348. @param currentActionIndex 当前是第几个动作
  349. @param faceInfo 人脸的信息
  350. */
  351. - (void) onActionChanged: (int)lastActionType
  352. withLastActionResult: (int)lastActionResult
  353. withNewActionType: (int)newActionType
  354. withCurrentActionIndex: (int)currentActionIndex
  355. withFaceInfo:(OliveappFaceInfo *)faceInfo {
  356. NSString * text = [_mActionHintTextDict objectForKey: [NSString stringWithFormat:@"hinttext_action_%d", newActionType]];
  357. if (lastActionType == 0) {
  358. [_mCameraController takePhoto];
  359. }
  360. [self playHintTextAnimation:text];
  361. _mCurrentVoiceFile = [_mAudioDict objectForKey: [NSString stringWithFormat:@"audio_action_%d", newActionType]];
  362. [self playBackgroundSoundEffect:_mCurrentVoiceFile];
  363. _mCurrentActionType = newActionType;
  364. _mLocationArray = [self getLocation:_mCurrentActionType
  365. withFaceInfo:faceInfo];
  366. [self playActionAnimation:_mCurrentActionType
  367. withLocation:_mLocationArray];
  368. [_mAnimationTimer invalidate];
  369. _mAnimationTimer = nil;
  370. _mAnimationTimer = [NSTimer scheduledTimerWithTimeInterval:REPEAT_SECOND
  371. target:self
  372. selector:@selector(playActionAnimation)
  373. userInfo:nil
  374. repeats:YES];
  375. }
  376. //=============================UI/动画相关================================//
  377. #pragma UI相关函数
  378. /**
  379. * 对不同屏幕进行动画适配
  380. */
  381. - (void)constructUI {
  382. if ([OliveappDeviceHelper deviceIsPad]) {
  383. if (_mDeviceOrientation == PORTRAIT) {
  384. _mScreenSize = CGSizeMake([UIScreen mainScreen].bounds.size.height * 9 / 16, [UIScreen mainScreen].bounds.size.height);
  385. } else {
  386. _mScreenSize = CGSizeMake([UIScreen mainScreen].bounds.size.height * 16 / 9, [UIScreen mainScreen].bounds.size.height);
  387. }
  388. } else {
  389. _mScreenSize = [UIScreen mainScreen].bounds.size;
  390. }
  391. }
  392. /**
  393. 播放预检动画和音频
  394. */
  395. - (void) playPreHint {
  396. if (_mVerificationControllerType == WITH_PRESTART && _mIsInPrestart) {
  397. [self playBackgroundSoundEffect:@"oliveapp_step_hint_prestart"];
  398. [self playAperture];
  399. }
  400. }
  401. /**
  402. 播放活检动画和音频
  403. */
  404. - (void) playActionAnimation {
  405. NSLog(@"重复动画");
  406. [self playActionAnimation:_mCurrentActionType withLocation:_mLocationArray];
  407. [self playBackgroundSoundEffect:_mCurrentVoiceFile];
  408. }
  409. /**
  410. * 播放音频
  411. *
  412. * @param resource 音频名字
  413. */
  414. - (void) playBackgroundSoundEffect: (NSString*) resource {
  415. NSString *soundFilePath = [[NSBundle mainBundle] pathForResource: resource ofType: @"mp3"];
  416. NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
  417. @synchronized (_mAudioPlayer) {
  418. if ([_mAudioPlayer isPlaying]) {
  419. [_mAudioPlayer stop];
  420. }
  421. _mAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL error:nil];
  422. [_mAudioPlayer play];
  423. }
  424. }
  425. /**
  426. 拿到当前动作对应的脸部坐标,用于做动画
  427. @param actionType 动作类型
  428. @param faceInfo 对应的人脸信息
  429. @return 脸部坐标数组
  430. */
  431. - (NSArray *) getLocation: (int) actionType
  432. withFaceInfo: (OliveappFaceInfo *) faceInfo {
  433. NSArray * resultArray;
  434. switch (actionType) {
  435. case EYE_CLOSE_ACTION: {
  436. //左右眼坐标
  437. CGPoint leftPoint = CGPointMake((1.f - faceInfo.leftEye.x) * [UIScreen mainScreen].bounds.size.width, faceInfo.leftEye.y * _mScreenSize.height);
  438. CGPoint rightPoint = CGPointMake((1.f - faceInfo.rightEye.x) * [UIScreen mainScreen].bounds.size.width, faceInfo.rightEye.y * _mScreenSize.height);
  439. resultArray = @[[NSValue valueWithCGPoint:leftPoint],
  440. [NSValue valueWithCGPoint:rightPoint]];
  441. break;
  442. }
  443. case MOUTH_OPEN_ACTION: {
  444. CGPoint mouthPoint = CGPointMake((1.f - faceInfo.mouth.x) * [UIScreen mainScreen].bounds.size.width, faceInfo.mouth.y * _mScreenSize.height);
  445. resultArray = @[[NSValue valueWithCGPoint:mouthPoint]];
  446. break;
  447. }
  448. case HEAD_UP_ACTION: {
  449. CGPoint chinPoint = CGPointMake((1.f - faceInfo.chin.x) * [UIScreen mainScreen].bounds.size.width, faceInfo.chin.y * _mScreenSize.height);
  450. resultArray = @[[NSValue valueWithCGPoint:chinPoint]];
  451. break;
  452. }
  453. default:
  454. break;
  455. }
  456. return resultArray;
  457. }
  458. //=============================设备辅助函数================================//
  459. #pragma 设备辅助函数
  460. - (BOOL) shouldAutorotate {
  461. return NO;
  462. }
  463. - (UIInterfaceOrientationMask)supportedInterfaceOrientations{
  464. switch (_mDeviceOrientation) {
  465. case LANDSCAPE_RIGHT:
  466. return UIInterfaceOrientationMaskLandscapeRight;
  467. break;
  468. case LANDSCAPE_LEFT:
  469. return UIInterfaceOrientationMaskLandscapeLeft;
  470. default:
  471. return UIInterfaceOrientationMaskPortrait;
  472. break;
  473. }
  474. }
  475. //================废弃的回调接口==========================//
  476. #pragma 废弃的回调函数
  477. - (void) onInitializeSucc {
  478. assert([NSThread isMainThread] == 1);
  479. NSLog(@"活体检测初始化成功");
  480. }
  481. - (void) onInitializeFail:(NSError*) error {
  482. assert([NSThread isMainThread] == 1);
  483. NSLog(@"活体检测初始化失败,错误信息: %@", [error localizedDescription]);
  484. }
  485. - (void)onImageCapture:(OliveappPhotoImage *)image {
  486. // 预处理图片
  487. CGRect cropRect = [OliveappPhotoImage getCropWithWidth:image.imageWidth
  488. withHeight:image.imageHeight
  489. withApertureView:self.view
  490. withCameraPreviewSuperViewAdapter:self.view];
  491. //切割后
  492. CIImage * croppedCIImage = [OliveappImageUtility cropImage:image.ciImage withCropArea:cropRect];
  493. if (@available(iOS 11.0, *)) {
  494. croppedCIImage = [croppedCIImage imageByApplyingCGOrientation:(kCGImagePropertyOrientationRight)];
  495. } else {
  496. // Fallback on earlier versions
  497. croppedCIImage = [croppedCIImage imageByApplyingTransform:[croppedCIImage imageTransformForOrientation:6]];
  498. }
  499. image.ciImage = croppedCIImage;
  500. image.imageWidth = cropRect.size.width;
  501. image.imageHeight = cropRect.size.height;
  502. _myImage = [OliveappImageUtility makeUIImageFromCIImage:image.ciImage];
  503. }
  504. @end