mirror of
https://github.com/status-im/react-native-camera.git
synced 2025-02-25 02:15:13 +00:00
120 lines
5.6 KiB
Mathematica
120 lines
5.6 KiB
Mathematica
|
//
|
||
|
// RNFaceEncoder.m
|
||
|
// RCTCamera
|
||
|
//
|
||
|
// Created by Joao Guilherme Daros Fidelis on 21/01/18.
|
||
|
//
|
||
|
|
||
|
#import "RNFaceEncoder.h"
|
||
|
|
||
|
#define cDefaultFloatComparisonEpsilon 0.0001
|
||
|
#define cModEqualFloatsWithEpsilon(dividend, divisor, modulo, epsilon) \
|
||
|
fabs( fmod(dividend, divisor) - modulo ) < epsilon
|
||
|
#define cModEqualFloats(dividend, divisor, modulo) \
|
||
|
cModEqualFloatsWithEpsilon(dividend, divisor, modulo, cDefaultFloatComparisonEpsilon)
|
||
|
|
||
|
@interface RNFaceEncoder()
|
||
|
|
||
|
@property (assign, nonatomic) BOOL swapWidthAndHeight;
|
||
|
@property (assign, nonatomic) CGAffineTransform transform;
|
||
|
@property (assign, nonatomic) CGFloat rollAngleDegreesFromTransform;
|
||
|
|
||
|
@end
|
||
|
|
||
|
@implementation RNFaceEncoder
|
||
|
|
||
|
- (instancetype)init
|
||
|
{
|
||
|
return [self initWithTransform:CGAffineTransformIdentity];
|
||
|
}
|
||
|
|
||
|
- (instancetype)initWithTransform:(CGAffineTransform)transform
|
||
|
{
|
||
|
self = [super init];
|
||
|
if (self) {
|
||
|
_transform = transform;
|
||
|
_rollAngleDegreesFromTransform = [self radianAngleToDegrees:[self rollAngleFromTransform:_transform]];
|
||
|
_swapWidthAndHeight = cModEqualFloats(_rollAngleDegreesFromTransform + 360, 180, 90);
|
||
|
}
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
|
||
|
- (NSDictionary *)encode:(GMVFaceFeature *)face
|
||
|
{
|
||
|
CGRect bounds = CGRectApplyAffineTransform(face.bounds, _transform);
|
||
|
NSDictionary *initialDictionary = @{
|
||
|
@"bounds" : @{
|
||
|
@"size" : @{
|
||
|
@"width" : @(_swapWidthAndHeight ? bounds.size.height : bounds.size.width),
|
||
|
@"height" : @(_swapWidthAndHeight ? bounds.size.width : bounds.size.height)
|
||
|
},
|
||
|
@"origin" : @{
|
||
|
@"x" : @(bounds.origin.x),
|
||
|
@"y" : @(bounds.origin.y)
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
NSMutableDictionary *encodedFace = [[NSMutableDictionary alloc] initWithDictionary:initialDictionary];
|
||
|
[self putAFloat:face.smilingProbability forKey:@"smilingProbability" toDictionary:encodedFace ifValueIsValid:face.hasSmilingProbability];
|
||
|
[self putAnInteger:face.trackingID forKey:@"faceID" toDictionary:encodedFace ifValueIsValid:face.hasTrackingID];
|
||
|
|
||
|
[self putAPoint:face.leftEarPosition forKey:@"leftEarPosition" toDictionary:encodedFace ifValueIsValid:face.hasLeftEarPosition];
|
||
|
[self putAPoint:face.rightEarPosition forKey:@"rightEarPosition" toDictionary:encodedFace ifValueIsValid:face.hasRightEarPosition];
|
||
|
|
||
|
[self putAPoint:face.leftEyePosition forKey:@"leftEyePosition" toDictionary:encodedFace ifValueIsValid:face.hasLeftEyePosition];
|
||
|
[self putAFloat:face.leftEyeOpenProbability forKey:@"leftEyeOpenProbability" toDictionary:encodedFace ifValueIsValid:face.hasLeftEyeOpenProbability];
|
||
|
|
||
|
[self putAPoint:face.rightEyePosition forKey:@"rightEyePosition" toDictionary:encodedFace ifValueIsValid:face.hasRightEyePosition];
|
||
|
[self putAFloat:face.rightEyeOpenProbability forKey:@"rightEyeOpenProbability" toDictionary:encodedFace ifValueIsValid:face.hasRightEyeOpenProbability];
|
||
|
|
||
|
[self putAPoint:face.leftCheekPosition forKey:@"leftCheekPosition" toDictionary:encodedFace ifValueIsValid:face.hasLeftCheekPosition];
|
||
|
[self putAPoint:face.rightCheekPosition forKey:@"rightCheekPosition" toDictionary:encodedFace ifValueIsValid:face.hasRightCheekPosition];
|
||
|
|
||
|
[self putAPoint:face.leftMouthPosition forKey:@"leftMouthPosition" toDictionary:encodedFace ifValueIsValid:face.hasLeftMouthPosition];
|
||
|
[self putAPoint:face.mouthPosition forKey:@"mouthPosition" toDictionary:encodedFace ifValueIsValid:face.hasMouthPosition];
|
||
|
[self putAPoint:face.rightMouthPosition forKey:@"rightMouthPosition" toDictionary:encodedFace ifValueIsValid:face.hasRightMouthPosition];
|
||
|
[self putAPoint:face.bottomMouthPosition forKey:@"bottomMouthPosition" toDictionary:encodedFace ifValueIsValid:face.hasBottomMouthPosition];
|
||
|
|
||
|
[self putAPoint:face.noseBasePosition forKey:@"noseBasePosition" toDictionary:encodedFace ifValueIsValid:face.hasNoseBasePosition];
|
||
|
|
||
|
[self putAFloat:face.headEulerAngleY forKey:@"yawAngle" toDictionary:encodedFace ifValueIsValid:face.hasHeadEulerAngleY];
|
||
|
[self putAFloat:-(face.headEulerAngleZ - _rollAngleDegreesFromTransform) forKey:@"rollAngle" toDictionary:encodedFace ifValueIsValid:face.hasHeadEulerAngleZ];
|
||
|
|
||
|
return encodedFace;
|
||
|
}
|
||
|
|
||
|
- (void)putAPoint:(CGPoint)point forKey:(NSString *)key toDictionary:(NSMutableDictionary *)dictionary ifValueIsValid:(BOOL)pointIsValid
|
||
|
{
|
||
|
if (pointIsValid) {
|
||
|
CGPoint transformedPoint = CGPointApplyAffineTransform(point, _transform);
|
||
|
[dictionary setObject:@{ @"x" : @(transformedPoint.x), @"y" : @(transformedPoint.y) } forKey:key];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void)putAFloat:(CGFloat)value forKey:(NSString *)key toDictionary:(NSMutableDictionary *)dictionary ifValueIsValid:(BOOL)floatIsValid
|
||
|
{
|
||
|
if (floatIsValid) {
|
||
|
[dictionary setObject:@(value) forKey:key];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void)putAnInteger:(NSUInteger)value forKey:(NSString *)key toDictionary:(NSMutableDictionary *)dictionary ifValueIsValid:(BOOL)integerIsValid
|
||
|
{
|
||
|
if (integerIsValid) {
|
||
|
[dictionary setObject:@(value) forKey:key];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (CGFloat)rollAngleFromTransform:(CGAffineTransform)transform
|
||
|
{
|
||
|
return atan2f(transform.b, transform.a);
|
||
|
}
|
||
|
|
||
|
- (CGFloat)radianAngleToDegrees:(CGFloat)angle
|
||
|
{
|
||
|
return angle * (180 / M_PI);
|
||
|
}
|
||
|
|
||
|
@end
|