1
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
import { AVCaptureSession, AVCaptureDevice, AVMediaType, AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureDeviceInput, AVCaptureInput, AVCaptureVideoDataOutput, AVCaptureConnection, AVCaptureVideoPreviewLayer, AVLayerVideoGravity, AVCaptureVideoOrientation } from 'AVFoundation';
|
||||
import { PHPhotoLibrary, PHAuthorizationStatus } from 'Photos';
|
||||
import { CMSampleBuffer, CMSampleBufferGetFormatDescription, CMFormatDescription, CMVideoFormatDescriptionGetDimensions } from 'CoreMedia';
|
||||
import { DispatchQueue } from "Dispatch"
|
||||
import { UIView, UIImage, UIApplication, UIImageView, UILabel, UIViewController, UIFontDescriptor, UIFont, NSTextAlignment, UITapGestureRecognizer, UIImagePickerController, UIImagePickerControllerDelegate, UINavigationControllerDelegate } from 'UIKit';
|
||||
import { CGRect, CGFloat, CGPoint } from 'CoreFoundation';
|
||||
import { Face, FaceContour, FaceDetector, FaceDetectorOptions,FaceContourType,FaceLandmarkType, FaceLandmark,FaceDetectorPerformanceMode,FaceDetectorClassificationMode,FaceDetectorLandmarkMode } from "MLKitFaceDetection"
|
||||
import { VisionImage } from "MLKit"
|
||||
|
||||
import { NotificationCenter, NSNotification, Notification } from 'Foundation';
|
||||
import { Selector } from 'ObjectiveC';
|
||||
import { Alignment } from 'ARKit';
|
||||
import { CABasicAnimation } from 'QuartzCore';
|
||||
import { Int,Float } from 'Swift';
|
||||
|
||||
import { XFACE_CHECK_OPTS, XFACE_EVENT_SUCCESS, XFACE_TEST_EYE_TYPE, XFACE_FACE_Direction, XFACE_EVENT_CHECK_SUCCESS } from "../interface.uts"
|
||||
import { XFACE_CHECK_OPTS_REAL, getDefaultConfig } from "../libs/config.uts"
|
||||
|
||||
|
||||
const checkFaceResult = (orimg:UIImage, faces : Array<Face>, callBack : (result : XFACE_EVENT_SUCCESS[]) => void) => {
|
||||
const cfaces = [] as XFACE_EVENT_SUCCESS[]
|
||||
// @ts-ignore
|
||||
for (item in faces) {
|
||||
// @ts-ignore
|
||||
const face = item as Face;
|
||||
let rightEye = { openNum: 0, isOpen: false } as XFACE_TEST_EYE_TYPE;
|
||||
let leftEye = { openNum: 0, isOpen: false } as XFACE_TEST_EYE_TYPE;
|
||||
// 眼睛
|
||||
let rightEyeMark = face.landmark(ofType = FaceLandmarkType.rightEye)
|
||||
let leftEyeMark = face.landmark(ofType = FaceLandmarkType.leftEye)
|
||||
|
||||
// 鼻子
|
||||
let noseMark = face.landmark(ofType = FaceLandmarkType.noseBase)
|
||||
// 耳朵
|
||||
let rightEarMark = face.landmark(ofType = FaceLandmarkType.rightEar)
|
||||
let leftEarMark = face.landmark(ofType = FaceLandmarkType.leftEar)
|
||||
|
||||
let rightEyeNum = face.rightEyeOpenProbability
|
||||
let leftEyeNum = face.leftEyeOpenProbability
|
||||
let isSmile = face.smilingProbability
|
||||
|
||||
let faceId = face.trackingID
|
||||
|
||||
|
||||
if (rightEyeNum != null) {
|
||||
rightEye.openNum = new Number(rightEyeNum) + 0;
|
||||
rightEye.isOpen = new Number(rightEyeNum) > 0.7
|
||||
}
|
||||
if (leftEyeNum != null) {
|
||||
leftEye.openNum = new Number(leftEyeNum)+ 0;
|
||||
leftEye.isOpen = new Number(leftEyeNum) > 0.7
|
||||
}
|
||||
|
||||
// 检测当前左,右,下,上
|
||||
let faceRightLeft : XFACE_FACE_Direction = "center"
|
||||
let faceUpDown : XFACE_FACE_Direction = "center"
|
||||
|
||||
|
||||
let eulerX = face.headEulerAngleX; // 获取头部左右旋转角度
|
||||
let eulerY = face.headEulerAngleY; // 获取头部上下俯仰角度
|
||||
let eulerZ = face.headEulerAngleZ; // 获取头部上下俯仰角度
|
||||
|
||||
// 嘴巴
|
||||
let leftMouth = face.landmark(ofType = FaceLandmarkType.mouthLeft)
|
||||
let rightMouth = face.landmark(ofType = FaceLandmarkType.mouthRight)
|
||||
let bottomMouth = face.landmark(ofType = FaceLandmarkType.mouthBottom)
|
||||
|
||||
let isMouthOpened = false
|
||||
let ANGLE_THRESHOLD = 30; // 容差值
|
||||
let ANGLE_HEAD_THRESHOLD = 0; // 容差值
|
||||
let ANGLE_EYE_THRESHOLD = 6; // 眨眼的容差.
|
||||
|
||||
let allHeadBody = false;
|
||||
|
||||
if (Math.abs(Number(eulerY)) > ANGLE_THRESHOLD) { // 确保头部没有明显上下俯仰
|
||||
faceRightLeft = eulerY > 0 ? 'left' : 'right';
|
||||
}
|
||||
|
||||
if (Math.abs(Number(eulerX)) >= ANGLE_HEAD_THRESHOLD) { // 确保头部没有明显上下俯仰
|
||||
faceUpDown = eulerY > 0 ? 'down' : 'up';
|
||||
}
|
||||
|
||||
if (leftMouth != null && rightMouth != null && bottomMouth != null) {
|
||||
let mouthWidth = rightMouth!.position.x - leftMouth!.position.x
|
||||
let mouthHeight = bottomMouth!.position.y - ((leftMouth!.position.y + rightMouth!.position.y) / 2)
|
||||
|
||||
if (mouthHeight / mouthWidth > 0.4 && faceRightLeft == 'center') {
|
||||
isMouthOpened = true;
|
||||
} else {
|
||||
isMouthOpened = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(
|
||||
leftMouth != null &&
|
||||
rightMouth != null &&
|
||||
bottomMouth != null &&
|
||||
noseMark !=null&&
|
||||
rightEarMark !=null&&
|
||||
leftEarMark !=null&&
|
||||
rightEyeMark !=null&&
|
||||
leftEyeMark !=null
|
||||
){
|
||||
allHeadBody = true;
|
||||
}
|
||||
cfaces.push({
|
||||
imgWidth: orimg.size.width,
|
||||
imgHeight: orimg.size.height,
|
||||
isSmile: isSmile == null ? false : (isSmile >= 0.8),
|
||||
rightEye,
|
||||
leftEye,
|
||||
faceRightLeft,
|
||||
faceUpDown,
|
||||
isMouthOpened,
|
||||
allHeadBody,
|
||||
faceId:faceId!=null?(faceId+0):null
|
||||
})
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
callBack(cfaces)
|
||||
}
|
||||
|
||||
export function checkFaceByImage(config : XFACE_CHECK_OPTS | null = null){
|
||||
const cfg = getDefaultConfig(config)
|
||||
let options_s = FaceDetectorOptions()
|
||||
options_s.performanceMode = FaceDetectorPerformanceMode.accurate
|
||||
options_s.landmarkMode = FaceDetectorLandmarkMode.all
|
||||
options_s.classificationMode = FaceDetectorClassificationMode.all
|
||||
// @ts-ignore
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
// @ts-ignore
|
||||
success(evt : ChooseImageSuccess) {
|
||||
if (evt.tempFilePaths.length == 0) return;
|
||||
const imgs = evt.tempFilePaths[0] as string;
|
||||
const decodedPath = UTSiOS.convert2AbsFullPath(imgs)
|
||||
let img = new UIImage(contentsOfFile = decodedPath);
|
||||
let image = new VisionImage(image = img!);
|
||||
let faceDetector = FaceDetector.faceDetector(options = options_s)
|
||||
faceDetector.process(image as VisionImage,completion = (faces:Array<Face>|null,error:any|null)=>{
|
||||
|
||||
if(error != null||faces==null||(faces?.length??0)==0){
|
||||
cfg.success({
|
||||
images:[],
|
||||
videoPath:"",
|
||||
isPass:false
|
||||
})
|
||||
return;
|
||||
}
|
||||
const _faces = faces!;
|
||||
|
||||
checkFaceResult(img!, _faces, (result : XFACE_EVENT_SUCCESS[]) => {
|
||||
|
||||
DispatchQueue.main.async(execute = () : void => {
|
||||
|
||||
cfg.enter(result,JSON.stringify(result)!)
|
||||
cfg.success({
|
||||
isPass: true,
|
||||
images: [decodedPath] as string[],
|
||||
videoPath: ""
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
// for(item in faces!){
|
||||
// const face = item as Face
|
||||
// let leftEye = face.landmark(ofType = FaceLandmarkType.leftEye)
|
||||
// if(leftEye!=null){
|
||||
// let leftEyePosition = leftEye!.position
|
||||
// console.log(leftEyePosition.x,'----',img!.size.width)
|
||||
// }
|
||||
// }
|
||||
})
|
||||
},
|
||||
fail() {
|
||||
cfg.fail("解析错误")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供外部图片地址检测当前图片是否存在人脸
|
||||
*/
|
||||
export function checkFaceByImageFromFilePath(config : XFACE_CHECK_OPTS) {
|
||||
const cfg = getDefaultConfig(config)
|
||||
const imgs = cfg.url;
|
||||
const decodedPath = UTSiOS.convert2AbsFullPath(imgs!)
|
||||
let img = new UIImage(contentsOfFile = decodedPath);
|
||||
let image = new VisionImage(image = img!);
|
||||
let options_s = FaceDetectorOptions()
|
||||
options_s.performanceMode = FaceDetectorPerformanceMode.accurate
|
||||
options_s.landmarkMode = FaceDetectorLandmarkMode.all
|
||||
options_s.classificationMode = FaceDetectorClassificationMode.all
|
||||
|
||||
let faceDetector = FaceDetector.faceDetector(options = options_s)
|
||||
faceDetector.process(image as VisionImage,completion = (faces:Array<Face>|null,error:any|null)=>{
|
||||
if(error != null||faces==null||(faces?.length??0)==0){
|
||||
cfg.success({
|
||||
images:[],
|
||||
videoPath:"",
|
||||
isPass:false
|
||||
})
|
||||
return;
|
||||
}
|
||||
const _faces = faces!;
|
||||
checkFaceResult(img!, _faces, (result : XFACE_EVENT_SUCCESS[]) => {
|
||||
DispatchQueue.main.async(execute = () : void => {
|
||||
cfg.enter(result,JSON.stringify(result)!)
|
||||
cfg.success({
|
||||
isPass: true,
|
||||
images: [decodedPath] as string[],
|
||||
videoPath: ""
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user