This commit is contained in:
启星
2025-08-08 10:49:36 +08:00
parent 6400cf78bb
commit b5ce3d580a
8780 changed files with 978183 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
//
// TencentCloudHuiyanSDKFace.h
// Pods
//
// Created by Leon on 2022/11/14.
//
#ifndef TencentCloudHuiyanSDKFace_h
#define TencentCloudHuiyanSDKFace_h
#import <TencentCloudHuiyanSDKFace/WBFaceError.h>
#import <TencentCloudHuiyanSDKFace/WBFaceVerifyConst.h>
#import <TencentCloudHuiyanSDKFace/WBFaceVerifyCustomerService.h>
#import <TencentCloudHuiyanSDKFace/WBFaceVerifyResult.h>
#import <TencentCloudHuiyanSDKFace/WBFaceVerifySDKConfig.h>
#endif /* TencentCloudHuiyanSDKFace_h */

View File

@@ -0,0 +1,112 @@
//
// WBFaceError.h
// Pods
//
// Created by pp on 2017/8/15.
//
//
#import <UIKit/UIKit.h>
/*
Domain(错误出现的地方) Code Desc(描述) Reason(详细实际原因)
WBFaceErrorDomainInputParams 12000 传入参数为空 传入的xx为空
12001 传入的keyLicence不可用 传入的keyLicence不可用
12002 身份证格式不正确 身份证格式不正确
12003 使用自带对比源,传入参数错误,非base64 传入的srcPhotoString不是base64
12004 使用自带对比源,传入参数错误,超过3M 传入的srcPhotoString超过3M
12005 sdk资源引入版本不匹配 没有引入资源包或者引入的资源包版本与当前SDK版本不匹配
12006 订单号不能为0或者超过32位
12007 nonce字符串位数不为32
12008 faceid不合法需要保证faceid与接口对应
12009 定制化SDK生成参数失败
12010 定制化参数校验错误
12011 当前版本意愿性表达服务暂不支持
WBFaceErrorDomainLoginNetwork 22100 网络异常 登陆时网络异常(请求未到达后台)
22200 网络异常 登陆时后台返回参数有误(请求到达后台)
WBFaceErrorDomainLoginServer 其他 透传后台错误码(请参考后台错误) 例如签名问题等等
WBFaceErrorDomainGetInfo 32100 网络异常 获取数字/活体类型/光线阈值,网络异常(请求未到达后台)
32200 网络异常 获取数字/活体类型/光线阈值,后台返回参数有误(请求到达后台)
WBFaceErrorDomainNativeProcess 42000 用户取消 回到后台/点击home/左上角/上传时左上角 取消
42001 网络环境不满足认证需求 无网络/2g网络
42002 权限异常,未获取权限 相机/麦克风/read phone/external storage
42003 相机运行中出错
42004 视频录制中出错 不能存/启动失败/结束失败
42005 请勿晃动人脸,保持姿势 未获取到最佳图片
42006 视频大小不满足要求 视频大小不满足要求
42007 超时 预检测/动作活体
42008 检测中人脸移出框外 活体/数字/反光
42009 光线活体本地错误
42010 风险控制超出次数 用户重试太多次
42011 没有检测到读数声音 数字活体过程中没有发声
42012 模型初始化失败
42013 意愿模块初始化失败
42015 登录态失效
42016 请求异常
42101 音频录制中出错
42102 没有检测到麦克风声音
42103 播报音频文件加载失败
42104 麦克风被占用,音频播报失败
42105 视频录制中出错
42106 音量过低,用户主动退出
42107 点头检测超时
WBFaceErrorDomainCompareNetwork 52100 网络异常 对比时,网络异常(请求未到达后台)
52200 网络异常 对比时,后台返回参数有误(请求到达后台)
WBFaceErrorDomainCompareServer 其他 透传后台错误码
*/
NS_ASSUME_NONNULL_BEGIN
/*
错误domain划分成两类:
1. 出现在登录时, 通过调用startXXXX 方法的failure block进行回调返回:
WBFaceErrorDomainInputParams, WBFaceErrorDomainLoginNetwork, WBFaceErrorDomainLoginServer
2. 人脸服务结果返回(封装在WBFaceVerifyResult中):
WBFaceErrorDomainGetInfo, WBFaceErrorDomainNativeProcess, WBFaceErrorDomainCompareNetwork, WBFaceErrorDomainCompareServer
*/
/* 登录时传入参数有误 */
UIKIT_EXTERN NSString *const WBFaceErrorDomainInputParams;
/* 登录时网络请求错误 */
UIKIT_EXTERN NSString *const WBFaceErrorDomainLoginNetwork;
/* 登录时后台拒绝登录, 具体参考后台word版本错误码, 这里直接透传 */
UIKIT_EXTERN NSString *const WBFaceErrorDomainLoginServer;
/* 拉取有效信息时候网络错误 */
UIKIT_EXTERN NSString *const WBFaceErrorDomainGetInfo;
/* native本地在活体检测中, 某些原因导致错误 */
UIKIT_EXTERN NSString *const WBFaceErrorDomainNativeProcess;
/* 上送后台比对时,网络错误 */
UIKIT_EXTERN NSString *const WBFaceErrorDomainCompareNetwork;
/* 后台比对完成,返回比对结果的错误原因*/
UIKIT_EXTERN NSString *const WBFaceErrorDomainCompareServer;
/* 后台比对未完成,返回失败的错误原因*/
UIKIT_EXTERN NSString *const WBFaceErrorDomainServerFailed;
@interface WBFaceError: NSObject
/**
错误发生的地方, 具体的发生地方由上面定义的 WBFaceErrorDomainXXXX 指定
*/
@property (nonatomic, readonly, copy) NSString *domain;
/**
每个domain中有相应的错误代码, 具体的错误代码见
*/
@property (nonatomic, readonly, assign) NSInteger code; //错误代码
@property (nonatomic, readonly, copy) NSString *desc; //获取本地化描述
@property (nonatomic, readonly, copy) NSString *reason; // 错误出现的真实原因原因
@property (nonatomic, readonly, copy) NSDictionary * _Nullable otherInfo;// 预留接口
+ (instancetype)errorWithDomain:(NSString *)domain code:(NSInteger)code desc:(NSString *)desc;
+ (instancetype)errorWithDomain:(NSString *)domain code:(NSInteger)code desc:(NSString *)desc reason:(NSString *)reason;
+ (instancetype)errorWithDomain:(NSString *)domain code:(NSInteger)code desc:(NSString *)desc reason:(NSString *)reason otherInfo:(nullable NSDictionary *)otherInfo;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,42 @@
//
// WBFaceVerifyConst.h
// Pods
//
// Created by pp on 2017/7/31.
//
//
#import <UIKit/UIKit.h>
#ifndef WBFaceVerifyConst_h
#define WBFaceVerifyConst_h
#define WBCloudReflectionFaceVerifyVersion @"8.7.0"
UIKIT_EXTERN NSString *const WBCloudFaceVerifySDKVersion;
/**
SDK使用的主题风格
- WBFaceVerifyThemeDarkness: 暗黑色系主题
- WBFaceVerifyThemeLightness: 明亮色系主题
- WBFaceVerifyThemeCustom: 自定义主题通过修改bundle中的custom.json实现自定义
*/
typedef NS_ENUM(NSInteger, WBFaceVerifyTheme) {
WBFaceVerifyThemeDarkness = 0,
WBFaceVerifyThemeLightness,
WBFaceVerifyThemeCustom,
};
typedef NS_ENUM(NSInteger, WBFaceVerifyLanguage) {
WBFaceVerifyLanguage_ZH_CN = 0, //简体中文
WBFaceVerifyLanguage_ZH_HK, //繁体中文
WBFaceVerifyLanguage_EN, //英语
WBFaceVerifyLanguage_ID, //印尼语
WBFaceVerifyLanguage_JA, //日语
WBFaceVerifyLanguage_KO, //韩语
WBFaceVerifyLanguage_TH //泰语
};
typedef NS_ENUM(NSInteger, WBFaceCustomTipsLoc) {
WBFaceCustomTipsLoc_Bottom = 0, //提示语在下
WBFaceCustomTipsLoc_Top,
};
#endif /* WBFaceVerifyConst_h */

View File

@@ -0,0 +1,177 @@
//
// WBFaceVerifyCustomerService.h
// WBFaceV2
//
// Created by tank on 25/10/2016.
// Copyright © 2016 tencent. All rights reserved.
//
/**
注意拉起页面的方式:
SDK会创建一个UIWindow覆盖在当前界面,并在新创建的UIWindow界面进行人脸认证,并且可以通过实现 wbfaceVerifyServiceGetWindowLevel 代理方法,传入创建的UIWindow的windowLevel, 传入的windowLevel必须是1~999, 默认情况如果不实现 wbfaceVerifyServiceGetWindowLevel 方法,windowLevel = UIWindowLevelNormal + 1
*/
#import <UIKit/UIKit.h>
#import "WBFaceVerifyConst.h"
#import "WBFaceVerifySDKConfig.h"
#import "WBFaceVerifyResult.h"
NS_ASSUME_NONNULL_BEGIN
// SDK在运行结束退出时候会发出通知. 具体的通知内容可以见delegate方法wbfaceVerifyCustomerServiceDidFinished:中的注释
UIKIT_EXTERN NSString *const WBFaceVerifyCustomerServiceDidFinishedNotification;
@class WBFaceVerifyCustomerService;
/**
处理刷脸回调
*/
@protocol WBFaceVerifyCustomerServiceDelegate <NSObject>
@optional
-(void)wbfaceVerifyCustomerServiceWillUploadBestImage:(UIImage *)bestImage;
@required
-(void)wbfaceVerifyCustomerServiceDidFinishedWithFaceVerifyResult:(WBFaceVerifyResult *)faceVerifyResult;
@end
@interface WBFaceVerifyCustomerService : NSObject
@property (nullable,nonatomic,weak) id<WBFaceVerifyCustomerServiceDelegate> delegate;
@property (nonatomic, assign, readonly) BOOL isService;
/*
全局唯一单例
*/
+(instancetype)sharedInstance;
/*
初始化云刷脸sdk仅做参数初始化与登陆不拉起刷脸页面
登陆有时效性建议在登陆完成后success回调中拉起刷脸页面
登陆过程为异步操作,多次登陆以最后一次收到的结果为准!!
此SDK接口中
合作方后台开发需要通过后台接口获取sign,
然后根据自带比对源接口, 通过后台接口获取faceId!!!!(native端无需传入自带比对源图)
*** faceId为空时启用仅活体检测服务不做比对
注意, 请使用 dispatch_async(dispatch_get_main_queue(), ^{ }); 异步调用SDK的入口方法
@param userid 用户唯一标识, 由合作方自行定义具体要求参考word接入文档
@param nonce 满足接入要求的32位随机数具体要求参考word接入文档
@param sign 满足接入要求的40位签名值具体要求参考word接入文档
@param appid 腾讯服务分配的appid
@param orderNo 每次人脸身份认证请求的唯一订单号: 建议为32位字符串(不超过32位)
@param apiVersion 后台api接口版本号(不是SDK的版本号),默认请填写@"1.0.0"
@param licence 腾讯给合作方派发的前端使用的licence(该licence同app当前使用的bundle id绑定)
@param faceId 合作方必须要先在获取faceId的接口里送入用户自带比对源图片信息得到相应的faceId后再送入sdk!!!!(参考word接入文档)
*** faceId为空时启用仅活体检测服务不做比对
@param sdkConfig SDK基础配置项目
@param success 服务登录成功回调,登录成功以后开始进行活体和检测服务
@param failure 服务登录失败回调,具体参考错误码文档(参考word接入文档)
*/
-(void)initSDKWithUserId:(NSString *)userid
nonce:(NSString *)nonce
sign:(NSString *)sign
appid:(NSString *)appid
orderNo:(NSString *)orderNo
apiVersion:(NSString *)apiVersion
licence:(NSString *)licence
faceId:(nullable NSString *)faceId
sdkConfig:(WBFaceVerifySDKConfig *)sdkConfig
success:(void (^)(void))success
failure:(void (^)(WBFaceError * _Nonnull error))failure;
/*
Plus级SDK核身入口注意传入的faceId不能为空否则会报failure
@param userid 用户唯一标识, 由合作方自行定义具体要求参考word接入文档
@param nonce 满足接入要求的32位随机数具体要求参考word接入文档
@param sign 满足接入要求的40位签名值具体要求参考word接入文档
@param appid 腾讯服务分配的appid
@param orderNo 每次人脸身份认证请求的唯一订单号: 建议为32位字符串(不超过32位)
@param apiVersion 后台api接口版本号(不是SDK的版本号),默认请填写@"1.0.0"
@param licence 腾讯给合作方派发的前端使用的licence(该licence同app当前使用的bundle id绑定)
@param faceId 合作方必须要先获取*增强级*faceId再送入sdk不允许为空(参考word接入文档)
@param sdkConfig SDK基础配置项目
@param success 服务登录成功回调,登录成功以后开始进行活体和检测服务
@param failure 服务登录失败回调,具体参考错误码文档(参考word接入文档)
*/
- (void)initPlusSDKWithUserId:(NSString *)userid
nonce:(NSString *)nonce
sign:(NSString *)sign
appid:(NSString *)appid
orderNo:(NSString *)orderNo
apiVersion:(NSString *)apiVersion
licence:(NSString *)licence
faceId:(nullable NSString *)faceId
sdkConfig:(WBFaceVerifySDKConfig *)sdkConfig
success:(void (^)(void))success
failure:(void (^)(WBFaceError * _Nonnull error))failure;
/*
增强级SDK核身入口注意传入的faceId不能为空且必须为增强faceId否则会报failure
@param userid 用户唯一标识, 由合作方自行定义具体要求参考word接入文档
@param nonce 满足接入要求的32位随机数具体要求参考word接入文档
@param sign 满足接入要求的40位签名值具体要求参考word接入文档
@param appid 腾讯服务分配的appid
@param orderNo 每次人脸身份认证请求的唯一订单号: 建议为32位字符串(不超过32位)
@param apiVersion 后台api接口版本号(不是SDK的版本号),默认请填写@"1.0.0"
@param licence 腾讯给合作方派发的前端使用的licence(该licence同app当前使用的bundle id绑定)
@param faceId 合作方必须要先获取*增强级*faceId再送入sdk不允许为空(参考word接入文档)
@param sdkConfig SDK基础配置项目
@param success 服务登录成功回调,登录成功以后开始进行活体和检测服务
@param failure 服务登录失败回调,具体参考错误码文档(参考word接入文档)
*/
-(void)initAdvanceSDKWithUserId:(NSString *)userid
nonce:(NSString *)nonce
sign:(NSString *)sign
appid:(NSString *)appid
orderNo:(NSString *)orderNo
apiVersion:(NSString *)apiVersion
licence:(NSString *)licence
faceId:(nonnull NSString *)faceId
sdkConfig:(WBFaceVerifySDKConfig *)sdkConfig
success:(void (^)(void))success
failure:(void (^)(WBFaceError * _Nonnull error))failure;
/**
以上一次的登陆结果拉起刷脸页面,必须先登录再拉起刷脸页面
@return 拉起是否成功
*/
- (BOOL)startWbFaceVeirifySdk;
#pragma mark - 意愿性表达接口
/*
意愿性SDK入口注意传入的faceId不能为空
@param userid 用户唯一标识, 由合作方自行定义具体要求参考word接入文档
@param nonce 满足接入要求的32位随机数具体要求参考word接入文档
@param sign 满足接入要求的40位签名值具体要求参考word接入文档
@param appid 腾讯服务分配的appid
@param orderNo 每次人脸身份认证请求的唯一订单号: 建议为32位字符串(不超过32位)
@param apiVersion 后台api接口版本号(不是SDK的版本号),默认请填写@"1.0.0"
@param licence 腾讯给合作方派发的前端使用的licence(该licence同app当前使用的bundle id绑定)
@param faceId 合作方必须要先获取*增强级*faceId再送入sdk不允许为空(参考word接入文档)
@param sdkConfig SDK基础配置项目
@param success 服务登录成功回调,登录成功以后开始进行活体和检测服务
@param failure 服务登录失败回调,具体参考错误码文档(参考word接入文档)
*/
-(void)initWillSDKWithUserId:(NSString *)userid
nonce:(NSString *)nonce
sign:(NSString *)sign
appid:(NSString *)appid
orderNo:(NSString *)orderNo
apiVersion:(NSString *)apiVersion
licence:(NSString *)licence
faceId:(nonnull NSString *)faceId
sdkConfig:(WBFaceVerifySDKConfig *)sdkConfig
success:(void (^)(void))success
failure:(void (^)(WBFaceError * _Nonnull error))failure;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,141 @@
//
// WBFaceVerifyResult.h
// Pods
//
// Created by pp on 2017/8/22.
//
//
#import <UIKit/UIKit.h>
#import "WBFaceError.h"
#import "WBFaceVerifyConst.h"
@interface WBFaceWillModeResult : NSObject
/*
核身结果的对应错误码
*/
@property (nonatomic, copy, readonly) NSString *faceCode;
/*
核身结果的对应错误描述
*/
@property (nonatomic, copy, readonly) NSString *faceMsg;
/*
意愿性结果的对应错误码
*/
@property (nonatomic, copy, readonly) NSString *willCode;
/*
意愿性结果的对应错误描述
*/
@property (nonatomic, copy, readonly) NSString *willMsg;
@property (nonatomic, strong, readonly) NSURL *videoURL;
@end
@interface WBFaceSimpleModeResult : NSObject
/**
结果对应的订单号
*/
@property (nonatomic, copy, readonly) NSString *orderNo;
/**
接下来用于人脸对比的安全性参数
*/
@property (nonatomic, copy, readonly) NSString *encryptAESKey;
/**
视频编码
*/
@property (nonatomic, copy, readonly) NSString *userVideoString;
/**
使用传入publickey加密过的AES
*/
@property (nonatomic, copy, readonly) NSString *videoEncryptAESKey;
/**
用于后面进行人脸比对的数据参数
*/
@property (nonatomic, copy, readonly) NSString *identifyStr;
@end
/*
增强级结果,具体参数含义参考后台返回字段,结果为透传
*/
@interface WBFaceRiskInfo : NSObject
@property (nonatomic, copy, readonly) NSString *deviceInfoLevel;
@property (nonatomic, copy, readonly) NSString *deviceInfoTag;
@property (nonatomic, copy, readonly) NSString *riskInfoLevel;
@property (nonatomic, copy, readonly) NSString *riskInfoTag;
@end
/**
人脸服务返回结果对象
*/
@interface WBFaceVerifyResult : NSObject
/**
人脸比对结果是否通过:
YES: 表示人脸服务通过
NO: 表示人脸服务不通过
*/
@property (nonatomic, assign, readonly) BOOL isSuccess;
/**
结果对应的订单号
*/
@property (nonatomic, copy, readonly) NSString *orderNo;
/**
isSuccess == YES 时, sign有值, 通过该sign可以去后台拉取本次人脸服务的照片,视频存证
isSuccess == NO 时, sign 无意义
*/
@property (nonatomic, copy, readonly) NSString * sign;
/**
活体检测服务得分
isSuccess == YES 时, liveRate 有值:
1. liveRate 可能是 @"分数为空", 这种情况具体咨询合作方
2. float类型的字符串, 请调用 [liveRate floatValue] 获取具体分数
isSuccess == NO 时, liveRate 无意义
*/
@property (nonatomic, copy, readonly) NSString * liveRate;
/**
人脸比对服务得分
isSuccess == YES 时, similarity 有值:
1. similarity 可能是 @"分数为空", 这种情况具体咨询合作方
2. float类型的字符串, 请调用 [similarity floatValue] 获取具体分数
isSuccess == NO 时, similarity 无意义
*/
@property (nonatomic, copy, readonly) NSString * similarity;
/**
人脸比对图片之一
isSuccess == YES 时, 该属性是上送比对图片之一UIImage的base64编码字符串(图片格式是jpg)
isSuccess == NO 时, 该属性为nil
*/
@property (nonatomic, copy, readonly) NSString * userImageString;
/**
isSuccess == YES 时候, error 无意义
isSuccess == NO 时, error中存储的具体错误信息,参考 WBFaceError.h
*/
@property (nonatomic, strong, readonly) WBFaceError * error;
#pragma mark - 非标专用返回参数
@property (nonatomic, strong, readonly) WBFaceSimpleModeResult *simpleModeResult;
#pragma mark - 增强SDK专用参数
@property (nonatomic, strong, readonly) WBFaceRiskInfo *riskInfo;
#pragma mark - 意愿性SDK返回参数
@property (nonatomic, strong, readonly) WBFaceWillModeResult *willModeResult;
-(NSString *)description;
@end

View File

@@ -0,0 +1,228 @@
//
// WBFaceVerifySDKConfig.h
// Pods
//
// Created by pp on 2017/8/2.
//
//
#import <Foundation/Foundation.h>
#import "WBFaceVerifyConst.h"
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, WBCompareType) {
/// 活体+比对
WBCompareTypeLiveCompare,
/// 仅活体
WBCompareTypeLive,
};
/**
人脸识别SDK 基础配置类
*/
@interface WBFaceVerifySDKConfig : NSObject
/// 是否使用非标模式, 默认为NO具体含义请咨询技术支持
/// - IMPORTANT: 一般不需要开启, 开启前请咨询技术支持
/// - IMPORTANT: 使用原WBCloudFaceVerifySimpleSDK升级过来的务必打开此项
@property (nonatomic, assign) BOOL useSimpleMode;
#pragma mark - common
/**
sdk中拉起人脸活体识别界面中使用UIWindow时的windowLevel配置,默认配置是1 + UIWindowLevelNormal
如果接入放app中有其他自定义UIWindow, 为了防止界面覆盖,可以酌情设置该参数
*/
@property (nonatomic, assign) NSUInteger windowLevel;
/**
人脸识别服务结果页是否展示配置项 - 是否展示人脸对比成功界面 -> 建议关闭
default: NO
*/
@property (nonatomic, assign) BOOL showSuccessPage DEPRECATED_MSG_ATTRIBUTE("SDK 已移除结果页, 若有需要可参考 Demo 实现");
/**
人脸识别服务结果页是否展示配置项 - 是否展示人脸对比失败界面 -> 建议关闭
default: NO
*/
@property (nonatomic, assign) BOOL showFailurePage DEPRECATED_MSG_ATTRIBUTE("SDK 已移除结果页, 若有需要可参考 Demo 实现");
/**
人脸识别服务是否进行通过录像, 从而进行视频存证
default: NO
*/
@property (nonatomic, assign) BOOL recordVideo;
/**
人脸识别服务是否强制校验视频,当视频为空时报错
可能会出现在部分性能差的机型
default: NO
*/
@property (nonatomic, assign) BOOL checkVideo;
/**
是否由SDK内部处理sdk网络请求的cookie
默认值: YES
*/
@property (nonatomic, assign) BOOL manualCookie;
/**
多语言配置
默认中文,当使用其他语言时,强制静音
*/
@property (nonatomic, assign) WBFaceVerifyLanguage language;
/**
人脸识别页面中的主题风格, 需要配合不同资源包使用:
WBFaceVerifyThemeDarkness - 暗灰主题
WBFaceVerifyThemeLightness - 明亮主题
- 当前意愿性表达只支持明亮主题, 若使用了意愿性表达功能则强制设定为明亮主题
*/
@property (nonatomic, assign) WBFaceVerifyTheme theme;
/**
是否静音
默认值YES
*/
@property (nonatomic, assign) BOOL mute;
/**
刷脸服务走iPv6协议栈
默认YES
*/
@property (nonatomic, assign) BOOL isIpv6 DEPRECATED_ATTRIBUTE;
/**
是否海外用户
默认NO
*/
@property (nonatomic, assign) BOOL isAbroad;
/**
是否打开日志上报
1打开 0关闭 -1由SDK内部决定
默认:-1
*/
@property (nonatomic, assign) NSInteger enableTrackLog DEPRECATED_ATTRIBUTE;
/*
送入自定义提示文案的位置
默认WBFaceCustomTipsLoc_Bottom
*/
@property (nonatomic, assign) WBFaceCustomTipsLoc tipsLoc;
/*
检测过程中展示的文案
默认为空
*/
@property (nonatomic, copy) NSString *customTipsInDetect;
/*
上传过程中展示的文案
默认为空
*/
@property (nonatomic, copy) NSString *customTipsInUpload;
/*
底部提示文案长度不超过70字
*/
@property (nonatomic, copy, nullable) NSString *bottomCustomTips;
/*
底部提示文案富文本版本长度不超过70字
*/
@property (nonatomic, copy, nullable) NSAttributedString *bottomCustomAttributedTips;
/*
退出二次确认UI配置
*/
@property (nonatomic, copy) NSString *exitAlertTitle; //标题
@property (nonatomic, copy) NSString *exitAlertMessage; //内容
@property (nonatomic, copy) NSString *exitAlertYES; //确认按钮
@property (nonatomic, copy) NSString *exitAlertNO; //取消按钮
/*
如果有使用苹果分屏模式UIWindowScene打开此开关
Xcode11新建工程有使用Scene可以参考资料自行调整
默认为NO
*/
@property (nonatomic, assign) BOOL useWindowSecene;
/// 使用 hostVC 以实现基于 Modal 的 transition, **一般不需要配置, 仅建议 native 开发者使用**
/// - IMPORTANT: **一般不需要配置, 仅建议 native 开发者酌情使用**
@property (nonatomic, weak, nullable) UIViewController *hostVC;
/**
TencentCloudHuiyanSDKFace.bundle 的目录路径不包含bundle本身仅当需要自己下发资源时配置本地资源无需配置
重要此目录下必须包含TencentCloudHuiyanSDKFace.bundle 文件否则无法拉起SDK
*/
@property (nonatomic, copy) NSString *bundlePath;
/**
face-tracker-v003.bundle 的目录路径
!!!重要:若有值,此目录下必须包含 face-tracker-v003.bundle 文件否则无法拉起SDK
*/
@property (nonatomic, copy, nullable) NSString *faceTrackerBundleDirPath;
/**
face-tracker-v003.bundle 是否经过重新打包, 默认值为 NO, **一般不需要配置**
*/
@property (nonatomic) BOOL faceTrackerBundleRepackaged;
/**
是否采用增强比对服务仅增强接口生效仅活体服务设置为NO
默认为 NO
*/
@property (nonatomic, assign) BOOL useAdvanceCompare;
/// 服务类型, 默认为 LiveCompare, **一般不需要修改**
@property (nonatomic, assign) WBCompareType compareType;
/**
APP是否只允许横屏非强制横屏的不用设置否则可能会出现旋转问题
@default NO
*/
@property (nonatomic, assign) BOOL forceOrientation;
#pragma mark - simple //非标特有字段,标准模式无需设置
/**
是否返回录制的视频
default: NO
*/
@property (nonatomic, assign) BOOL returnVideo;
/**
返回视频加密的公钥,如果不配置则不加密
需要recordVideo returnVideo同时为YES才返回加密的视频内容
*/
@property (nonatomic, copy) NSString *publicKey;
/**
AES加密需要用到的IV
*/
@property (nonatomic, copy) NSString *aesIV;
#pragma mark - will //意愿性特有字段,标准模式无需设置
@property (nonatomic, assign) BOOL recordWillVideo;
@property (nonatomic, assign) BOOL checkWillVideo;
/// 播报音量值范围0.1,1]
@property (nonatomic, assign) float willVolume;
/// 当录制意愿视频时是否同时返回sdk+服务端视频
@property (nonatomic, assign) BOOL uploadAndReturnWillVideo;
/// 是否允许意愿阶段使用有线耳机, 默认不允许
@property (nonatomic, assign) BOOL allowWillHeadset;
#pragma mark -
/**
默认sdk配置
*/
+(instancetype)sdkConfig;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,6 @@
framework module TencentCloudHuiyanSDKFace {
umbrella header "TencentCloudHuiyanSDKFace.h"
export *
module * { export * }
}

View File

@@ -0,0 +1,52 @@
//
// CamRisk.h
// CamRisk
//
// Created by 徐森圣 on 2020/12/1.
// Copyright © 2020 Tencent Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <TuringShieldCamRisk/TuringCamRiskTask.h>
#import <TuringShieldCamRisk/TuringCamRiskService.h>
/**
!!!: 一、服务概览
本服务旨在对摄像头风险进行识别。由于识别引擎和预测模型均在云端,因此大多数服务均为异步接口。
!!!: 二、主要接口介绍
TuringCamRiskService
|
| 创建检测任务
|
v
TuringCamRiskTask
|
| 产生请求数据
v
NSData
更多的信息请参阅 TuringCamRiskService.h 和 TuringCamRiskTask.h中的注释
!!!: 三、一般使用范例
```objective-c
// 为服务配置上下文可用的key有多个这里只简单例举一个参见TuringCamRiskContextKey中的枚举字符串
[[TuringCamRiskService sharedService] setupContext:@{ TuringCamRiskContextAppIDKey: @"F.R.D." }];
// 创建一个检测任务
TuringCamRiskTask *task = [[TuringCamRiskService sharedService] taskForSceneID:nil];
// 为任务指定监控的视图,检测群控风险(此动作可选)
[task monitorView:[UIApplication sharedApplication].keyWindow];
// 为任务指定监控的摄像头设备,检测劫持风险(注意请提供正在使用的设备;此动作可选)
[task monitorCameraWithDevice:cameraDevice session:captureSession previewView:previewLayer];
// 获取用于请求的数据
[task queryPostDataWithCompletionHandler:^(NSData * _Nullable data, NSError * _Nullable error) {
// 如果成功data非空error为空如果失败data为空error非空
// data可用于http post直接请求图灵盾服务
NSLog(@"data = %@, error = %@", error);
}];
```
*/

View File

@@ -0,0 +1,122 @@
//
// TuringCamRiskService.h
// TuringShieldCamRisk
//
// Created by 徐森圣 on 2020/12/2.
// Copyright © 2020 Tencent Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <TuringShieldCamRisk/TuringServiceDefine.h>
#import <TuringShieldCamRisk/TuringServiceSettings.h>
#import <TuringShieldCamRisk/TuringCamRiskTask.h>
/// 这些常量值用于设置或获取context中的字典数据中的key。
typedef NSString * TuringCamRiskContextKey NS_EXTENSIBLE_STRING_ENUM;
/// 用于设置请求序列编号的key参见 `TuringCamRiskContextKey`。该key对应的值应为 NSString *。
extern TuringCamRiskContextKey const _Nonnull TuringCamRiskContextRequestSequenceKey;
/// 用于设置meta data的key参见 `TuringCamRiskContextKey`。该key对应的值应为 NSString *。
extern TuringCamRiskContextKey const _Nonnull TuringCamRiskContextMetaDataKey;
/// 用于设置接入渠道号的key参见 `TuringCamRiskContextKey`。该key对应的值应为 NSString *。
extern TuringCamRiskContextKey const _Nonnull TuringCamRiskContextChannelKey;
/// 用于设置接入构建号的key参见 `TuringCamRiskContextKey`。该key对应的值应为 NSNumber *。
extern TuringCamRiskContextKey const _Nonnull TuringCamRiskContextBuildNoKey;
/// 用于设置接入版本号的key参见 `TuringCamRiskContextKey`。该key对应的值应为 NSString *。
extern TuringCamRiskContextKey const _Nonnull TuringCamRiskContextVersionKey;
/// 用于设置接入版本LC的key参见 `TuringCamRiskContextKey`。该key对应的值应为 NSString *。
extern TuringCamRiskContextKey const _Nonnull TuringCamRiskContextLCKey;
/// 用于设置其它额外信息的key参见 `TuringCamRiskContextKey`。该key对应的值应为 NSString *。
extern TuringCamRiskContextKey const _Nonnull TuringCamRiskContextExtraInfoKey;
/// 用于设置接入App ID的key参见 `TuringCamRiskContextKey`。该key对应的值应为 NSString *。
extern TuringCamRiskContextKey const _Nonnull TuringCamRiskContextAppIDKey;
@interface TuringCamRiskConfiguration : NSObject
/// 禁止直接生成实例
- (nonnull instancetype)init NS_UNAVAILABLE;
@property (assign) int32_t channelID TS_AVAILABLE_IF(TS_ENABLES_CUSTOM_CHANNEL_ID);
@property (nullable, nonatomic, copy) NSString *URLForTarsServer TS_AVAILABLE_IF(TS_NETWORKING_TMF_SHARK_SUPPORTS);
@property (nullable, nonatomic, copy) NSString *valificationFilePath TS_AVAILABLE_IF(TS_USING_SIGN_VALIFICATION);
@end
@interface TuringCamRiskService : NSObject
+ (nullable NSError *)setupWithConfiguration:(nullable void(^)(TuringCamRiskConfiguration *_Nonnull config))configurationHandler;
+ (void)setupTarsServerWithURL:(nonnull NSString *)URLString withChannelID:(int32_t)ChannelID TS_AVAILABLE_IF(TS_NETWORKING_TMF_SHARK_SUPPORTS)
TS_MSG_DEPRECATED("Use `-setupTarsServerWithURL:withChannelID:withLicense:` instead");
/// 禁止直接生成实例
- (nonnull instancetype)init NS_UNAVAILABLE;
/// 所有服务均以此单例提供
+ (nonnull instancetype)sharedService;
/// 预连接服务器网络,以便加速后续请求的回应速度
+ (void)touchNetworking;
/// 设置全局回调用于控制HTTP请求的发送
/// @param callback 该回调会回传HTTP请求所使用的request对象修改对象属性可改变请求的行为。回调返回NO时将取消请求否则正常执行请求。
/// @discussion 图灵盾完成一个操作可能会执行多个HTTP请求中途改变请求的http目标后无法确保原子操作需要业务自行控制。建议在调用图灵盾任何操作前调用并且只调用一次。
+ (void)setupTarsHTTPPostCallback:(nullable BOOL(^)(NSMutableURLRequest *_Nonnull request))callback TS_AVAILABLE_IF(TS_ALLOWS_HTTP_POST_HANDLING);
/// 设置调用相关的上下文。这些上下文由业务设置,同时回传业务的后端,用于数据稽核。
/// @param context 上下文的内容。字典中用到的key请参考`TuringCamRiskContextKey`及其常量定义。
- (void)setupContext:(nonnull NSDictionary<TuringCamRiskContextKey, id> *)context;
/// 生成一个摄像头检测任务并接受TuringCamRiskService的管理。如果相同sceneID的任务已经生成则会
/// 返回同一个任务实例,直到该实例被`- detatchTask:`释放。
/// @param sceneID 摄像头检测任务的场景ID
/// @discussion 如果sceneID为空则该任务不会被TuringCamRiskService管理也不需要调用
/// `- detatchTask:`释放
- (nonnull TuringCamRiskTask *)taskForSceneID:(nullable NSString *)sceneID;
/// 释放一个摄像头检测任务
/// @param task 要释放的任务实例
- (void)detatchTask:(nonnull TuringCamRiskTask *)task;
+ (nonnull NSDictionary *)SDKInfo;
@end
@interface TuringCamRiskService (Validation)
+ (nullable NSError *)verifySDKUsingLisence:(nullable NSString *)licenseFilePath TS_AVAILABLE_IF(TS_USING_SIGN_VALIFICATION);
@end
/// 设备实时风险标签
@interface TuringCamRiskService (RiskToken)
/// 获取实时风险标签
/// @param usingCache 是否使用缓存。YES表示由图灵盾SDK根据缓存策略决定是否更新缓存NO表示总是联网获取实时结果。
/// @param completion 获取结果的回调
/// @discussion 一般我们建议usingCache设置为YES。仅当在对风险检测要求特别高的场景下才设置为NO。图灵盾SDK能有效管理缓存并确保缓存的检测安全效果同时节省请求流量和服务计算成本。同时由于您可能不够理解何时可以使用缓存而何时需要更新缓存因此我们不建议客户端自行缓存我们的结果。
- (void)fetchRiskTokenUsingCache:(BOOL)usingCache WithCompletionHandler:(nonnull void(^)(NSString *_Nullable message, NSError *_Nullable error))completion TS_AVAILABLE_IF(TS_ENABLES_RISK_DETECT_FEATURE);
@end
@interface TuringCamRiskService (Debugging)
/// 设置是否使用测试服务器
/// @discussion 注意只能在未使用任何 TuringCamRiskService 的服务之前设置,否则某些正在进行中的
/// 服务可能会出现错误
@property (class, nonatomic) BOOL usesDebugServer TS_AVAILABLE_IF(__TS_OR(TS_NETWORKING_WUP_SUPPORTS, TS_NETWORKING_SHARK_SUPPORTS));
@end

View File

@@ -0,0 +1,52 @@
//
// TuringCamRiskTask.h
// TuringShieldCamRisk
//
// Created by 徐森圣 on 2020/12/2.
// Copyright © 2020 Tencent Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import <UIKit/UIKit.h>
/// 摄像头检测任务
/// @example
/// ```
/// [task queryPostDataWithCompletionHandler:^(NSData * _Nullable data, NSError * _Nullable error) {
/// // error为空时可以用于发送到图灵盾服务器
/// }];
/// ```
@interface TuringCamRiskTask : NSObject
/// 禁止直接创建摄像头检测任务
- (nonnull instancetype)init NS_UNAVAILABLE;
/// 为任务指定要监控的摄像头设备及其相关信息,需要调用`-postWithCompletionHandler:`或者
/// `-queryPostDataWithCompletionHandler`之前调用。
/// @param cameraDevice 受监控的摄像头设备
/// @param session 受监控的摄像会话
/// @param previewLayer 受监控的预览图层
/// @discussion 调用该方法是可选的,但会提升检测的准确性
- (void)monitorCameraWithDevice:(nullable AVCaptureDevice *)cameraDevice session:(nullable AVCaptureSession *)session previewView:(nullable AVCaptureVideoPreviewLayer *)previewLayer;
/// 为任务指定要监控的用户界面通常是一个用户可操作的视图例如viewController.view或者一个按钮
/// @param view 受监控的用户界面
/// @discussion 调用该方法是可选的,但会提升检测的准确性
- (void)monitorView:(nonnull UIView *)view;
/// 请求检测
/// @param completionHandler 请求完成的回调函数。如果正确返回则result非空否则error非空
/// @discussion 数据将会直接发送到图灵盾服务器,只是为了便于测试连通性而提供该接口。
- (void)postWithCompletionHandler:(nullable void(^)(NSDictionary<NSString *, id> *_Nullable result, NSError *_Nullable error))completionHandler;
/// 生成用于请求的数据包
/// @param completionHandler 请求完成的回调函数。如果正确返回则data非空否则error非空
- (void)queryPostDataWithCompletionHandler:(nonnull void(^)(NSData *_Nullable data, NSError *_Nullable error))completionHandler;
/// 任务的场景ID
@property (nonatomic, copy, readonly, nonnull) NSString *scene;
@end

View File

@@ -0,0 +1,282 @@
//
// TuringServiceDefine.h
// TuringShield
//
// Created by 徐森圣 on 2018/3/13.
// Copyright © 2018年 Tecent Inc. All rights reserved.
//
// $$api_level=TS_TURING_SHIELD_OPEN_API_LEVEL$$
//
//
#ifndef __TURING_SERVICE_DEFINE_H__
#define __TURING_SERVICE_DEFINE_H__
#import "TuringServiceSettings.h"
#define TS_OBJECT_CLASS(name) TS_CLASS_##name
#define TS_OBJECT_IMPL(name) TS_REAL_##name
#define TS_OBJECT_DECL(name) \
@protocol TS_OBJECT_CLASS(name) <NSObject> \
@end \
typedef NSObject<TS_OBJECT_CLASS(name)> *name##_t
#define TS_OBJECT_DECL_SUBCLASS(name, super) \
@protocol TS_OBJECT_CLASS(name) <TS_OBJECT_CLASS(super)> \
@end \
typedef NSObject<TS_OBJECT_CLASS(name)> *name##_t
#if defined(__cplusplus)
#define TS_BEGIN_DECLS extern "C" {
#define TS_END_DECLS }
#else
#define TS_BEGIN_DECLS
#define TS_END_DECLS
#endif
TS_OBJECT_DECL(ts_object);
/**
将浮点类型的秒数转换为长整数类型的毫秒数
@param sec 秒数需要为double类型
@return 毫秒数long long类型
*/
#define SEC_TO_MSEC(sec) (int64_t)( (sec) * 1000ll )
/**
如果condition的定义为0或未定义则声明函数不可用
@param condition 一个可展开的宏定义
*/
#define TS_AVAILABLE_IF(condition) \
__TS_IF_ELSE(condition) \
/*Case True*/ (__TS_EMPTY()) \
/*Case False*/(UNAVAILABLE_ATTRIBUTE)
/**
如果c1或c2中任意一个的定义为0或未定义则声明函数不可用
@param c1 条件1一个可展开的宏定义
@param c2 条件2一个可展开的宏定义
*/
#define TS_AVAILABLE_IFS(c1, c2) \
__TS_IF_ELSE(c1) \
/*Case True*/ (TS_AVAILABLE_IF(c2)) \
/*Case False*/(UNAVAILABLE_ATTRIBUTE)
/**
如果当前线程是主线程,直接执行包含的短语句;如果当前不在主线
程,将包含的短语句调度到主线程执行,并阻塞当前线程。
@param ... 一个需要调度到主线程执行的短语句
*/
#define TSMainThreadProtectCall(...) do { \
if ([NSThread isMainThread] == NO) { \
dispatch_sync(dispatch_get_main_queue(), ^{ \
__VA_ARGS__; \
}); \
} \
else { \
__VA_ARGS__; \
} \
} while (0)
/**
如果当前线程是主线程,直接执行包含的短语句;如果当前不在主线
程,将包含的短语句调度到主线程执行,并阻塞当前线程。然后返回
短语句执行的结果。注意如果返回值是Objective C对象目前
不支持MRC。
@param ... 一个需要调度到主线程执行的短语句
@return 短语句的返回值
*/
#define TSMainThreadProtectGet(...) ({ \
typeof(__VA_ARGS__) val; \
if ([NSThread isMainThread] == NO) { \
__block typeof(val) bval; \
dispatch_sync(dispatch_get_main_queue(), ^{ \
bval = __VA_ARGS__; \
}); \
val = bval; \
} \
else { \
val = __VA_ARGS__; \
} \
val; \
})
#define __1second (1.0f)
#define __10seconds (__1second * 10)
#define __20seconds (__1second * 20)
#define __1minute (__1second * 60)
#define __10minutes (__1minute * 10)
#define __30minutes (__1minute * 30)
#define __1hour (__1minute * 60)
#define __1day (__1hour * 24)
#define __1week (__1day * 7)
#define ts_shutup(v) (void)(v)
///
/// there's a stupid bug in @available:
/// If we build TuringShield in Xcode 11 and use @available in TuringShield, Xcode 11 is ALSO required
/// on building the An app that integrating TuringShield. The main reason is, the implementation of
/// @available in Xcode 11 is different to the one in Xcode 10.
/// So let's disable @available for time being.
///
#if 0
#define ts_ios_version_is_at_least(major, minor, patch) @available(iOS major##.##minor##.##patch, *)
#else
#define ts_ios_version_is_at_least(major, minor, patch) \
({ \
NSOperatingSystemVersion v = \
NSProcessInfo.processInfo.operatingSystemVersion; \
v.majorVersion == major ? \
( v.minorVersion == minor ? \
( v.patchVersion >= patch ) : \
( v.minorVersion > minor ) ) : \
( v.majorVersion > major ); \
})
#endif
#if defined(TS_SDK_CHANNEL_ID) && TS_USES_CLASS_ALIAS
#define tsclassname(name) __TS_CAT(name, TS_ALIAS_SURFIX)
#define tsmethodname(name) __TS_CAT(TS_ALIAS_SURFIX, name)
#define tsclass(className) class tsclassname(className); @compatibility_alias className tsclassname(className)
#else
#define tsclassname(name) name
#define tsmethodname(name) name
#define tsclass(className) class className
#endif
#define ts_channel_alias(name) __TS_CAT(name, __TS_CAT(_, TS_SDK_CHANNEL_ID))
#define TS_DEPRECATED __attribute__((deprecated))
#define TS_MSG_DEPRECATED(msg) __attribute((deprecated((msg))))
#pragma mark - Inner Macro, do NOT use
#define __TS_ARG_0_(n, ...) n
#define __TS_ARG_1_(x0, n, ...) n
#define __TS_ARG_2_(x0, x1, n, ...) n
#define __TS_ARG_3_(x0, x1, x2, n, ...) n
#define __TS_ARG_4_(x0, x1, x2, x3, n, ...) n
#define __TS_ARG_5_(x0, x1, x2, x3, x4, n, ...) n
#define __TS_ARG_6_(x0, x1, x2, x3, x4, x5, n, ...) n
#define __TS_ARG_7_(x0, x1, x2, x3, x4, x5, x6, n, ...) n
#define __TS_ARG_8_(x0, x1, x2, x3, x4, x5, x6, x7, n, ...) n
#define __TS_ARG_9_(x0, x1, x2, x3, x4, x5, x6, x7, x8, n, ...) n
#define __TS_EVAL(...) __TS_EVAL1(__TS_EVAL1(__TS_EVAL1(__VA_ARGS__)))
#define __TS_EVAL1(...) __TS_EVAL2(__TS_EVAL2(__TS_EVAL2(__VA_ARGS__)))
#define __TS_EVAL2(...) __TS_EVAL3(__TS_EVAL3(__TS_EVAL3(__VA_ARGS__)))
#define __TS_EVAL3(...) __TS_EVAL4(__TS_EVAL4(__TS_EVAL4(__VA_ARGS__)))
#define __TS_EVAL4(...) __TS_EVAL5(__TS_EVAL5(__TS_EVAL5(__VA_ARGS__)))
#define __TS_EVAL5(...) __VA_ARGS__
#define __TS_TO_CSTRING_(str) #str
#define __TS_TO_CSTRING(...) __TS_TO_CSTRING_(__VA_ARGS__)
#define __TS_TO_NSSTRING_(str) @#str
#define __TS_TO_NSSTRING(...) __TS_TO_NSSTRING_(__VA_ARGS__)
#define __TS_PRIMITIVE_CAT(a, ...) a##__VA_ARGS__
#define __TS_CAT(a, ...) __TS_PRIMITIVE_CAT(a, __VA_ARGS__)
#define __TS_ARG_0(n, ...) n
#define __TS_ARG_1(x0, n, ...) n
#define __TS_IS_PROBE(...) __TS_ARG_1(__VA_ARGS__, 0)
#define __TS_PROBE() ~, 1
#define __TS_NOT(x) __TS_IS_PROBE(__TS_CAT(__TS_NOT_, x))
#define __TS_NOT_0 __TS_PROBE()
#define __TS_BOOL(x) __TS_NOT(__TS_NOT(x))
#define __TS_AND(x1, x2) __TS_IF_ELSE(x1)(__TS_IF_ELSE(x2)(1)(0))(0)
#define __TS_AND_3(x1, x2, x3) __TS_AND(x1, __TS_AND(x2, x3))
#define __TS_AND_4(x1, x2, x3, x4) __TS_AND(__TS_AND(x1, x2), __TS_AND(x3, x4))
#define __TS_OR(x1, x2) __TS_IF_ELSE(x1)(1)(__TS_IF_ELSE(x2)(1)(0))
#define __TS_OR_3(x1, x2, x3) __TS_OR(x1, __TS_OR(x2, x3))
#define __TS_IIF(c) __TS_PRIMITIVE_CAT(__TS_IIF_, c)
#define __TS_IIF_0(...)
#define __TS_IIF_1(...) __VA_ARGS__
#define __TS_IELSE(c) __TS_PRIMITIVE_CAT(__TS_IELSE_, c)
#define __TS_IELSE_0(...) __VA_ARGS__
#define __TS_IELSE_1(...)
#define __TS_IIF_ELSE(c) __TS_PRIMITIVE_CAT(__TS_IIF_ELSE_, c)
#define __TS_IIF_ELSE_0(...) __TS_IELSE_0
#define __TS_IIF_ELSE_1(...) __VA_ARGS__ __TS_IELSE_1
#define __TS_IF(c) __TS_IIF(__TS_BOOL(c))
#define __TS_IF_ELSE(c) __TS_IIF_ELSE(__TS_BOOL(c))
#define __TS_EMPTY()
#define __TS_DEFER(id) id __TS_EMPTY()
#define __TS_OBSTRUCT(...) __VA_ARGS__ __TS_DEFER(__TS_EMPTY)()
#pragma mark - API Levels
#define TS_ALWAYS_VISIBLE __attribute__ ((visibility ("default")))
#define TS_ALWAYS_HIDDEN __attribute__ ((visibility ("hidden")))
#define TS_TURING_HIGHER_WRAPPER_LEVEL 1
#define TS_TURING_SHIELD_OPEN_API_LEVEL 2
#define TS_FRIENDLY_API_LEVEL 3
#define TS_PRIVATE_LEVEL 4
#if TS_API_LEVEL >= TS_TURING_HIGHER_WRAPPER_LEVEL && !!TS_TURING_ID_WRAPPER_APIS
# define TS_TURING_ID_API 1
#else
# define TS_TURING_ID_API 0
#endif
#if TS_API_LEVEL >= TS_TURING_HIGHER_WRAPPER_LEVEL && !!TS_TURING_AGE_WRAPPER_APIS
# define TS_TURING_AGE_API 1
#else
# define TS_TURING_AGE_API 0
#endif
#if TS_API_LEVEL >= TS_TURING_SHIELD_OPEN_API_LEVEL
# define TS_TURING_SHIELD_OPEN_API 1
#else
# define TS_TURING_SHIELD_OPEN_API 0
#endif
#if TS_API_LEVEL >= TS_FRIENDLY_API_LEVEL
# define TS_FRIENDLY_API 1
#else
# define TS_FRIENDLY_API 0
#endif
#if TS_API_LEVEL >= TS_PRIVATE_LEVEL
# define TS_PRIVATE 1
#else
# define TS_PRIVATE 0
#endif
#define TS_VISIBLE_LEVEL(APIKind) \
__TS_IF_ELSE(APIKind) \
/*CASE TRUE*/ (TS_ALWAYS_VISIBLE) \
/*CASE FALSE*/ (TS_ALWAYS_HIDDEN)
#endif /* __TURING_SERVICE_DEFINE_H__ */

View File

@@ -0,0 +1,258 @@
//
// TuringServiceSettings.h
// TuringShield
//
// Created by 徐森圣 on 2018/3/19.
// Copyright © 2018年 Tecent Inc. All rights reserved.
//
#ifndef TuringServiceSettings_h
#define TuringServiceSettings_h
/**
编译目标,用于检查变量是否正确
格式为TS_BUILD_TARGET_xxx
@discussion
受Build Settings中环境变量TS_BUILD_TARGET影响并自动更新
*/
#define TS_BUILD_TARGET_YOUTU
/**
定义为1使用主人识别模型
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_OWNER_PROJECT 0
/**
定义为1使用青少年识别模型
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_AGE_PROJECT 0
/**
定义为1使用人机识别模型
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_HUMAN_PROJECT 0
/**
渠道号,用于决定用哪个模型
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_SDK_CHANNEL_ID 108138
#define TS_SDK_CHANNEL_STRING __TS_TO_NSSTRING(TS_SDK_CHANNEL_ID)
/**
SDK是否自带数据请求和回复逻辑
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_ENABLES_DATA_SENDING 1
/**
SDK是否自带数据处理逻辑
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_ENABLES_PREDICTION_PROCEEDING 1
/**
SDK是否带请求签名逻辑云端请求需要WAF服务配合SDK需要打开
TS_ENABLES_DATA_SENDING和TS_HUMAN_PROJECT
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_ENABLES_HTTP_REQUEST_SIGN 0
/**
如果设置为非0则同一个场景scene和事件action最多保留指定数量的数据
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_LIMITED_RECORDS_PER_SCENE_ACTION 20
/**
实验室模式,某些逻辑在工程化前后可能有变化,服务器接口的调用方式也可能不一致
目前人机部分默认值为0主人识别部分默认值为1
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_ENABLES_LAB_LOGIC 0
/**
打开日志打印
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_ENALBLES_LOG_PRINT 0
/**
使用模型预测之前不检查数据非空
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_DONT_CHECK_DATA_SIZE 0
/**
不记录(当然也不上报)触摸事件中的位置信息
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_DONT_RECORD_TOUCH_POSITION 0
/**
不加密打包的数据
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_DONT_ENCRYPT_PACKING_DATA 0
/**
不压缩打包的数据
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_DONT_COMPRESS_PACKING_DATA 0
/**
使用设备指纹特性
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_ENABLES_FINGERPRINT_FEATURE 1
/**
支持的打包方式WUP协议
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_NETWORKING_WUP_SUPPORTS 1
/**
支持的打包方式Shark协议
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_NETWORKING_SHARK_SUPPORTS 1
/**
支持的打包方式TMF Shark协议
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_NETWORKING_TMF_SHARK_SUPPORTS 0
/**
是否支持云控设备指纹配置;目前私有化部署不支持该选项
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_ENABLES_FINGERPRINT_CONFIG_CONTROL 1
/**
是否支持关键API篡改检测
@discussion
受Build Settings中同名环境变量影响并自动更新
*/
#define TS_ENABLES_KEYED_API_CHECKING 1
/**
绑定的App bundle ID
@discussion
设置后SDK将只能运行在指定的App上
*/
#define TS_BOUND_BUNDLE_IDENTIFIER nil
#define TS_BOUND_BUNDLE_TOKEN { 0x00 }
/**
是否允许多渠道复用SDK
@discussion
若打开并且初始渠道号为0则必须设置渠道号后才可以开始调用相关功能
*/
#define TS_ENABLES_CUSTOM_CHANNEL_ID 0
#define TS_DOMAIN_PREFIX_TOKEN com.tencent.TuringShield.
#define TS_DOMAIN_PREFIX_CSTRING __TS_TO_CSTRING(TS_DOMAIN_PREFIX_TOKEN)
#define TS_DOMAIN_PREFIX_STRING __TS_TO_NSSTRING(TS_DOMAIN_PREFIX_TOKEN)
#define TS_DOMAIN_FOR_REACHABLITTY_TEST 8.8.8.8
#define TS_DOMAIN_FOR_REACHABLITTY_TEST_CSTRING __TS_TO_CSTRING(TS_DOMAIN_FOR_REACHABLITTY_TEST)
#define TS_DOMAIN_FOR_REACHABLITTY_TEST_STRING __TS_TO_NSSTRING(TS_DOMAIN_FOR_REACHABLITTY_TEST)
/**
一些临时用的开关
*/
#define TS_ENABLES_SENSOR_RECORDING 0
#define TS_ENABLES_SENSOR_REPLAYING 0
#define TS_USES_OLD_MOTION_TRACKER_IF_NEEDED 1
#define TS_ENABLES_CUSTOM_CLIENT_VERSION 0
#define TS_ENABLES_CUSTOM_CHANNEL_ID 0
#define TS_USES_CLASS_ALIAS 2
#define TS_ACT_AS_TAID_ADVERTISER 0
#define TS_ACT_AS_TAID_PROVIDER 1
#define TS_ENABLES_FINGERPRINT_CONFIG_TEST 0
#define TS_API_LEVEL TS_FRIENDLY_API_LEVEL
#define TS_AVOID_USING_IDFA 1
#define TS_FEATURE_DELEGATION 0
#define TS_ENABLES_DEVICE_INFO_ACCESS 0
#define TS_TURING_ID_WRAPPER_APIS 0
#define TS_TURING_AGE_WRAPPER_APIS 0
#define TS_ANTIBOT_SDK 0
#define TS_RISK_TOKEN_SDK 0
#define TS_ENABLES_UAID_FETCHING 0
#define TS_ENABLES_PHONE_MASK_FETCHING 0
#define TS_ENABLES_RISK_DETECT_FEATURE 1
#define TS_USES_RANDOM_NAMING 1
#define TS_USES_GMSSL_AS_ENCRYPTION_ALGORITHM 0
#define TS_ALLOWS_HTTP_POST_HANDLING 1
#define TS_SKIP_GATHERER_AUTO_HANDLING 0
#define TS_SIGNING_TOKEN_FEATURE 0
#define TS_USING_SIGN_VALIFICATION 0
#define TS_ENABLES_UNIVERSAL_TOKEN 0
#define TS_USES_IDFV_LOCK 0
#define TS_CAFISBRAIN_SDK 0
#define TS_SDK_VERSION 20074
#define TS_SDK_LC_CODE QINN2D9KC5XY90F0
#define TS_SDK_LC __TS_TO_NSSTRING(TS_SDK_LC_CODE)
#define TS_SDK_BUILD_DATE 2024-08-15 19:28:34
#define TS_ALIAS_SURFIX _YOUTU108138v20074
#endif /* TuringServiceSettings_h */

View File

@@ -0,0 +1,16 @@
#define ANDROID_CUSTOM_NONE (1)
#define ANDROID_CUSTOM_FOR_IOT (0)
#define ANDROID_CUSTOM_FOR_UNIONPAY (0)
#define ANDROID_CUSTOM_SUPPORT_VTS (0)
//vts && vndk: https://source.android.com/devices/architecture/images/VNDK.pdf
#define CUSTOM_FOR_QQ (0)
#define ALLOW_EMPTY_SECRET_KEY (1)
// change namespace for different business
#define YTLICENSE_NAMESPACE ytliveness
#define CLASS_WITH_PREFIX(__class) YTLiveness##__class
#define FUNCTION_WITH_PREFIX(__func) ytliveness_##__func
#define INNER_INTERFACE_USE_NAMESPACE (1)

View File

@@ -0,0 +1,79 @@
/**
* @file yt_auth.h
* @author tencent
* @brief 鉴权接口
* @version 2.0
* @date 2020-09-10
*
* @copyright Copyright (c) 2020
*
*/
#ifndef _YT_AUTH_H_
#define _YT_AUTH_H_
#include "yt_defines.h"
// license文件申请https://docs.qq.com/doc/DZERXWmNYeVNyWlF0
/**
* @brief 使用license文件初始化授权
* @param `platform_context` Android平台输入JNIEnv*其他平台输入NULL
* @param `license_path` Android平台将license文件打包到assets中传入文件名其他平台传入文件完整路径
* @param `secret_key` 传入license对应的secret_key在申请的时候获得
* @return 授权结果0代表成功错误码参考[授权错误代码](#errorcode)
*/
YT_PUBLIC int ytliveness_auth_init_by_path(void* platform_context, const char* license_path, const char* secret_key);
/**
* @brief 使用license字符串初始化鉴权字符串获取方式将license文件做base64即可
* @param `platform_context` Android平台输入JNIEnv*其他平台输入NULL
* @param `license_string` license字符串
* @param `secret_key` 传入license对应的secret_key在申请的时候获得
* @return 授权结果0代表成功错误码参考[授权错误代码](#errorcode)
*/
YT_PUBLIC int ytliveness_auth_init_by_string(void* platform_context, const char* license_string, const char* secret_key);
/**
* @brief 腾讯内部业务专用授权接口
* @param `platform_context` Android平台输入JNIEnv*其他平台输入NULL
* @return 授权结果0代表成功错误码参考[授权错误代码](#errorcode)
*/
YT_PUBLIC int ytliveness_auth_init_for_qq(void* platform_context);
/**
* @brief 授权成功后,查询授权有效期
* @return 授权到期时间的时间戳
*/
YT_PUBLIC long long ytliveness_auth_get_endtime();
/**
* @brief 查询授权库的版本
* @return 授权库的版本号
*/
YT_PUBLIC const char* ytliveness_auth_get_version();
/**
* @brief 获取已授权的SDK列表
* @param sdklist_buf 出参返回sdklist调用者自己分配一个int[]数组用于存储SDKlist
* @param max_count 入参传入的sdklist_buf的最大index
* @return 实际返回的sdklist数量
* @note 如果sdklist_buf传NULL返回值代表SDK列表的总数
*/
YT_PUBLIC int ytliveness_auth_get_sdklist_ids(int* sdklist_buf, int max_count);
/**
* @brief 获取sdk_id代表的SDK名称
* @param sdk_id
* @return 该id代表的SDK名称
*/
YT_PUBLIC const char* ytliveness_auth_get_sdkname(int sdk_id);
/**
* @brief 设置是否显示log默认为显示
* @param enable1-显示 0-不显示
* @return
*/
YT_PUBLIC void ytliveness_auth_enable_log(int enable);
#endif

View File

@@ -0,0 +1,21 @@
#import <Foundation/Foundation.h>
__attribute__((visibility("default"))) @interface YTLivenessAuthManager : NSObject
+ (int)initAuthByFilePath:(NSString*) license_path withSecretKey:(NSString*) secret_key;
+ (int)initAuthByString:(NSString*) license_string withSecretKey:(NSString*) secret_key;
+ (int)initAuthForQQ;
+ (NSString*)getVersion;
+ (int64_t)getEndTime;
+ (NSArray*)getSDKList;
+ (NSString*)getSDKNameByID:(int)sdk_id;
+ (void)setEnableLog:(int)enable;
@end

View File

@@ -0,0 +1,15 @@
#ifndef __YT_AUTH_ERRORCODE_H__
#define __YT_AUTH_ERRORCODE_H__
#define YT_AUTH_ERROR_FETCH_FAIL (1002)
#define YT_AUTH_ERROR_DECODE_FAIL (3004)
#define YT_AUTH_ERROR_EMPTY_STRING (3005)
#define YT_AUTH_ERROR_UNMATCH_DEVICE_INFO (3013)
#define YT_AUTH_ERROR_UNMATCH_IDENTIFIER (3015)
#define YT_AUTH_ERROR_EMPTY_IDENTIFIER (3016)
#define YT_AUTH_ERROR_TIME_EXPIRED (3018)
#define YT_AUTH_ERROR_UNMATCH_SECRET_KEY (3024)
#define YT_AUTH_ERROR_INVALID_DEVICE_INFO (4003)
#define YT_AUTH_ERROR_FUNC_NOT_IMPLEMENT (5001)
#endif // __YT_AUTH_ERRORCODE_H__

View File

@@ -0,0 +1,72 @@
#ifndef _YT_DEFINES_H_
#define _YT_DEFINES_H_
// ----------------------------------------------------------------------------
// YouTu for cross platform defines export c api.
// windows @see: http://geoffair.net/ms/declspec.htm
// ----------------------------------------------------------------------------
#if (defined(WIN32) || defined(WIN64))
#ifdef YT_EXPORT
#define YT_PUBLIC_ __declspec(dllexport)
#else
#define YT_PUBLIC_ __declspec(dllimport)
#endif
#else
#ifdef YT_EXPORT
#define YT_PUBLIC_ __attribute__((visibility("default")))
#else
#define YT_PUBLIC_
#endif
#endif
#ifdef __cplusplus
#define YT_PUBLIC extern "C" YT_PUBLIC_
#else
#define YT_PUBLIC YT_PUBLIC_
#endif
// ----------------------------------------------------------------------------
// YouTu error code defines
// ----------------------------------------------------------------------------
#define YT_SUCCESS 0
#define YT_ERROR -1
// init error code: [-10, -99]
#define YT_ERROR_OPEN_FILE -10
#define YT_ERROR_READ_FILE -11
#define YT_ERROR_FILE_EMPTY -12
#define YT_ERROR_RPN_NET_INIT -20
#define YT_ERROR_RPN_NET_NOT_INIT -21
#define YT_ERROR_RPN_INST_INIT -22
#define YT_ERROR_RPN_INST_NOT_INIT -23
#define YT_ERROR_RPN_FORWARD -24
#define YT_ERROR_INVALID_INSTANCE -99
// arguments error code: [-100, -999]
#define YT_ERROR_MUST_NOT_NULL -100
#define YT_ERROR_IMAGE_TYPE -110
#define YT_ERROR_FACE_POINTS -120
#define YT_ERROR_FACE_FIVE_POINTS -121
#define YT_ERROR_FACE_NINETY_POINTS -122
#define YT_ERROR_FACE_RECT -123
#define YT_ERROR_INVALID_MODEL_VERSION -130
#define YT_ERROR_MODEL_THRESHOLDS_SIZE -131
// auth error code
#define YT_ERROR_AUTH_FAILED -1024
// ----------------------------------------------------------------------------
// YouTu common code defines
// ----------------------------------------------------------------------------
#define YT_FACE_FEATURE_SIZE_512 512
#define YT_FACE_FEATURE_SIZE_1024 1024
#define YT_FACE_FIVE_POINTS_SIZE 5
#define YT_FACE_NINETY_POINTS_SIZE 90
#endif // _YT_DEFINES_H_

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>YTCommonLiveness</string>
<key>CFBundleIdentifier</key>
<string>com.tencent.youtu</string>
<key>CFBundleVersion</key>
<string>v2.3.5-liveness.21</string>
<key>CFBundleShortVersionString</key>
<string>v2.3.5-liveness.21</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
</dict>
</plist>

View File

@@ -0,0 +1,217 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_NARY_MAT_ITERATOR_HPP_
#define FBC_CV_CORE_NARY_MAT_ITERATOR_HPP_
/* reference: include/opencv2/core/map.hpp
modules/core/src/matrix.cpp
*/
#include "mat.hpp"
namespace yt_tinycv {
// n-ary multi-dimensional array iterator
// Use the class to implement unary, binary, and, generally, n-ary element-wise operations on multi - dimensional arrays.
template<typename _Tp, int chs> class NAryMatIterator {
public:
// the default constructor
NAryMatIterator();
// the full constructor taking arbitrary number of n-dim matrices
NAryMatIterator(const Mat_<_Tp, chs>** arrays, uchar** ptrs, int narrays = -1);
// the full constructor taking arbitrary number of n-dim matrices
NAryMatIterator(const Mat_<_Tp, chs>** arrays, Mat_<_Tp, chs>* planes, int narrays = -1);
// the separate iterator initialization method
void init(const Mat_<_Tp, chs>** arrays, Mat_<_Tp, chs>* planes, uchar** ptrs, int narrays = -1);
// proceeds to the next plane of every iterated matrix
NAryMatIterator& operator ++();
// proceeds to the next plane of every iterated matrix (postfix increment operator)
NAryMatIterator operator ++(int);
// the iterated arrays
const Mat_<_Tp, chs>** arrays;
// the current planes
Mat_<_Tp, chs>* planes;
// data pointers
uchar** ptrs;
// the number of arrays
int narrays;
// the number of hyper-planes that the iterator steps through
size_t nplanes;
// the size of each segment (in elements)
size_t size;
protected:
int iterdepth;
size_t idx;
};
template<typename _Tp, int chs> inline
NAryMatIterator<_Tp, chs>::NAryMatIterator()
: arrays(0), planes(0), ptrs(0), narrays(0), nplanes(0), size(0), iterdepth(0), idx(0)
{
}
template<typename _Tp, int chs>
NAryMatIterator<_Tp, chs>::NAryMatIterator(const Mat_<_Tp, chs>** _arrays, Mat_<_Tp, chs>* _planes, int _narrays)
: arrays(0), planes(0), ptrs(0), narrays(0), nplanes(0), size(0), iterdepth(0), idx(0)
{
init(_arrays, _planes, 0, _narrays);
}
template<typename _Tp, int chs>
NAryMatIterator<_Tp, chs>::NAryMatIterator(const Mat_<_Tp, chs>** _arrays, uchar** _ptrs, int _narrays)
: arrays(0), planes(0), ptrs(0), narrays(0), nplanes(0), size(0), iterdepth(0), idx(0)
{
init(_arrays, 0, _ptrs, _narrays);
}
template<typename _Tp, int chs>
void NAryMatIterator<_Tp, chs>::init(const Mat_<_Tp, chs>** _arrays, Mat_<_Tp, chs>* _planes, uchar** _ptrs, int _narrays)
{
fprintf(stderr, "NAryMatIterator no impl\n");
FBC_Error("null"); // TODO
/*FBC_Assert(_arrays && (_ptrs || _planes));
int i, j, d1 = 0, i0 = -1, d = -1;
arrays = _arrays;
ptrs = _ptrs;
planes = _planes;
narrays = _narrays;
nplanes = 0;
size = 0;
if (narrays < 0) {
for (i = 0; _arrays[i] != 0; i++)
;
narrays = i;
FBC_Assert(narrays <= 1000);
}
iterdepth = 0;
for (i = 0; i < narrays; i++) {
FBC_Assert(arrays[i] != 0);
const Mat_<_Tp, chs>& A = *arrays[i];
if (ptrs)
ptrs[i] = A.data;
if (!A.data)
continue;
if (i0 < 0) {
i0 = i;
d = 2; // A.dims;
// find the first dimensionality which is different from 1;
// in any of the arrays the first "d1" step do not affect the continuity
for (d1 = 0; d1 < d; d1++)
if (A.size[d1] > 1)
break;
} else {
FBC_Assert(A.size == arrays[i0]->size);
}
if (!A.isContinuous()) {
FBC_Assert(A.step[d - 1] == A.elemSize());
for (j = d - 1; j > d1; j--)
if (A.step[j] * A.size[j] < A.step[j - 1])
break;
iterdepth = std::max(iterdepth, j);
}
}
if (i0 >= 0) {
size = arrays[i0]->size[d - 1];
for (j = d - 1; j > iterdepth; j--) {
int64 total1 = (int64)size*arrays[i0]->size[j - 1];
if (total1 != (int)total1)
break;
size = (int)total1;
}
iterdepth = j;
if (iterdepth == d1)
iterdepth = 0;
nplanes = 1;
for (j = iterdepth - 1; j >= 0; j--)
nplanes *= arrays[i0]->size[j];
} else {
iterdepth = 0;
}
idx = 0;
if (!planes)
return;
for (i = 0; i < narrays; i++) {
FBC_Assert(arrays[i] != 0);
const Mat_<_Tp, chs>& A = *arrays[i];
if (!A.data) {
planes[i] = Mat_<_Tp, chs>();
continue;
}
planes[i] = Mat_<_Tp, chs>(1, (int)size, A.data);
}*/
}
template<typename _Tp, int chs>
NAryMatIterator<_Tp, chs>& NAryMatIterator<_Tp, chs>::operator ++()
{
fprintf(stderr, "NAryMatIterator no impl\n");
/*if (idx >= nplanes - 1)
return *this;
++idx;
if (iterdepth == 1) {
if (ptrs) {
for (int i = 0; i < narrays; i++) {
if (!ptrs[i])
continue;
ptrs[i] = arrays[i]->data + arrays[i]->step[0] * idx;
}
}
if (planes) {
for (int i = 0; i < narrays; i++) {
if (!planes[i].data)
continue;
planes[i].data = arrays[i]->data + arrays[i]->step[0] * idx;
}
}
} else {
for (int i = 0; i < narrays; i++) {
const Mat_<_Tp, chs>& A = *arrays[i];
if (!A.data)
continue;
int _idx = (int)idx;
uchar* data = A.data;
for (int j = iterdepth - 1; j >= 0 && _idx > 0; j--) {
int szi = A.size[j], t = _idx / szi;
data += (_idx - t * szi)*A.step[j];
_idx = t;
}
if (ptrs)
ptrs[i] = data;
if (planes)
planes[i].data = data;
}
}*/
return *this;
}
template<typename _Tp, int chs>
NAryMatIterator<_Tp, chs> NAryMatIterator<_Tp, chs>::operator ++(int)
{
NAryMatIterator<_Tp, chs> it = *this;
++*this;
return it;
}
} // namespace yt_tinycv
#endif // FBC_CV_CORE_NARY_MAT_ITERATOR_HPP_

View File

@@ -0,0 +1,285 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_BASE_HPP_
#define FBC_CV_CORE_BASE_HPP_
// reference: include/opencv2/core/base.hpp
#ifndef __cplusplus
#error base.hpp header must be compiled as C++
#endif
#include <assert.h>
#include <algorithm>
#include <cmath>
#include "fbcdef.hpp"
#include "interface.hpp"
namespace yt_tinycv {
#define FBC_StaticAssert(condition, reason) static_assert((condition), reason " " #condition)
#define FBC_Assert(expr) assert(expr)
#define FBC_Error(msg) \
fprintf(stderr, "Error: "#msg", file: %s, func: %s, line: %d \n", __FILE__, __FUNCTION__, __LINE__); \
assert(0);
template<typename _Tp, typename _AccTp> static inline
_AccTp normL2Sqr(const _Tp* a, int n)
{
_AccTp s = 0;
int i = 0;
for (; i <= n - 4; i += 4) {
_AccTp v0 = a[i], v1 = a[i + 1], v2 = a[i + 2], v3 = a[i + 3];
s += v0*v0 + v1*v1 + v2*v2 + v3*v3;
}
for (; i < n; i++) {
_AccTp v = a[i];
s += v*v;
}
return s;
}
template<typename _Tp, typename _AccTp> static inline
_AccTp normL1(const _Tp* a, int n)
{
_AccTp s = 0;
int i = 0;
for (; i <= n - 4; i += 4) {
s += (_AccTp)cv_abs(a[i]) + (_AccTp)cv_abs(a[i + 1]) +
(_AccTp)cv_abs(a[i + 2]) + (_AccTp)cv_abs(a[i + 3]);
}
for (; i < n; i++)
s += cv_abs(a[i]);
return s;
}
template<typename _Tp, typename _AccTp> static inline
_AccTp normInf(const _Tp* a, int n)
{
_AccTp s = 0;
for (int i = 0; i < n; i++)
s = std::max(s, (_AccTp)cv_abs(a[i]));
return s;
}
template<typename _Tp, typename _AccTp> static inline
_AccTp normL2Sqr(const _Tp* a, const _Tp* b, int n)
{
_AccTp s = 0;
int i = 0;
for (; i <= n - 4; i += 4) {
_AccTp v0 = _AccTp(a[i] - b[i]), v1 = _AccTp(a[i + 1] - b[i + 1]), v2 = _AccTp(a[i + 2] - b[i + 2]), v3 = _AccTp(a[i + 3] - b[i + 3]);
s += v0*v0 + v1*v1 + v2*v2 + v3*v3;
}
for (; i < n; i++) {
_AccTp v = _AccTp(a[i] - b[i]);
s += v*v;
}
return s;
}
static inline float normL2Sqr(const float* a, const float* b, int n)
{
float s = 0.f;
for (int i = 0; i < n; i++) {
float v = a[i] - b[i];
s += v*v;
}
return s;
}
template<typename _Tp, typename _AccTp> static inline
_AccTp normL1(const _Tp* a, const _Tp* b, int n)
{
_AccTp s = 0;
int i = 0;
for (; i <= n - 4; i += 4) {
_AccTp v0 = _AccTp(a[i] - b[i]), v1 = _AccTp(a[i + 1] - b[i + 1]), v2 = _AccTp(a[i + 2] - b[i + 2]), v3 = _AccTp(a[i + 3] - b[i + 3]);
s += std::abs(v0) + std::abs(v1) + std::abs(v2) + std::abs(v3);
}
for (; i < n; i++) {
_AccTp v = _AccTp(a[i] - b[i]);
s += std::abs(v);
}
return s;
}
inline float normL1(const float* a, const float* b, int n)
{
float s = 0.f;
for (int i = 0; i < n; i++) {
s += std::abs(a[i] - b[i]);
}
return s;
}
inline int normL1(const uchar* a, const uchar* b, int n)
{
int s = 0;
for (int i = 0; i < n; i++) {
s += std::abs(a[i] - b[i]);
}
return s;
}
template<typename _Tp, typename _AccTp> static inline
_AccTp normInf(const _Tp* a, const _Tp* b, int n)
{
_AccTp s = 0;
for (int i = 0; i < n; i++) {
_AccTp v0 = a[i] - b[i];
s = std::max(s, std::abs(v0));
}
return s;
}
//! comparison types
enum CmpTypes {
CMP_EQ = 0, //!< src1 is equal to src2.
CMP_GT = 1, //!< src1 is greater than src2.
CMP_GE = 2, //!< src1 is greater than or equal to src2.
CMP_LT = 3, //!< src1 is less than src2.
CMP_LE = 4, //!< src1 is less than or equal to src2.
CMP_NE = 5 //!< src1 is unequal to src2.
};
//! matrix decomposition types
enum DecompTypes {
/** Gaussian elimination with the optimal pivot element chosen. */
DECOMP_LU = 0,
/** singular value decomposition (SVD) method; the system can be over-defined and/or the matrix
src1 can be singular */
DECOMP_SVD = 1,
/** eigenvalue decomposition; the matrix src1 must be symmetrical */
DECOMP_EIG = 2,
/** Cholesky \f$LL^T\f$ factorization; the matrix src1 must be symmetrical and positively
defined */
DECOMP_CHOLESKY = 3,
/** QR factorization; the system can be over-defined and/or the matrix src1 can be singular */
DECOMP_QR = 4,
/** while all the previous flags are mutually exclusive, this flag can be used together with
any of the previous; it means that the normal equations
\f$\texttt{src1}^T\cdot\texttt{src1}\cdot\texttt{dst}=\texttt{src1}^T\texttt{src2}\f$ are
solved instead of the original system
\f$\texttt{src1}\cdot\texttt{dst}=\texttt{src2}\f$ */
DECOMP_NORMAL = 16
};
/** norm types
- For one array:
\f[norm = \forkthree{\|\texttt{src1}\|_{L_{\infty}} = \max _I | \texttt{src1} (I)|}{if \(\texttt{normType} = \texttt{NORM_INF}\) }
{ \| \texttt{src1} \| _{L_1} = \sum _I | \texttt{src1} (I)|}{if \(\texttt{normType} = \texttt{NORM_L1}\) }
{ \| \texttt{src1} \| _{L_2} = \sqrt{\sum_I \texttt{src1}(I)^2} }{if \(\texttt{normType} = \texttt{NORM_L2}\) }\f]
- Absolute norm for two arrays
\f[norm = \forkthree{\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} = \max _I | \texttt{src1} (I) - \texttt{src2} (I)|}{if \(\texttt{normType} = \texttt{NORM_INF}\) }
{ \| \texttt{src1} - \texttt{src2} \| _{L_1} = \sum _I | \texttt{src1} (I) - \texttt{src2} (I)|}{if \(\texttt{normType} = \texttt{NORM_L1}\) }
{ \| \texttt{src1} - \texttt{src2} \| _{L_2} = \sqrt{\sum_I (\texttt{src1}(I) - \texttt{src2}(I))^2} }{if \(\texttt{normType} = \texttt{NORM_L2}\) }\f]
- Relative norm for two arrays
\f[norm = \forkthree{\frac{\|\texttt{src1}-\texttt{src2}\|_{L_{\infty}} }{\|\texttt{src2}\|_{L_{\infty}} }}{if \(\texttt{normType} = \texttt{NORM_RELATIVE_INF}\) }
{ \frac{\|\texttt{src1}-\texttt{src2}\|_{L_1} }{\|\texttt{src2}\|_{L_1}} }{if \(\texttt{normType} = \texttt{NORM_RELATIVE_L1}\) }
{ \frac{\|\texttt{src1}-\texttt{src2}\|_{L_2} }{\|\texttt{src2}\|_{L_2}} }{if \(\texttt{normType} = \texttt{NORM_RELATIVE_L2}\) }\f]
As example for one array consider the function \f$r(x)= \begin{pmatrix} x \\ 1-x \end{pmatrix}, x \in [-1;1]\f$.
The \f$ L_{1}, L_{2} \f$ and \f$ L_{\infty} \f$ norm for the sample value \f$r(-1) = \begin{pmatrix} -1 \\ 2 \end{pmatrix}\f$
is calculated as follows
\f{align*}
\| r(-1) \|_{L_1} &= |-1| + |2| = 3 \\
\| r(-1) \|_{L_2} &= \sqrt{(-1)^{2} + (2)^{2}} = \sqrt{5} \\
\| r(-1) \|_{L_\infty} &= \max(|-1|,|2|) = 2
\f}
and for \f$r(0.5) = \begin{pmatrix} 0.5 \\ 0.5 \end{pmatrix}\f$ the calculation is
\f{align*}
\| r(0.5) \|_{L_1} &= |0.5| + |0.5| = 1 \\
\| r(0.5) \|_{L_2} &= \sqrt{(0.5)^{2} + (0.5)^{2}} = \sqrt{0.5} \\
\| r(0.5) \|_{L_\infty} &= \max(|0.5|,|0.5|) = 0.5.
\f}
The following graphic shows all values for the three norm functions \f$\| r(x) \|_{L_1}, \| r(x) \|_{L_2}\f$ and \f$\| r(x) \|_{L_\infty}\f$.
It is notable that the \f$ L_{1} \f$ norm forms the upper and the \f$ L_{\infty} \f$ norm forms the lower border for the example function \f$ r(x) \f$.
![Graphs for the different norm functions from the above example](pics/NormTypes_OneArray_1-2-INF.png)
*/
enum NormTypes {
NORM_INF = 1,
NORM_L1 = 2,
NORM_L2 = 4,
NORM_L2SQR = 5,
NORM_HAMMING = 6,
NORM_HAMMING2 = 7,
NORM_TYPE_MASK = 7,
NORM_RELATIVE = 8, // flag
NORM_MINMAX = 32 // flag
};
//! Various border types, image boundaries are denoted with `|`
enum BorderTypes {
BORDER_CONSTANT = 0, //!< `iiiiii|abcdefgh|iiiiiii` with some specified `i`
BORDER_REPLICATE = 1, //!< `aaaaaa|abcdefgh|hhhhhhh`
BORDER_REFLECT = 2, //!< `fedcba|abcdefgh|hgfedcb`
BORDER_WRAP = 3, //!< `cdefgh|abcdefgh|abcdefg`
BORDER_REFLECT_101 = 4, //!< `gfedcb|abcdefgh|gfedcba`
BORDER_TRANSPARENT = 5, //!< `uvwxyz|absdefgh|ijklmno`
BORDER_REFLECT101 = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101
BORDER_DEFAULT = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101
BORDER_ISOLATED = 16 //!< do not look outside of ROI
};
enum DftFlags {
/** performs an inverse 1D or 2D transform instead of the default forward transform. */
DFT_INVERSE = 1,
/** scales the result: divide it by the number of array elements. Normally, it is
combined with DFT_INVERSE. */
DFT_SCALE = 2,
/** performs a forward or inverse transform of every individual row of the input
matrix; this flag enables you to transform multiple vectors simultaneously and can be used to
decrease the overhead (which is sometimes several times larger than the processing itself) to
perform 3D and higher-dimensional transformations and so forth.*/
DFT_ROWS = 4,
/** performs a forward transformation of 1D or 2D real array; the result,
though being a complex array, has complex-conjugate symmetry (*CCS*, see the function
description below for details), and such an array can be packed into a real array of the same
size as input, which is the fastest option and which is what the function does by default;
however, you may wish to get a full complex array (for simpler spectrum analysis, and so on) -
pass the flag to enable the function to produce a full-size complex output array. */
DFT_COMPLEX_OUTPUT = 16,
/** performs an inverse transformation of a 1D or 2D complex array; the
result is normally a complex array of the same size, however, if the input array has
conjugate-complex symmetry (for example, it is a result of forward transformation with
DFT_COMPLEX_OUTPUT flag), the output is a real array; while the function itself does not
check whether the input is symmetrical or not, you can pass the flag and then the function
will assume the symmetry and produce the real output array (note that when the input is packed
into a real array and inverse transformation is executed, the function treats the input as a
packed complex-conjugate symmetrical array, and the output will also be a real array). */
DFT_REAL_OUTPUT = 32,
/** performs an inverse 1D or 2D transform instead of the default forward transform. */
DCT_INVERSE = DFT_INVERSE,
/** performs a forward or inverse transform of every individual row of the input
matrix. This flag enables you to transform multiple vectors simultaneously and can be used to
decrease the overhead (which is sometimes several times larger than the processing itself) to
perform 3D and higher-dimensional transforms and so forth.*/
DCT_ROWS = DFT_ROWS
};
} //yt_tinycv
#endif //FBC_CV_CORE_BASE_HPP_

View File

@@ -0,0 +1,313 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_CORE_HPP_
#define FBC_CV_CORE_CORE_HPP_
/* reference: include/opencv2/core/core_c.h
include/opencv2/core.hpp
modules/core/src/stat.cpp
modules/core/include/opencv2/core/private.hpp
modules/core/src/matrix.cpp
modules/core/src/arithm.cpp
*/
#ifndef __cplusplus
#error core.hpp header must be compiled as C++
#endif
#include <exception>
#include <string>
#include "fbcdef.hpp"
#include "mat.hpp"
namespace yt_tinycv {
// NormFlags
#define FBC_C 1
#define FBC_L1 2
#define FBC_L2 4
#define FBC_NORM_MASK 7
#define FBC_RELATIVE 8
#define FBC_DIFF 16
#define FBC_MINMAX 32
#define FBC_DIFF_C (FBC_DIFF | FBC_C)
#define FBC_DIFF_L1 (FBC_DIFF | FBC_L1)
#define FBC_DIFF_L2 (FBC_DIFF | FBC_L2)
#define FBC_RELATIVE_C (FBC_RELATIVE | FBC_C)
#define FBC_RELATIVE_L1 (FBC_RELATIVE | FBC_L1)
#define FBC_RELATIVE_L2 (FBC_RELATIVE | FBC_L2)
// Discrete Linear Transforms and Related Functions
#define FBC_DXT_SCALE 2 // divide result by size of array
// Fast cubic root calculation
FBC_EXPORTS float fbcCbrt(float value);
template<typename dump>
static inline void* fbcAlignPtr(const void* ptr, int align = 32)
{
FBC_Assert((align & (align - 1)) == 0);
return (void*)(((size_t)ptr + align - 1) & ~(size_t)(align - 1));
}
template<typename dump>
static inline int fbcAlign(int size, int align)
{
FBC_Assert((align & (align - 1)) == 0 && size < INT_MAX);
return (size + align - 1) & -align;
}
// Computes the source location of an extrapolated pixel
/* Various border types, image boundaries are denoted with '|'
* BORDER_REPLICATE: aaaaaa|abcdefgh|hhhhhhh
* BORDER_REFLECT: fedcba|abcdefgh|hgfedcb
* BORDER_REFLECT_101: gfedcb|abcdefgh|gfedcba
* BORDER_WRAP: cdefgh|abcdefgh|abcdefg
* BORDER_CONSTANT: iiiiii|abcdefgh|iiiiiii with some specified 'i'
*/
template<typename _Tp>
int borderInterpolate(int p, int len, int borderType)
{
if ((unsigned)p < (unsigned)len) {
;
} else if (borderType == BORDER_REPLICATE) {
p = p < 0 ? 0 : len - 1;
} else if (borderType == BORDER_REFLECT || borderType == BORDER_REFLECT_101) {
int delta = borderType == BORDER_REFLECT_101;
if (len == 1)
return 0;
do {
if (p < 0)
p = -p - 1 + delta;
else
p = len - 1 - (p - len) - delta;
} while ((unsigned)p >= (unsigned)len);
} else if (borderType == BORDER_WRAP) {
FBC_Assert(len > 0);
if (p < 0)
p -= ((p - len + 1) / len)*len;
if (p >= len)
p %= len;
} else if (borderType == BORDER_CONSTANT) {
p = -1;
} else {
FBC_Error("Unknown/unsupported border type");
}
return p;
}
// Transposes a matrix
// \f[\texttt{dst} (i,j) = \texttt{src} (j,i)\f]
template<typename _Tp, int chs>
int transpose(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst)
{
if (src.empty()) {
dst.release();
return -1;
}
// handle the case of single-column/single-row matrices, stored in STL vectors
if (src.rows != dst.cols || src.cols != dst.rows) {
FBC_Assert(src.size() == dst.size() && (src.cols == 1 || src.rows == 1));
src.copyTo(dst);
return 0;
}
if (dst.data == src.data) {
FBC_Assert(0); // TODO
} else {
Size sz = src.size();
int i = 0, j, m = sz.width, n = sz.height;
int sstep = src.step;
int dstep = dst.step;
for (; i <= m - 4; i += 4) {
_Tp* d0 = (_Tp*)(dst.data + dstep*i);
_Tp* d1 = (_Tp*)(dst.data + dstep*(i + 1));
_Tp* d2 = (_Tp*)(dst.data + dstep*(i + 2));
_Tp* d3 = (_Tp*)(dst.data + dstep*(i + 3));
for (j = 0; j <= n - 4; j += 4) {
const _Tp* s0 = (const _Tp*)(src.data + i*sizeof(_Tp) + sstep*j);
const _Tp* s1 = (const _Tp*)(src.data + i*sizeof(_Tp) + sstep*(j + 1));
const _Tp* s2 = (const _Tp*)(src.data + i*sizeof(_Tp) + sstep*(j + 2));
const _Tp* s3 = (const _Tp*)(src.data + i*sizeof(_Tp) + sstep*(j + 3));
d0[j] = s0[0]; d0[j + 1] = s1[0]; d0[j + 2] = s2[0]; d0[j + 3] = s3[0];
d1[j] = s0[1]; d1[j + 1] = s1[1]; d1[j + 2] = s2[1]; d1[j + 3] = s3[1];
d2[j] = s0[2]; d2[j + 1] = s1[2]; d2[j + 2] = s2[2]; d2[j + 3] = s3[2];
d3[j] = s0[3]; d3[j + 1] = s1[3]; d3[j + 2] = s2[3]; d3[j + 3] = s3[3];
}
for (; j < n; j++) {
const _Tp* s0 = (const _Tp*)(src.data + i*sizeof(_Tp) + j*sstep);
d0[j] = s0[0]; d1[j] = s0[1]; d2[j] = s0[2]; d3[j] = s0[3];
}
}
for (; i < m; i++) {
_Tp* d0 = (_Tp*)(dst.data + dstep*i);
j = 0;
for (; j <= n - 4; j += 4) {
const _Tp* s0 = (const _Tp*)(src.data + i*sizeof(_Tp) + sstep*j);
const _Tp* s1 = (const _Tp*)(src.data + i*sizeof(_Tp) + sstep*(j + 1));
const _Tp* s2 = (const _Tp*)(src.data + i*sizeof(_Tp) + sstep*(j + 2));
const _Tp* s3 = (const _Tp*)(src.data + i*sizeof(_Tp) + sstep*(j + 3));
d0[j] = s0[0]; d0[j + 1] = s1[0]; d0[j + 2] = s2[0]; d0[j + 3] = s3[0];
}
for (; j < n; j++) {
const _Tp* s0 = (const _Tp*)(src.data + i*sizeof(_Tp) + j*sstep);
d0[j] = s0[0];
}
}
}
return 0;
}
// Counts non-zero array elements
// \f[\sum _{ I: \; \texttt{ src } (I) \ne0 } 1\f]
template<typename _Tp, int chs>
int countNonZero(const Mat_<_Tp, chs>& src)
{
FBC_Assert(chs == 1);
int len = src.rows * src.cols;
const _Tp* p = (_Tp*)src.data;
int nz = 0;
for (int i = 0; i < len; i++) {
nz += (p[i] != 0);
}
return nz;
}
template<typename _Tp, int chs>
void scalarToRawData(const yt_tinycv::Scalar& s, void* _buf, int unroll_to = 0)
{
FBC_Assert(typeid(uchar).name() == typeid(_Tp).name() || typeid(float).name() == typeid(_Tp).name()); // uchar || float
int i, cn = chs;
FBC_Assert(chs <= 4);
int depth = sizeof(_Tp);
switch (depth) {
case 1: {
uchar* buf = (uchar*)_buf;
for (i = 0; i < cn; i++)
buf[i] = saturate_cast<uchar>(s.val[i]);
for (; i < unroll_to; i++)
buf[i] = buf[i - cn];
}
break;
case 4: {
float* buf = (float*)_buf;
for (i = 0; i < cn; i++)
buf[i] = saturate_cast<float>(s.val[i]);
for (; i < unroll_to; i++)
buf[i] = buf[i - cn];
}
break;
default:
FBC_Error("UnsupportedFormat");
}
}
// calculates the per - element bit - wise logical conjunction
// \f[\texttt{dst} (I) = \texttt{src1} (I) \wedge \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0\f]
// mask optional operation mask, 8-bit single channel array, that specifies elements of the output array to be changed
template<typename _Tp, int chs>
int bitwise_and(const Mat_<_Tp, chs>& src1, const Mat_<_Tp, chs>& src2, Mat_<_Tp, chs>& dst, const Mat_<uchar, 1>& mask = Mat_<uchar, 1>())
{
FBC_Assert(src1.rows == src2.rows && src1.cols == src2.cols);
if (dst.empty()) {
dst = Mat_<_Tp, chs>(src1.rows, src1.cols);
} else {
FBC_Assert(src1.rows == dst.rows && src1.cols == dst.cols);
}
if (!mask.empty()) {
FBC_Assert(src1.rows == mask.rows && src1.cols == mask.cols);
}
int bytePerRow = src1.cols * chs * sizeof(_Tp);
int bypePerPixel = chs * sizeof(_Tp);
for (int y = 0; y < src1.rows; y++) {
const uchar* pSrc1 = src1.ptr(y);
const uchar* pSrc2 = src2.ptr(y);
uchar* pDst = dst.ptr(y);
const uchar* pMask = NULL;
if (!mask.empty()) {
pMask = mask.ptr(y);
for (int x = 0; x < src1.cols; x++) {
if (pMask[x] == 1) {
int addr = x * bypePerPixel;
for (int t = 0; t < bypePerPixel; t++) {
pDst[addr + t] = pSrc1[addr + t] & pSrc2[addr + t];
}
}
}
} else {
for (int x = 0; x < bytePerRow; x++) {
pDst[x] = pSrc1[x] & pSrc2[x];
}
}
}
return 0;
}
// Inverts every bit of an array
// \f[\texttt{dst} (I) = \neg \texttt{src} (I)\f]
// mask optional operation mask, 8-bit single channel array, that specifies elements of the output array to be changed
template<typename _Tp, int chs>
int bitwise_not(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst, const Mat_<uchar, 1>& mask = Mat_<uchar, 1>())
{
if (dst.empty()) {
dst = Mat_<_Tp, chs>(src.rows, src.cols);
} else {
FBC_Assert(src.rows == dst.rows && src.cols == dst.cols);
}
if (!mask.empty()) {
FBC_Assert(src.rows == mask.rows && src.cols == mask.cols);
}
int bytePerRow = src.cols * chs * sizeof(_Tp);
int bypePerPixel = chs * sizeof(_Tp);
for (int y = 0; y < src.rows; y++) {
const uchar* pSrc = src.ptr(y);
uchar* pDst = dst.ptr(y);
const uchar* pMask = NULL;
if (!mask.empty()) {
pMask = mask.ptr(y);
for (int x = 0; x < src.cols; x++) {
if (pMask[x] == 1) {
int addr = x * bypePerPixel;
for (int t = 0; t < bypePerPixel; t++) {
pDst[addr + t] = ~pSrc[addr + t];
}
}
}
} else {
for (int x = 0; x < bytePerRow; x++) {
pDst[x] = ~pSrc[x];
}
}
}
return 0;
}
} // namespace yt_tinycv
#endif // FBC_CV_CORE_CORE_HPP_

View File

@@ -0,0 +1,543 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
// from: https://github.com/fengbingchun/OpenCV_Test/blob/master/src/fbc_cv/include/cvtColor.hpp
// commitID: 7c0eccf85e31c456256cc4c87d4ba752a56a18dc
#ifndef FBC_CV_CVTCOLOR_HPP_
#define FBC_CV_CVTCOLOR_HPP_
/* reference: include/opencv2/imgproc.hpp
imgproc/src/color.cpp
*/
#include <typeinfo>
#include "mat.hpp"
#include "saturate.hpp"
#include "imgproc.hpp"
#include "core.hpp"
#ifdef __ARM_NEON__
#include "arm_neon.h"
#include <sys/time.h>
#endif
namespace yt_tinycv {
#define FBC_DESCALE(x,n) (((x) + (1 << ((n)-1))) >> (n))
#ifdef __ARM_NEON__
// neon intrinsic
static void NeonCvtColorRGBA2BGR(unsigned char *rgba, unsigned char *bgr, int rows, int cols) {
int len_color = rows * cols;
int num8x16 = len_color / 16;
int num8len = num8x16 * 16;
uint8x16x4_t intlv_rgba;
uint8x16x3_t intlv_bgr;
for (int i=0; i < num8x16; i++) {
intlv_rgba = vld4q_u8(rgba);
intlv_bgr.val[0] = intlv_rgba.val[2];
intlv_bgr.val[1] = intlv_rgba.val[1];
intlv_bgr.val[2] = intlv_rgba.val[0];
vst3q_u8(bgr, intlv_bgr);
rgba += 64;
bgr += 48;
}
for (; num8len < len_color; num8len++) {
bgr[0] = rgba[2];
bgr[1] = rgba[1];
bgr[2] = rgba[0];
rgba += 4;
bgr += 3;
}
}
static void NeonCvtColorRGBA2RGB(unsigned char *rgba, unsigned char *bgr, int rows, int cols) {
int len_color = rows * cols;
int num8x16 = len_color / 16;
int num8len = num8x16 * 16;
uint8x16x4_t intlv_rgba;
uint8x16x3_t intlv_bgr;
for (int i=0; i < num8x16; i++) {
intlv_rgba = vld4q_u8(rgba);
intlv_bgr.val[0] = intlv_rgba.val[0];
intlv_bgr.val[1] = intlv_rgba.val[1];
intlv_bgr.val[2] = intlv_rgba.val[2];
vst3q_u8(bgr, intlv_bgr);
rgba += 64;
bgr += 48;
}
for (; num8len < len_color; num8len++) {
bgr[0] = rgba[0];
bgr[1] = rgba[1];
bgr[2] = rgba[2];
rgba += 4;
bgr += 3;
}
}
static void NeonCvtColorRGB2BGR(unsigned char *rgb, unsigned char *bgr, int rows, int cols) {
int len_color = rows * cols;
int num8x16 = len_color / 16;
int num8len = num8x16 * 16;
uint8x16x3_t intlv_rgb;
uint8x16x3_t intlv_bgr;
for (int i=0; i < num8x16; i++) {
intlv_rgb = vld3q_u8(rgb);
intlv_bgr.val[0] = intlv_rgb.val[2];
intlv_bgr.val[1] = intlv_rgb.val[1];
intlv_bgr.val[2] = intlv_rgb.val[0];
vst3q_u8(bgr, intlv_bgr);
rgb += 48;
bgr += 48;
}
for (; num8len < len_color; num8len++) {
bgr[0] = rgb[2];
bgr[1] = rgb[1];
bgr[2] = rgb[0];
rgb += 3;
bgr += 3;
}
}
#endif
template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_RGB2RGB(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst, int bidx);
template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_RGB2Gray(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst, int bidx);
template<typename _Tp, int chs1, int chs2> static int CvtColorLoop_RGB2YCrCb(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst, int bidx, const float* coeffs_f, const int* coeffs_i);
template<typename _Tp, int chs1, int chs2, int bIdx, int uIdx> static void cvtRGBtoYUV420p(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst);
#undef R2Y
#undef G2Y
#undef B2Y
enum {
yuv_shift = 14,
xyz_shift = 12,
R2Y = 4899,
G2Y = 9617,
B2Y = 1868,
BLOCK_SIZE = 256
};
// Converts an image from one color space to another
// support type: uchar/ushort/float
template<typename _Tp, int chs1, int chs2>
int cvtColor(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst, int code)
{
FBC_Assert(src.cols > 0 && src.rows > 0 && dst.cols > 0 && dst.rows > 0);
FBC_Assert(src.cols == dst.cols);
FBC_Assert(src.data != NULL && dst.data != NULL);
FBC_Assert(typeid(uchar).name() == typeid(_Tp).name() ||
typeid(ushort).name() == typeid(_Tp).name() ||
typeid(float).name() == typeid(_Tp).name());
FBC_Assert((sizeof(_Tp) == 1) || sizeof(_Tp) == 2 || sizeof(_Tp) == 4); // uchar || ushort || float
int scn = src.channels;
int dcn = dst.channels; // number of channels in the destination image
Size sz = src.size();
Size dz = dst.size();
int bidx;
#ifdef __ARM_NEON__
if (CV_RGBA2BGR == code || CV_BGRA2RGB == code) {
// timeval tv_begin, tv_end;
// gettimeofday(&tv_begin, NULL);
NeonCvtColorRGBA2BGR(src.data, dst.data, dst.rows, dst.cols);
// gettimeofday(&tv_end, NULL);
// float elapsed = ((tv_end.tv_sec - tv_begin.tv_sec) * 1000000.0f + tv_end.tv_usec - tv_begin.tv_usec) / 1000.0f;
// printf("lgy neon NeonCvtColorRGBA2BGR code : %d, %f ms\n", code, elapsed);
return 0;
}
if (CV_RGBA2RGB == code || CV_BGRA2BGR == code) {
NeonCvtColorRGBA2RGB(src.data, dst.data, dst.rows, dst.cols);
return 0;
}
if (CV_BGR2RGB == code || CV_RGB2BGR == code) {
NeonCvtColorRGB2BGR(src.data, dst.data, dst.rows, dst.cols);
return 0;
}
#endif
switch (code) {
case CV_BGR2BGRA: case CV_RGB2BGRA: case CV_BGRA2BGR:
case CV_RGBA2BGR: case CV_RGB2BGR: case CV_BGRA2RGBA: {
FBC_Assert(scn == 3 || scn == 4);
dcn = code == CV_BGR2BGRA || code == CV_RGB2BGRA || code == CV_BGRA2RGBA ? 4 : 3;
FBC_Assert(dst.channels == dcn);
bidx = code == CV_BGR2BGRA || code == CV_BGRA2BGR ? 0 : 2;
CvtColorLoop_RGB2RGB(src, dst, bidx); // uchar/ushort/float
break;
}
case CV_BGR2GRAY: case CV_BGRA2GRAY: case CV_RGB2GRAY: case CV_RGBA2GRAY: {
FBC_Assert(scn == 3 || scn == 4);
FBC_Assert(dst.channels == 1);
bidx = code == CV_BGR2GRAY || code == CV_BGRA2GRAY ? 0 : 2;
CvtColorLoop_RGB2Gray(src, dst, bidx);
break;
}
case CV_BGR2YUV: case CV_RGB2YUV:{
FBC_Assert(scn == 3 || scn == 4);
bidx = code == CV_BGR2YUV ? 0 : 2;
static const float yuv_f[] = { 0.114f, 0.587f, 0.299f, 0.492f, 0.877f };
static const int yuv_i[] = { B2Y, G2Y, R2Y, 8061, 14369 };
CvtColorLoop_RGB2YCrCb(src, dst, bidx, yuv_f, yuv_i);
break;
}
case CV_RGB2YUV_YV12: case CV_BGR2YUV_YV12: case CV_RGBA2YUV_YV12: case CV_BGRA2YUV_YV12:
case CV_RGB2YUV_IYUV: case CV_BGR2YUV_IYUV: case CV_RGBA2YUV_IYUV: case CV_BGRA2YUV_IYUV: {
const int bIdx = (code == CV_BGR2YUV_IYUV || code == CV_BGRA2YUV_IYUV || code == CV_BGR2YUV_YV12 || code == CV_BGRA2YUV_YV12) ? 0 : 2;
const int uIdx = (code == CV_BGR2YUV_IYUV || code == CV_BGRA2YUV_IYUV || code == CV_RGB2YUV_IYUV || code == CV_RGBA2YUV_IYUV) ? 1 : 2;
FBC_Assert(scn == 3 || scn == 4);
FBC_Assert(sizeof(_Tp) == 1);
FBC_Assert(dcn == 1);
FBC_Assert(sz.width % 2 == 0 && sz.height % 2 == 0);
//Size dstSz(sz.width, sz.height / 2 * 3);
FBC_Assert((dz.width == sz.width) && (sz.height / 2 * 3 == dz.height));
switch (bIdx + uIdx * 10) {
case 10: cvtRGBtoYUV420p<_Tp, chs1, chs2, 0, 1>(src, dst); break;
case 12: cvtRGBtoYUV420p<_Tp, chs1, chs2, 2, 1>(src, dst); break;
case 20: cvtRGBtoYUV420p<_Tp, chs1, chs2, 0, 2>(src, dst); break;
case 22: cvtRGBtoYUV420p<_Tp, chs1, chs2, 2, 2>(src, dst); break;
default: FBC_Error("Unknown/unsupported color conversion code"); break;
};
break;
}
default:
FBC_Error("Unknown/unsupported color conversion code");
}
return 0;
}
// computes cubic spline coefficients for a function: (xi=i, yi=f[i]), i=0..n
template<typename _Tp> static void splineBuild(const _Tp* f, int n, _Tp* tab)
{
_Tp cn = 0;
int i;
tab[0] = tab[1] = (_Tp)0;
for (i = 1; i < n - 1; i++) {
_Tp t = 3 * (f[i + 1] - 2 * f[i] + f[i - 1]);
_Tp l = 1 / (4 - tab[(i - 1) * 4]);
tab[i * 4] = l; tab[i * 4 + 1] = (t - tab[(i - 1) * 4 + 1])*l;
}
for (i = n - 1; i >= 0; i--) {
_Tp c = tab[i * 4 + 1] - tab[i * 4] * cn;
_Tp b = f[i + 1] - f[i] - (cn + c * 2)*(_Tp)0.3333333333333333;
_Tp d = (cn - c)*(_Tp)0.3333333333333333;
tab[i * 4] = f[i]; tab[i * 4 + 1] = b;
tab[i * 4 + 2] = c; tab[i * 4 + 3] = d;
cn = c;
}
}
// interpolates value of a function at x, 0 <= x <= n using a cubic spline.
template<typename _Tp> static inline _Tp splineInterpolate(_Tp x, const _Tp* tab, int n)
{
// don't touch this function without urgent need - some versions of gcc fail to inline it correctly
int ix = std::min(std::max(int(x), 0), n - 1);
x -= ix;
tab += ix * 4;
return ((tab[3] * x + tab[2])*x + tab[1])*x + tab[0];
}
template<typename _Tp> struct ColorChannel
{
typedef float worktype_f;
static _Tp max() { return std::numeric_limits<_Tp>::max(); }
static _Tp half() { return (_Tp)(max() / 2 + 1); }
};
template<> struct ColorChannel<float>
{
typedef float worktype_f;
static float max() { return 1.f; }
static float half() { return 0.5f; }
};
template<typename _Tp> struct RGB2Gray
{
typedef _Tp channel_type;
RGB2Gray(int _srccn, int blueIdx, const float* _coeffs) : srccn(_srccn)
{
static const float coeffs0[] = { 0.299f, 0.587f, 0.114f };
memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 3 * sizeof(coeffs[0]));
if (blueIdx == 0)
std::swap(coeffs[0], coeffs[2]);
}
void operator()(const _Tp* src, _Tp* dst, int n) const
{
int scn = srccn;
float cb = coeffs[0], cg = coeffs[1], cr = coeffs[2];
for (int i = 0; i < n; i++, src += scn)
dst[i] = saturate_cast<_Tp>(src[0] * cb + src[1] * cg + src[2] * cr);
}
int srccn;
float coeffs[3];
};
template<> struct RGB2Gray<uchar>
{
typedef uchar channel_type;
RGB2Gray(int _srccn, int blueIdx, const int* coeffs) : srccn(_srccn)
{
const int coeffs0[] = { R2Y, G2Y, B2Y };
if (!coeffs) coeffs = coeffs0;
int b = 0, g = 0, r = (1 << (yuv_shift - 1));
int db = coeffs[blueIdx ^ 2], dg = coeffs[1], dr = coeffs[blueIdx];
for (int i = 0; i < 256; i++, b += db, g += dg, r += dr) {
tab[i] = b;
tab[i + 256] = g;
tab[i + 512] = r;
}
}
void operator()(const uchar* src, uchar* dst, int n) const
{
int scn = srccn;
const int* _tab = tab;
for (int i = 0; i < n; i++, src += scn)
dst[i] = (uchar)((_tab[src[0]] + _tab[src[1] + 256] + _tab[src[2] + 512]) >> yuv_shift);
}
int srccn;
int tab[256 * 3];
};
template<> struct RGB2Gray<ushort>
{
typedef ushort channel_type;
RGB2Gray(int _srccn, int blueIdx, const int* _coeffs) : srccn(_srccn)
{
static const int coeffs0[] = { R2Y, G2Y, B2Y };
memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 3 * sizeof(coeffs[0]));
if (blueIdx == 0)
std::swap(coeffs[0], coeffs[2]);
}
void operator()(const ushort* src, ushort* dst, int n) const
{
int scn = srccn, cb = coeffs[0], cg = coeffs[1], cr = coeffs[2];
for (int i = 0; i < n; i++, src += scn)
dst[i] = (ushort)FBC_DESCALE((unsigned)(src[0] * cb + src[1] * cg + src[2] * cr), yuv_shift);
}
int srccn;
int coeffs[3];
};
template<typename _Tp> struct RGB2YCrCb_f{
typedef _Tp channel_type;
RGB2YCrCb_f(int _srccn, int _blueIdx, const float* _coeffs) : srccn(_srccn), blueIdx(_blueIdx)
{
static const float coeffs0[] = { 0.299f, 0.587f, 0.114f, 0.713f, 0.564f };
memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5 * sizeof(coeffs[0]));
if (blueIdx == 0) std::swap(coeffs[0], coeffs[2]);
}
void operator()(const _Tp* src, _Tp* dst, int n) const
{
int scn = srccn, bidx = blueIdx;
const _Tp delta = ColorChannel<_Tp>::half();
float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
n *= 3;
for (int i = 0; i < n; i += 3, src += scn) {
_Tp Y = saturate_cast<_Tp>(src[0] * C0 + src[1] * C1 + src[2] * C2);
_Tp Cr = saturate_cast<_Tp>((src[bidx ^ 2] - Y)*C3 + delta);
_Tp Cb = saturate_cast<_Tp>((src[bidx] - Y)*C4 + delta);
dst[i] = Y; dst[i + 1] = Cr; dst[i + 2] = Cb;
}
}
int srccn, blueIdx;
float coeffs[5];
};
template<typename _Tp> struct RGB2YCrCb_i{
typedef _Tp channel_type;
RGB2YCrCb_i(int _srccn, int _blueIdx, const int* _coeffs) : srccn(_srccn), blueIdx(_blueIdx)
{
static const int coeffs0[] = { R2Y, G2Y, B2Y, 11682, 9241 };
memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5 * sizeof(coeffs[0]));
if (blueIdx == 0) std::swap(coeffs[0], coeffs[2]);
}
void operator()(const _Tp* src, _Tp* dst, int n) const
{
int scn = srccn, bidx = blueIdx;
int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
int delta = ColorChannel<_Tp>::half()*(1 << yuv_shift);
n *= 3;
for (int i = 0; i < n; i += 3, src += scn) {
int Y = FBC_DESCALE(src[0] * C0 + src[1] * C1 + src[2] * C2, yuv_shift);
int Cr = FBC_DESCALE((src[bidx ^ 2] - Y)*C3 + delta, yuv_shift);
int Cb = FBC_DESCALE((src[bidx] - Y)*C4 + delta, yuv_shift);
dst[i] = saturate_cast<_Tp>(Y);
dst[i + 1] = saturate_cast<_Tp>(Cr);
dst[i + 2] = saturate_cast<_Tp>(Cb);
}
}
int srccn, blueIdx;
int coeffs[5];
};
const int ITUR_BT_601_CY = 1220542;
const int ITUR_BT_601_CUB = 2116026;
const int ITUR_BT_601_CUG = -409993;
const int ITUR_BT_601_CVG = -852492;
const int ITUR_BT_601_CVR = 1673527;
const int ITUR_BT_601_SHIFT = 20;
const int ITUR_BT_601_CRY = 269484;
const int ITUR_BT_601_CGY = 528482;
const int ITUR_BT_601_CBY = 102760;
const int ITUR_BT_601_CRU = -155188;
const int ITUR_BT_601_CGU = -305135;
const int ITUR_BT_601_CBU = 460324;
const int ITUR_BT_601_CGV = -385875;
const int ITUR_BT_601_CBV = -74448;
template<typename _Tp, int chs1, int chs2, int bIdx>
struct RGB888toYUV420pInvoker{
RGB888toYUV420pInvoker(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>* dst, const int uIdx)
: src_(src), dst_(dst), uIdx_(uIdx) { }
void operator()(const Range& rowRange) const
{
const int w = src_.cols;
const int h = src_.rows;
const int cn = src_.channels;
for (int i = rowRange.start; i < rowRange.end; i++) {
const uchar* row0 = src_.ptr(2 * i);
const uchar* row1 = src_.ptr(2 * i + 1);
uchar* y = (uchar*)dst_->ptr(2 * i);
uchar* u = (uchar*)dst_->ptr(h + i / 2) + (i % 2) * (w / 2);
uchar* v = (uchar*)dst_->ptr(h + (i + h / 2) / 2) + ((i + h / 2) % 2) * (w / 2);
if (uIdx_ == 2) std::swap(u, v);
for (int j = 0, k = 0; j < w * cn; j += 2 * cn, k++) {
int r00 = row0[2 - bIdx + j]; int g00 = row0[1 + j]; int b00 = row0[bIdx + j];
int r01 = row0[2 - bIdx + cn + j]; int g01 = row0[1 + cn + j]; int b01 = row0[bIdx + cn + j];
int r10 = row1[2 - bIdx + j]; int g10 = row1[1 + j]; int b10 = row1[bIdx + j];
int r11 = row1[2 - bIdx + cn + j]; int g11 = row1[1 + cn + j]; int b11 = row1[bIdx + cn + j];
const int shifted16 = (16 << ITUR_BT_601_SHIFT);
const int halfShift = (1 << (ITUR_BT_601_SHIFT - 1));
int y00 = ITUR_BT_601_CRY * r00 + ITUR_BT_601_CGY * g00 + ITUR_BT_601_CBY * b00 + halfShift + shifted16;
int y01 = ITUR_BT_601_CRY * r01 + ITUR_BT_601_CGY * g01 + ITUR_BT_601_CBY * b01 + halfShift + shifted16;
int y10 = ITUR_BT_601_CRY * r10 + ITUR_BT_601_CGY * g10 + ITUR_BT_601_CBY * b10 + halfShift + shifted16;
int y11 = ITUR_BT_601_CRY * r11 + ITUR_BT_601_CGY * g11 + ITUR_BT_601_CBY * b11 + halfShift + shifted16;
y[2 * k + 0] = saturate_cast<uchar>(y00 >> ITUR_BT_601_SHIFT);
y[2 * k + 1] = saturate_cast<uchar>(y01 >> ITUR_BT_601_SHIFT);
y[2 * k + dst_->step + 0] = saturate_cast<uchar>(y10 >> ITUR_BT_601_SHIFT);
y[2 * k + dst_->step + 1] = saturate_cast<uchar>(y11 >> ITUR_BT_601_SHIFT);
const int shifted128 = (128 << ITUR_BT_601_SHIFT);
int u00 = ITUR_BT_601_CRU * r00 + ITUR_BT_601_CGU * g00 + ITUR_BT_601_CBU * b00 + halfShift + shifted128;
int v00 = ITUR_BT_601_CBU * r00 + ITUR_BT_601_CGV * g00 + ITUR_BT_601_CBV * b00 + halfShift + shifted128;
u[k] = saturate_cast<uchar>(u00 >> ITUR_BT_601_SHIFT);
v[k] = saturate_cast<uchar>(v00 >> ITUR_BT_601_SHIFT);
}
}
}
private:
RGB888toYUV420pInvoker& operator=(const RGB888toYUV420pInvoker&);
const Mat_<_Tp, chs1>& src_;
Mat_<_Tp, chs2>* const dst_;
const int uIdx_;
};
template<typename _Tp, int chs1, int chs2>
static int CvtColorLoop_RGB2RGB(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst, int bidx)
{
Range range(0, src.rows);
const uchar* yS_ = src.ptr(range.start);
uchar* yD_ = (uchar*)dst.ptr(range.start);
int scn = src.channels, dcn = dst.channels;
for (int h = range.start; h < range.end; ++h, yS_ += src.step, yD_ += dst.step) {
int n = src.cols;
const _Tp* yS = (const _Tp*)yS_;
_Tp* yD = (_Tp*)yD_;
if (dcn == 3) {
n *= 3;
for (int i = 0; i < n; i += 3, yS += scn) {
_Tp t0 = yS[bidx], t1 = yS[1], t2 = yS[bidx ^ 2];
yD[i] = t0; yD[i + 1] = t1; yD[i + 2] = t2;
}
} else if (scn == 3) {
n *= 3;
_Tp alpha = ColorChannel<_Tp>::max(); // Note: _Tp = float: alpha = 1.0f
for (int i = 0; i < n; i += 3, yD += 4) {
_Tp t0 = yS[i], t1 = yS[i + 1], t2 = yS[i + 2];
yD[bidx] = t0; yD[1] = t1; yD[bidx ^ 2] = t2; yD[3] = alpha;
}
} else {
n *= 4;
for (int i = 0; i < n; i += 4) {
_Tp t0 = yS[i], t1 = yS[i + 1], t2 = yS[i + 2], t3 = yS[i + 3];
yD[i] = t2; yD[i + 1] = t1; yD[i + 2] = t0; yD[i + 3] = t3;
}
}
}
return 0;
}
template<typename _Tp, int chs1, int chs2>
static int CvtColorLoop_RGB2Gray(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst, int bidx)
{
Range range(0, src.rows);
const uchar* yS = src.ptr(range.start);
uchar* yD = (uchar*)dst.ptr(range.start);
int scn = src.channels, dcn = dst.channels;
RGB2Gray<_Tp> rgb2gray(scn, bidx, 0);
for (int i = range.start; i < range.end; ++i, yS += src.step, yD += dst.step) {
rgb2gray((const _Tp*)yS, (_Tp*)yD, src.cols);
}
return 0;
}
template<typename _Tp, int chs1, int chs2>
static int CvtColorLoop_RGB2YCrCb(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst, int bidx, const float* coeffs_f, const int* coeffs_i)
{
Range range(0, src.rows);
const uchar* yS = src.ptr(range.start);
uchar* yD = (uchar*)dst.ptr(range.start);
int scn = src.channels, dcn = dst.channels;
if (sizeof(_Tp) == 4) {
RGB2YCrCb_f<_Tp> rgb2ycrcb(scn, bidx, coeffs_f);
for (int i = range.start; i < range.end; ++i, yS += src.step, yD += dst.step) {
rgb2ycrcb((const _Tp*)yS, (_Tp*)yD, src.cols);
}
} else {
if (sizeof(_Tp) == 1) {
RGB2YCrCb_i<uchar> rgb2ycrcb(scn, bidx, coeffs_i);
for (int i = range.start; i < range.end; ++i, yS += src.step, yD += dst.step) {
rgb2ycrcb((const uchar*)yS, (uchar*)yD, src.cols);
}
} else {
RGB2YCrCb_i<ushort> rgb2ycrcb(scn, bidx, coeffs_i);
for (int i = range.start; i < range.end; ++i, yS += src.step, yD += dst.step) {
rgb2ycrcb((const ushort*)yS, (ushort*)yD, src.cols);
}
}
}
return 0;
}
template<typename _Tp, int chs1, int chs2, int bIdx, int uIdx>
static void cvtRGBtoYUV420p(const Mat_<_Tp, chs1>& src, Mat_<_Tp, chs2>& dst)
{
RGB888toYUV420pInvoker<_Tp, chs1, chs2, bIdx> colorConverter(src, &dst, uIdx);
colorConverter(Range(0, src.rows / 2));
}
} // namespace yt_tinycv
#endif // FBC_CV_CVTCOLOR_HPP_

View File

@@ -0,0 +1,75 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_FAST_MATH_HPP_
#define FBC_CV_CORE_FAST_MATH_HPP_
// reference: include/opencv2/core/fast_math.hpp
#include "fbcdef.hpp"
namespace yt_tinycv {
// Rounds floating-point number to the nearest integer
static inline int fbcRound(double value)
{
// it's ok if round does not comply with IEEE754 standard;
// it should allow +/-1 difference when the other functions use round
return (int)(value + (value >= 0 ? 0.5 : -0.5));
}
static inline int fbcRound(float value)
{
// it's ok if round does not comply with IEEE754 standard;
// it should allow +/-1 difference when the other functions use round
return (int)(value + (value >= 0 ? 0.5f : -0.5f));
}
static inline int fbcRound(int value)
{
return value;
}
// Rounds floating-point number to the nearest integer not larger than the original
static inline int fbcFloor(double value)
{
int i = fbcRound(value);
float diff = (float)(value - i);
return i - (diff < 0);
}
static inline int fbcFloor(float value)
{
int i = fbcRound(value);
float diff = (float)(value - i);
return i - (diff < 0);
}
static inline int fbcFloor(int value)
{
return value;
}
// Rounds floating-point number to the nearest integer not smaller than the original
static inline int fbcCeil(double value)
{
int i = fbcRound(value);
float diff = (float)(i - value);
return i + (diff < 0);
}
static inline int fbcCeil(float value)
{
int i = fbcRound(value);
float diff = (float)(i - value);
return i + (diff < 0);
}
static inline int fbcCeil(int value)
{
return value;
}
} // yt_tinycv
#endif // FBC_CV_CORE_FAST_MATH_HPP_

View File

@@ -0,0 +1,67 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_FBCDEF_HPP_
#define FBC_CV_CORE_FBCDEF_HPP_
/* reference: include/opencv2/core/cvdef.h
include/opencv2/core/typedef_c.h
*/
#include "interface.hpp"
#ifdef _MSC_VER
#define FBC_EXPORTS __declspec(dllexport)
#define FBC_DECL_ALIGNED(x) __declspec(align(x))
#else
#define FBC_EXPORTS __attribute__((visibility("default")))
#define FBC_DECL_ALIGNED(x) __attribute__((aligned(x)))
#endif
namespace yt_tinycv {
#define FBC_CN_MAX 512
#define FBC_CN_SHIFT 3
#define FBC_DEPTH_MAX (1 << FBC_CN_SHIFT)
#define FBC_MAT_TYPE_MASK (FBC_DEPTH_MAX*FBC_CN_MAX - 1)
#define FBC_MAT_TYPE(flags) ((flags) & FBC_MAT_TYPE_MASK)
#ifndef MIN
#define MIN(a,b) ((a) > (b) ? (b) : (a))
#endif
#ifndef MAX
#define MAX(a,b) ((a) < (b) ? (b) : (a))
#endif
#define FBC_CN_MAX 512
// Common macros and inline functions
#define FBC_SWAP(a,b,t) ((t) = (a), (a) = (b), (b) = (t))
/** min & max without jumps */
#define FBC_IMIN(a, b) ((a) ^ (((a)^(b)) & (((a) < (b)) - 1)))
#define FBC_IMAX(a, b) ((a) ^ (((a)^(b)) & (((a) > (b)) - 1)))
// fundamental constants
#define FBC_PI 3.1415926535897932384626433832795
// Note: No practical significance
class dump {};
typedef union Cv32suf {
int i;
unsigned u;
float f;
} Cv32suf;
typedef union Cv64suf {
int64 i;
yt_tinycv::uint64 u;
double f;
} Cv64suf;
} // namespace yt_tinycv
#endif // FBC_CV_CORE_FBCDEF_HPP_

View File

@@ -0,0 +1,30 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_FBCSTD_HPP_
#define FBC_CV_CORE_FBCSTD_HPP_
// reference: include/opencv2/core/cvstd.hpp
#include "fbcdef.hpp"
#ifndef __cplusplus
#error fbcstd.hpp header must be compiled as C++
#endif
namespace yt_tinycv {
/* the alignment of all the allocated buffers */
#define FBC_MALLOC_ALIGN 16
// Allocates an aligned memory buffer
FBC_EXPORTS void* fastMalloc(size_t size);
// Deallocates a memory buffer
FBC_EXPORTS void fastFree(void* ptr);
void* cvAlloc(size_t size);
void cvFree_(void* ptr);
#define cvFree(ptr) (cvFree_(*(ptr)), *(ptr)=0)
} // namespace yt_tinycv
#endif // FBC_CV_CORE_FBCSTD_HPP_

View File

@@ -0,0 +1,316 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_IMGPROC_HPP_
#define FBC_CV_IMGPROC_HPP_
// reference: include/opencv2/imgproc.hpp
#include "fbcdef.hpp"
#include "interface.hpp"
#include "mat.hpp"
#include "core.hpp"
namespace yt_tinycv {
// interpolation algorithm
enum InterpolationFlags{
/** nearest neighbor interpolation */
INTER_NEAREST = 0,
/** bilinear interpolation */
INTER_LINEAR = 1,
/** bicubic interpolation */
INTER_CUBIC = 2,
/** resampling using pixel area relation. It may be a preferred method for image decimation, as
it gives moire'-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method. */
INTER_AREA = 3,
/** Lanczos interpolation over 8x8 neighborhood */
INTER_LANCZOS4 = 4,
/** mask for interpolation codes */
INTER_MAX = 7,
/** flag, fills all of the destination image pixels. If some of them correspond to outliers in the
source image, they are set to zero */
WARP_FILL_OUTLIERS = 8,
/** flag, inverse transformation
For example, polar transforms:
- flag is __not__ set: \f$dst( \phi , \rho ) = src(x,y)\f$
- flag is set: \f$dst(x,y) = src( \phi , \rho )\f$
*/
WARP_INVERSE_MAP = 16
};
enum InterpolationMasks {
INTER_BITS = 5,
INTER_BITS2 = INTER_BITS * 2,
INTER_TAB_SIZE = 1 << INTER_BITS,
INTER_TAB_SIZE2 = INTER_TAB_SIZE * INTER_TAB_SIZE
};
// Constants for color conversion
enum ColorConversionFlags {
CV_BGR2BGRA = 0,
CV_RGB2RGBA = CV_BGR2BGRA,
CV_BGRA2BGR = 1,
CV_RGBA2RGB = CV_BGRA2BGR,
CV_BGR2RGBA = 2,
CV_RGB2BGRA = CV_BGR2RGBA,
CV_RGBA2BGR = 3,
CV_BGRA2RGB = CV_RGBA2BGR,
CV_BGR2RGB = 4,
CV_RGB2BGR = CV_BGR2RGB,
CV_BGRA2RGBA = 5,
CV_RGBA2BGRA = CV_BGRA2RGBA,
CV_BGR2GRAY = 6,
CV_RGB2GRAY = 7,
CV_GRAY2BGR = 8,
CV_GRAY2RGB = CV_GRAY2BGR,
CV_GRAY2BGRA = 9,
CV_GRAY2RGBA = CV_GRAY2BGRA,
CV_BGRA2GRAY = 10,
CV_RGBA2GRAY = 11,
// CV_BGR2BGR565 // 12 - 31
CV_BGR2XYZ = 32,
CV_RGB2XYZ = 33,
CV_XYZ2BGR = 34,
CV_XYZ2RGB = 35,
CV_BGR2YCrCb = 36,
CV_RGB2YCrCb = 37,
CV_YCrCb2BGR = 38,
CV_YCrCb2RGB = 39,
CV_BGR2HSV = 40,
CV_RGB2HSV = 41,
CV_BGR2Lab = 44,
CV_RGB2Lab = 45,
// CV_BayerBG2BGR // 46 - 49
CV_BGR2Luv = 50,
CV_RGB2Luv = 51,
CV_BGR2HLS = 52,
CV_RGB2HLS = 53,
CV_HSV2BGR = 54,
CV_HSV2RGB = 55,
CV_Lab2BGR = 56,
CV_Lab2RGB = 57,
CV_Luv2BGR = 58,
CV_Luv2RGB = 59,
CV_HLS2BGR = 60,
CV_HLS2RGB = 61,
// CV_BayerBG2BGR_VNG // 62 - 65
CV_BGR2HSV_FULL = 66,
CV_RGB2HSV_FULL = 67,
CV_BGR2HLS_FULL = 68,
CV_RGB2HLS_FULL = 69,
CV_HSV2BGR_FULL = 70,
CV_HSV2RGB_FULL = 71,
CV_HLS2BGR_FULL = 72,
CV_HLS2RGB_FULL = 73,
// CV_LBGR2Lab // 74 - 81
CV_BGR2YUV = 82,
CV_RGB2YUV = 83,
CV_YUV2BGR = 84,
CV_YUV2RGB = 85,
// CV_BayerBG2GRAY // 86 - 89
//YUV 4:2:0 formats family
CV_YUV2RGB_NV12 = 90,
CV_YUV2BGR_NV12 = 91,
CV_YUV2RGB_NV21 = 92,
CV_YUV2BGR_NV21 = 93,
CV_YUV420sp2RGB = CV_YUV2RGB_NV21,
CV_YUV420sp2BGR = CV_YUV2BGR_NV21,
CV_YUV2RGBA_NV12 = 94,
CV_YUV2BGRA_NV12 = 95,
CV_YUV2RGBA_NV21 = 96,
CV_YUV2BGRA_NV21 = 97,
CV_YUV420sp2RGBA = CV_YUV2RGBA_NV21,
CV_YUV420sp2BGRA = CV_YUV2BGRA_NV21,
CV_YUV2RGB_YV12 = 98,
CV_YUV2BGR_YV12 = 99,
CV_YUV2RGB_IYUV = 100,
CV_YUV2BGR_IYUV = 101,
CV_YUV2RGB_I420 = CV_YUV2RGB_IYUV,
CV_YUV2BGR_I420 = CV_YUV2BGR_IYUV,
CV_YUV420p2RGB = CV_YUV2RGB_YV12,
CV_YUV420p2BGR = CV_YUV2BGR_YV12,
CV_YUV2RGBA_YV12 = 102,
CV_YUV2BGRA_YV12 = 103,
CV_YUV2RGBA_IYUV = 104,
CV_YUV2BGRA_IYUV = 105,
CV_YUV2RGBA_I420 = CV_YUV2RGBA_IYUV,
CV_YUV2BGRA_I420 = CV_YUV2BGRA_IYUV,
CV_YUV420p2RGBA = CV_YUV2RGBA_YV12,
CV_YUV420p2BGRA = CV_YUV2BGRA_YV12,
CV_YUV2GRAY_420 = 106,
CV_YUV2GRAY_NV21 = CV_YUV2GRAY_420,
CV_YUV2GRAY_NV12 = CV_YUV2GRAY_420,
CV_YUV2GRAY_YV12 = CV_YUV2GRAY_420,
CV_YUV2GRAY_IYUV = CV_YUV2GRAY_420,
CV_YUV2GRAY_I420 = CV_YUV2GRAY_420,
CV_YUV420sp2GRAY = CV_YUV2GRAY_420,
CV_YUV420p2GRAY = CV_YUV2GRAY_420,
// YUV 4:2:2 formats family // 107 - 124
// alpha premultiplication // 125 - 126
CV_RGB2YUV_I420 = 127,
CV_BGR2YUV_I420 = 128,
CV_RGB2YUV_IYUV = CV_RGB2YUV_I420,
CV_BGR2YUV_IYUV = CV_BGR2YUV_I420,
CV_RGBA2YUV_I420 = 129,
CV_BGRA2YUV_I420 = 130,
CV_RGBA2YUV_IYUV = CV_RGBA2YUV_I420,
CV_BGRA2YUV_IYUV = CV_BGRA2YUV_I420,
CV_RGB2YUV_YV12 = 131,
CV_BGR2YUV_YV12 = 132,
CV_RGBA2YUV_YV12 = 133,
CV_BGRA2YUV_YV12 = 134
// Edge-Aware Demosaicing // 135 - 139
};
// type of morphological operation
enum MorphTypes{
MORPH_ERODE = 0, // see cv::erode
MORPH_DILATE = 1, // see cv::dilate
MORPH_OPEN = 2, // an opening operation
// \f[\texttt{dst} = \mathrm{open} ( \texttt{src} , \texttt{element} )= \mathrm{dilate} ( \mathrm{erode} ( \texttt{src} , \texttt{element} ))\f]
MORPH_CLOSE = 3, // a closing operation
// \f[\texttt{dst} = \mathrm{close} ( \texttt{src} , \texttt{element} )= \mathrm{erode} ( \mathrm{dilate} ( \texttt{src} , \texttt{element} ))\f]
MORPH_GRADIENT = 4, // a morphological gradient
// \f[\texttt{dst} = \mathrm{morph\_grad} ( \texttt{src} , \texttt{element} )= \mathrm{dilate} ( \texttt{src} , \texttt{element} )- \mathrm{erode} ( \texttt{src} , \texttt{element} )\f]
MORPH_TOPHAT = 5, // "top hat"
// \f[\texttt{dst} = \mathrm{tophat} ( \texttt{src} , \texttt{element} )= \texttt{src} - \mathrm{open} ( \texttt{src} , \texttt{element} )\f]
MORPH_BLACKHAT = 6, // "black hat"
// \f[\texttt{dst} = \mathrm{blackhat} ( \texttt{src} , \texttt{element} )= \mathrm{close} ( \texttt{src} , \texttt{element} )- \texttt{src}\f]
MORPH_HITMISS = 7 // "hit and miss"
// Only supported for CV_8UC1 binary images. Tutorial can be found in [this page](http://opencv-code.com/tutorials/hit-or-miss-transform-in-opencv/)
};
// shape of the structuring element
enum MorphShapes {
MORPH_RECT = 0, // a rectangular structuring element: \f[E_{ij}=1\f]
MORPH_CROSS = 1, // a cross-shaped structuring element:
//!< \f[E_{ij} = \fork{1}{if i=\texttt{anchor.y} or j=\texttt{anchor.x}}{0}{otherwise}\f]
MORPH_ELLIPSE = 2 // an elliptic structuring element, that is, a filled ellipse inscribed
// into the rectangle Rect(0, 0, esize.width, 0.esize.height)
};
// type of the threshold operation
enum ThresholdTypes {
THRESH_BINARY = 0, // \f[\texttt{dst} (x,y) = \fork{\texttt{maxval}}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{0}{otherwise}\f]
THRESH_BINARY_INV = 1, // \f[\texttt{dst} (x,y) = \fork{0}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{maxval}}{otherwise}\f]
THRESH_TRUNC = 2, // \f[\texttt{dst} (x,y) = \fork{\texttt{threshold}}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{src}(x,y)}{otherwise}\f]
THRESH_TOZERO = 3, // \f[\texttt{dst} (x,y) = \fork{\texttt{src}(x,y)}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{0}{otherwise}\f]
THRESH_TOZERO_INV = 4, // \f[\texttt{dst} (x,y) = \fork{0}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{src}(x,y)}{otherwise}\f]
THRESH_MASK = 7,
THRESH_OTSU = 8, // flag, use Otsu algorithm to choose the optimal threshold value, combine the flag with one of the above THRESH_* values
THRESH_TRIANGLE = 16 // flag, use Triangle algorithm to choose the optimal threshold value, combine the flag with one of the above THRESH_* values, but not with THRESH_OTSU
};
// adaptive threshold algorithm
enum AdaptiveThresholdTypes {
/** the threshold value \f$T(x,y)\f$ is a mean of the \f$\texttt{blockSize} \times
\texttt{blockSize}\f$ neighborhood of \f$(x, y)\f$ minus C */
ADAPTIVE_THRESH_MEAN_C = 0,
/** the threshold value \f$T(x, y)\f$ is a weighted sum (cross-correlation with a Gaussian
window) of the \f$\texttt{blockSize} \times \texttt{blockSize}\f$ neighborhood of \f$(x, y)\f$
minus C . The default sigma (standard deviation) is used for the specified blockSize . See cv::getGaussianKernel*/
ADAPTIVE_THRESH_GAUSSIAN_C = 1
};
// helper tables
const uchar icvSaturate8u_cv[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255
};
#define FBC_FAST_CAST_8U(t) (assert(-256 <= (t) && (t) <= 512), icvSaturate8u_cv[(t)+256])
#define FBC_CALC_MIN_8U(a,b) (a) -= FBC_FAST_CAST_8U((a) - (b))
#define FBC_CALC_MAX_8U(a,b) (a) += FBC_FAST_CAST_8U((b) - (a))
// cal a structuring element of the specified size and shape for morphological operations
FBC_EXPORTS int getStructuringElement(Mat_<uchar, 1>& dst, int shape, Size ksize, Point anchor = Point(-1, -1));
// Returns the optimal DFT size for a given vector size
// Arrays whose size is a power-of-two (2, 4, 8, 16, 32, ...) are the fastest to process.
// Though, the arrays whose size is a product of 2's, 3's, and 5's are also processed quite efficiently
FBC_EXPORTS int getOptimalDFTSize(int vecsize);
} // namespace yt_tinycv
#endif // FBC_CV_IMGPROC_HPP_

View File

@@ -0,0 +1,38 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_INTERFACE_HPP_
#define FBC_CV_CORE_INTERFACE_HPP_
// reference: include/opencv2/core/hal/interface.h
#include <stdint.h>
namespace yt_tinycv {
/* primitive types */
/*
schar - signed 1 byte integer
uchar - unsigned 1 byte integer
short - signed 2 byte integer
ushort - unsigned 2 byte integer
int - signed 4 byte integer
uint - unsigned 4 byte integer
int64 - signed 8 byte integer
uint64 - unsigned 8 byte integer
*/
typedef unsigned int uint;
typedef signed char schar;
typedef unsigned char uchar;
typedef unsigned short ushort;
#ifdef _MSC_VER
typedef __int64 int64;
typedef unsigned __int64 uint64;
#else
typedef int64_t int64;
typedef uint64_t uint64;
#endif
} // yt_tinycv
#endif // FBC_CV_CORE_INTERFACE_HPP_

View File

@@ -0,0 +1,646 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_MAT_HPP_
#define FBC_CV_CORE_MAT_HPP_
/* reference: include/opencv2/core/mat.hpp
core/src/alloc.cpp
include/opencv2/core/utility.hpp
include/opencv2/core/cvstd.hpp
include/opencv2/core/mat.inl.hpp
*/
#ifndef __cplusplus
#error mat.hpp header must be compiled as C++
#endif
#include <typeinfo>
#include <string.h>
#include <float.h>
#include "fbcdef.hpp"
#include "types.hpp"
#include "base.hpp"
#include "interface.hpp"
#include "fbcstd.hpp"
#include "utility.hpp"
#include "saturate.hpp"
namespace yt_tinycv {
// The class Mat_ represents an n-dimensional dense numerical single-channel or multi-channel array
template<typename _Tp, int chs> class Mat_ {
public:
typedef _Tp value_type;
// default constructor
Mat_() : rows(0), cols(0), channels(0), data(NULL), step(0), allocated(false), datastart(NULL), dataend(NULL) {}
// constructs 2D matrix of the specified size
Mat_(int _rows, int _cols);
// constucts 2D matrix and fills it with the specified value _s
Mat_(int _rows, int _cols, const Scalar& _s);
// constructor for matrix headers pointing to user-allocated data, no data is copied
Mat_(int _rows, int _cols, void* _data);
// copy constructor, NOTE: deep copy
Mat_(const Mat_<_Tp, chs>& _m);
Mat_& operator = (const Mat_& _m);
Mat_ clone() const;
// reports whether the matrix is continuous or not
bool isContinuous() const;
// returns true if the matrix is a submatrix of another matrix
bool isSubmatrix() const;
// copies the matrix content to "_m"
void copyTo(Mat_<_Tp, chs>& _m, const Rect& rect = Rect(0, 0, 0, 0)) const;
// return typed pointer to the specified matrix row,i0, A 0-based row index
const uchar* ptr(int i0 = 0) const;
uchar* ptr(int i0 = 0);
// no data is copied, no memory is allocated
void getROI(Mat_<_Tp, chs>& _m, const Rect& rect = Rect(0, 0, 0, 0));
// Locates the matrix header within a parent matrix
void locateROI(Size& wholeSize, Point& ofs) const;
// Adjusts a submatrix size and position within the parent matrix
void adjustROI(int dtop, int dbottom, int dleft, int dright);
// value converted to the actual array type
void setTo(const Scalar& _value);
// Converts an array to another data type with optional scaling
// the method converts source pixel values to the target data type
// if it does not have a proper size before the operation, it is reallocated
// \f[m(x,y) = saturate \_ cast<rType>( \alpha (*this)(x,y) + \beta )\f]
template<typename _Tp2>
void convertTo(Mat_<_Tp2, chs>& _m, double alpha = 1, const Scalar& scalar = Scalar(0, 0, 0, 0)) const;
Mat_<_Tp, chs>& zeros(int _rows, int _cols);
// returns the matrix cols and rows
Size size() const;
// returns true if Mat_::total() is 0 or if Mat_::data is NULL
bool empty() const;
// returns the matrix element size in bytes: sizeof(_Tp) * channels
size_t elemSize() const;
// returns the size of each matrix element channel in bytes: sizeof(_Tp)
size_t elemSize1() const;
// returns the total number of array elements
size_t total() const;
// release memory
inline void release();
// destructor - calls release()
~Mat_() { release(); };
public:
// the number of rows and columns
int rows, cols;
// channel num
int channels;
// pointer to the data
uchar* data;
// bytes per row
int step; // stride
// memory allocation flag
bool allocated;
// helper fields used in locateROI and adjustROI
const uchar* datastart;
const uchar* dataend;
}; // Mat_
typedef Mat_<uchar, 1> Mat1Gray;
typedef Mat_<uchar, 3> Mat3BGR;
typedef Mat_<uchar, 4> Mat4BGRA;
template<typename _Tp, int chs> inline
void Mat_<_Tp, chs>::release()
{
if (this->data && this->allocated) {
fastFree(this->data);
}
this->data = NULL;
this->datastart = NULL;
this->dataend = NULL;
this->allocated = false;
this->rows = this->cols = this->step = this->channels = 0;
}
template<typename _Tp, int chs>
Mat_<_Tp, chs>::Mat_(int _rows, int _cols)
{
FBC_Assert(_rows > 0 && _cols > 0 && chs > 0);
this->rows = _rows;
this->cols = _cols;
this->channels = chs;
this->step = sizeof(_Tp) * _cols * chs;
this->allocated = true;
size_t size_ = this->rows * this->step;
uchar* p = (uchar*)fastMalloc(size_);
FBC_Assert(p != NULL);
this->data = p;
this->datastart = this->data;
this->dataend = this->data + size_;
}
template<typename _Tp, int chs>
Mat_<_Tp, chs>::Mat_(int _rows, int _cols, const Scalar& _s)
{
FBC_Assert(_rows > 0 && _cols > 0 && chs > 0);
this->rows = _rows;
this->cols = _cols;
this->channels = chs;
this->step = sizeof(_Tp) * _cols * chs;
this->allocated = true;
size_t size_ = this->rows * this->step;
uchar* p = (uchar*)fastMalloc(size_);
FBC_Assert(p != NULL);
this->data = p;
this->datastart = this->data;
this->dataend = this->data + size_;
for (int i = 0; i < _rows; i++) {
_Tp* pRow = (_Tp*)this->data + i * _cols * chs;
for (int j = 0; j < _cols; j++) {
_Tp* pPixel = pRow + j * chs;
for (int m = 0, n = 0; m < chs && n < 4; m++, n++) {
pPixel[n] = saturate_cast<_Tp>(_s.val[n]);
}
}
}
}
template<typename _Tp, int chs>
Mat_<_Tp, chs>::Mat_(int _rows, int _cols, void* _data)
{
FBC_Assert(_rows > 0 && _cols > 0 && chs > 0);
this->rows = _rows;
this->cols = _cols;
this->channels = chs;
this->step = sizeof(_Tp) * _cols * chs;
this->allocated = false;
this->data = (uchar*)_data;
this->datastart = this->data;
this->dataend = this->data + this->step * this->rows;
}
template<typename _Tp, int chs>
Mat_<_Tp, chs>::Mat_(const Mat_<_Tp, chs>& _m)
{
this->rows = _m.rows;
this->cols = _m.cols;
this->channels = _m.channels;
this->step = sizeof(_Tp) * this->cols * this->channels;
size_t size_ = this->rows * this->step;
if (size_ > 0) {
this->allocated = true;
uchar* p = (uchar*)fastMalloc(size_);
FBC_Assert(p != NULL);
memcpy(p, _m.data, size_);
this->data = p;
} else {
this->allocated = false;
this->data = NULL;
}
this->datastart = this->data;
this->dataend = this->data + size_;
}
// template<typename _Tp, int chs>
// Mat_<_Tp, chs>& Mat_<_Tp, chs>::operator () (const Rect& roi)
// {
// return *this;
// }
template<typename _Tp, int chs>
Mat_<_Tp, chs>& Mat_<_Tp, chs>::operator = (const Mat_& _m)
{
size_t size1 = this->rows * this->step;
size_t size2 = _m.rows * _m.step;
this->rows = _m.rows;
this->cols = _m.cols;
this->channels = _m.channels;
this->step = sizeof(_Tp) * this->cols * this->channels;
if ((size1 == size2) && (this->allocated == true) && (this->data != _m.data)) {
memcpy(this->data, _m.data, size2);
} else if (size2 > 0){
if (this->allocated == true) {
fastFree(this->data);
}
this->allocated = true;
uchar* p = (uchar*)fastMalloc(size2);
FBC_Assert(p != NULL);
memcpy(p, _m.data, size2);
this->data = p;
} else {
this->allocated = false;
this->data = NULL;
}
this->datastart = this->data;
this->dataend = this->data + size2;
return *this;
}
template<typename _Tp, int chs>
Mat_<_Tp, chs> Mat_<_Tp, chs>::clone() const
{
Mat_ m;
Rect rect(0, 0, this->cols, this->rows);
copyTo(m, rect);
return m;
}
template<typename _Tp, int chs>
bool Mat_<_Tp, chs>::isContinuous() const
{
return this->rows == 1 || this->step == this->cols * this->elemSize();
}
template<typename _Tp, int chs>
bool Mat_<_Tp, chs>::isSubmatrix() const
{
if ((this->datastart < this->data) || ((this->data + this->step * this->rows) < this->dataend))
return true;
return false;
}
template<typename _Tp, int chs>
void Mat_<_Tp, chs>::copyTo(Mat_<_Tp, chs>& _m, const Rect& rect) const
{
FBC_Assert((this->rows >= rect.y + rect.height) && (this->cols >= rect.x + rect.width));
if (this->data != NULL) {
if ((rect.width > 0) && (rect.height > 0)) {
size_t size1 = sizeof(_Tp) * this->channels * rect.width * rect.height;
int step_ = sizeof(_Tp) * this->channels * rect.width;
size_t size2 = _m.rows * _m.step;
if (size1 == size2) {
uchar* p1 = _m.data;
uchar* p2 = this->data;
for (int i = 0; i < rect.height; i++) {
uchar* p1_ = p1 + i * sizeof(_Tp) * this->channels * rect.width;
uchar* p2_ = p2 + (rect.y + i) * this->step + rect.x * this->channels * sizeof(_Tp);
memcpy(p1_, p2_, step_);
}
} else {
if (_m.allocated == true)
fastFree(_m.data);
uchar* p1 = (uchar*)fastMalloc(size1);
FBC_Assert(p1 != NULL);
uchar* p2 = this->data;
for (int i = 0; i < rect.height; i++) {
uchar* p1_ = p1 + i * sizeof(_Tp) * this->channels * rect.width;
uchar* p2_ = p2 + (rect.y + i) * this->step + rect.x * this->channels * sizeof(_Tp);
memcpy(p1_, p2_, step_);
}
_m.data = p1;
_m.allocated = true;
}
_m.rows = rect.height;
_m.cols = rect.width;
_m.step = step_;
} else {
size_t size1 = this->rows * this->step;
size_t size2 = _m.step * _m.rows;
if (size1 == size2) {
memcpy(_m.data, this->data, size1);
} else {
if (_m.allocated == true)
fastFree(_m.data);
uchar* p = (uchar*)fastMalloc(size1);
FBC_Assert(p != NULL);
memcpy(p, this->data, size1);
_m.data = p;
_m.allocated = true;
}
_m.rows = this->rows;
_m.cols = this->cols;
_m.step = this->step;
}
_m.channels = this->channels;
} else {
if ((_m.data != NULL) && (_m.allocated == true)) {
fastFree(_m.data);
}
_m.data = NULL;
_m.allocated = false;
_m.rows = 0;
_m.cols = 0;
_m.step = 0;
_m.channels = 0;
}
_m.datastart = _m.data;
_m.dataend = _m.data + _m.step * _m.rows;
}
template<typename _Tp, int chs>
const uchar* Mat_<_Tp, chs>::ptr(int i0) const
{
FBC_Assert(i0 < this->rows);
return this->data + i0 * this->step;
}
template<typename _Tp, int chs>
uchar* Mat_<_Tp, chs>::ptr(int i0)
{
FBC_Assert(i0 < this->rows);
return this->data + i0 * this->step;
}
template<typename _Tp, int chs>
void Mat_<_Tp, chs>::getROI(Mat_<_Tp, chs>& _m, const Rect& rect)
{
FBC_Assert((rect.x >= 0) && (rect.y >= 0) && (rect.width > 0) && (rect.height > 0) &&
(this->rows >= rect.y + rect.height) && (this->cols >= rect.x + rect.width));
if (_m.allocated == true) {
fastFree(_m.data);
}
_m.rows = rect.height;
_m.cols = rect.width;
_m.channels = this->channels;
_m.allocated = false;
_m.step = this->step;
_m.data = this->data + rect.y * this->step + rect.x * sizeof(_Tp) * this->channels;
_m.datastart = this->datastart;
_m.dataend = this->dataend;
}
template<typename _Tp, int chs>
void Mat_<_Tp, chs>::locateROI(Size& wholeSize, Point& ofs) const
{
wholeSize.width = this->step / (sizeof(_Tp) * chs);
wholeSize.height = (this->dataend - this->datastart) / this->step;
ofs.y = (this->data - this->datastart) / this->step;
ofs.x = ((this->data - this->datastart) - ((this->data - this->datastart) / this->step * this->step)) / (sizeof(_Tp) * chs);
FBC_Assert(wholeSize.width >= 0 && wholeSize.height >= 0 && ofs.x >= 0 && ofs.y >= 0);
}
template<typename _Tp, int chs>
void Mat_<_Tp, chs>::adjustROI(int dtop, int dbottom, int dleft, int dright)
{
Size wholeSize; Point ofs;
size_t esz = elemSize();
locateROI(wholeSize, ofs);
int row1 = std::max(ofs.y - dtop, 0);
int row2 = std::min(ofs.y + rows + dbottom, wholeSize.height);
int col1 = std::max(ofs.x - dleft, 0);
int col2 = std::min(ofs.x + cols + dright, wholeSize.width);
this->data += (row1 - ofs.y)*step + (col1 - ofs.x)*esz;
this->rows = row2 - row1;
this->cols = col2 - col1;
}
template<typename _Tp, int chs>
void Mat_<_Tp, chs>::setTo(const Scalar& _value)
{
for (int i = 0; i < this->rows; i++) {
uchar* pRow = this->data + i * this->step;
for (int j = 0; j < this->cols; j++) {
_Tp* pPixel = (_Tp*)pRow + j * chs;
for (int m = 0, n = 0; m < chs && n < 4; m++, n++) {
pPixel[n] = saturate_cast<_Tp>(_value.val[n]);
}
}
}
}
template<typename _Tp, int chs> template<typename _Tp2>
void Mat_<_Tp, chs>::convertTo(Mat_<_Tp2, chs>& _m, double alpha, const Scalar& scalar) const
{
FBC_Assert(this->channels <= 4);
bool noScale = fabs(alpha - 1) < DBL_EPSILON && fabs(scalar[0]) < DBL_EPSILON && fabs(scalar[1]) < DBL_EPSILON &&
fabs(scalar[2]) < DBL_EPSILON && fabs(scalar[3]) < DBL_EPSILON;
/*if ((typeid(_Tp).name() == typeid(_Tp2).name()) && noScale) {
this->copyTo(_m);
return;
}*/
size_t size = this->rows * this->cols * this->channels * sizeof(_Tp2);
if (this->rows * this->cols != _m.rows * _m.cols) {
if (_m.allocated == true) {
fastFree(_m.data);
}
uchar* p = (uchar*)fastMalloc(size);
FBC_Assert(p != NULL);
_m.data = p;
_m.allocated = true;
}
_m.channels = this->channels;
_m.rows = this->rows;
_m.cols = this->cols;
_m.step = _m.cols * sizeof(_Tp2) * _m.channels;
_m.datastart = _m.data;
_m.dataend = _m.data + _m.step * _m.rows;
_Tp2 alpha_ = (_Tp2)alpha;
Scalar_<_Tp2> scalar_;
for (int i = 0; i < 4; i++) {
scalar_.val[i]= (_Tp2)scalar.val[i];
}
for (int i = 0; i < this->rows; i++) {
uchar* p1 = this->data + i * this->step;
uchar* p2 = _m.data + i * _m.step;
for (int j = 0; j < this->cols; j++) {
_Tp* p1_ = (_Tp*)p1 + j * chs;
_Tp2* p2_ = (_Tp2*)p2 + j * chs;
for (int ch = 0; ch < chs; ch++) {
p2_[ch] = saturate_cast<_Tp2>(p1_[ch] * alpha_ + scalar_.val[ch]);
}
}
}
}
template<typename _Tp, int chs>
Mat_<_Tp, chs>& Mat_<_Tp, chs>::zeros(int _rows, int _cols)
{
this->rows = _rows;
this->cols = _cols;
this->channels = chs;
this->step = sizeof(_Tp) * _cols * chs;
this->allocated = true;
size_t size_ = this->rows * this->step;
uchar* p = (uchar*)fastMalloc(size_);
FBC_Assert(p != NULL);
this->data = p;
memset(this->data, 0, size_);
return *this;
}
template<typename _Tp, int chs>
Size Mat_<_Tp, chs>::size() const
{
return Size(this->cols, this->rows);
}
template<typename _Tp, int chs>
size_t Mat_<_Tp, chs>::elemSize() const
{
return (this->channels * sizeof(_Tp));
}
template<typename _Tp, int chs>
size_t Mat_<_Tp, chs>::elemSize1() const
{
return sizeof(_Tp);
}
template<typename _Tp, int chs>
size_t Mat_<_Tp, chs>::total() const
{
return (size_t)rows * cols;
}
template<typename _Tp, int chs>
bool Mat_<_Tp, chs>::empty() const
{
return total() == 0 || this->data == NULL;
}
/////////////////////////// Mat_ out-of-class operators ///////////////////////////
template<typename _Tp1, typename _Tp2, int chs> static inline
Mat_<_Tp1, chs>& operator -= (Mat_<_Tp1, chs>& a, const Mat_<_Tp2, chs>& b)
{
FBC_Assert(a.rows == b.rows && a.cols == b.cols);
for (int y = 0; y < a.rows; y++) {
_Tp1* pa = (_Tp1*)a.ptr(y);
_Tp2* pb = (_Tp2*)b.ptr(y);
for (int x = 0; x < a.cols * chs; x++) {
pa[x] = saturate_cast<_Tp1>(pa[x] - pb[x]);
}
}
return a;
}
template<typename _Tp1, typename _Tp2, int chs> static inline
Mat_<_Tp1, chs>& operator += (Mat_<_Tp1, chs>& a, const Mat_<_Tp2, chs>& b)
{
FBC_Assert(a.rows == b.rows && a.cols == b.cols);
for (int y = 0; y < a.rows; y++) {
_Tp1* pa = (_Tp1*)a.ptr(y);
_Tp2* pb = (_Tp2*)b.ptr(y);
for (int x = 0; x < a.cols * chs; x++) {
pa[x] = saturate_cast<_Tp1>(pa[x] + pb[x]);
}
}
return a;
}
template<typename _Tp1, typename _Tp2, int chs> static inline
Mat_<_Tp1, chs> operator - (const Mat_<_Tp1, chs>& a, const Mat_<_Tp2, chs>& b)
{
FBC_Assert(a.rows == b.rows && a.cols == b.cols);
Mat_<_Tp1, chs> c(a.rows, a.cols);
for (int y = 0; y < a.rows; y++) {
_Tp1* pa = (_Tp1*)a.ptr(y);
_Tp2* pb = (_Tp2*)b.ptr(y);
_Tp1* pc = (_Tp1*)c.ptr(y);
for (int x = 0; x < a.cols * chs; x++) {
pc[x] = saturate_cast<_Tp1>(pa[x] - pb[x]);
}
}
return c;
}
template<typename _Tp1, typename _Tp2, int chs> static inline
Mat_<_Tp1, chs> operator == (const Mat_<_Tp1, chs>& a, const Mat_<_Tp2, chs>& b)
{
FBC_Assert(a.rows == b.rows && a.cols == b.cols);
Mat_<_Tp1, chs> c(a.rows, a.cols);
for (int y = 0; y < a.rows; y++) {
_Tp1* pa = (_Tp1*)a.ptr(y);
_Tp2* pb = (_Tp2*)b.ptr(y);
_Tp1* pc = (_Tp1*)c.ptr(y);
for (int x = 0; x < a.cols * chs; x++) {
pc[x] = pa[x] != pb[x] ? 0 : 1;
}
}
return c;
}
template<typename _Tp, int chs> static inline
Mat_<_Tp, chs> operator & (const Mat_<_Tp, chs>& a, const Mat_<_Tp, chs>& b)
{
FBC_Assert(a.rows == b.rows && a.cols == b.cols);
Mat_<_Tp, chs> c(a.rows, a.cols);
for (int y = 0; y < a.rows; y++) {
_Tp* pa = (_Tp*)a.ptr(y);
_Tp* pb = (_Tp*)b.ptr(y);
_Tp* pc = (_Tp*)c.ptr(y);
for (int x = 0; x < a.cols * chs; x++) {
pc[x] = pa[x] & pb[x];
}
}
return c;
}
} // yt_tinycv
#endif // FBC_CV_CORE_MAT_HPP_

View File

@@ -0,0 +1,667 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_MATHFUNCS_HPP_
#define FBC_CV_CORE_MATHFUNCS_HPP_
/* reference: include/opencv2/core.hpp
modules/core/src/mathfuncs.cpp
modules/core/src/mathfuncs_core.cpp
*/
#include "mat.hpp"
#include "NAryMatIterator.hpp"
namespace yt_tinycv {
// calculates the magnitude of 2D vectors formed from the corresponding elements of x and y arrays
// \f[\texttt{dst} (I) = \sqrt{\texttt{x}(I)^2 + \texttt{y}(I)^2}\f]
// support type: float/double, multi-channels
// template <typename _Tp, int chs>
// int magnitude(const Mat_<_Tp, chs>& src1, const Mat_<_Tp, chs>& src2, Mat_<_Tp, chs>& dst)
// {
// FBC_Assert(typeid(float).name() == typeid(_Tp).name() || typeid(double).name() == typeid(_Tp).name());
// FBC_Assert(src1.size() == src2.size());
// if (dst.empty()) {
// dst = Mat_<_Tp, chs>(src1.rows, src1.cols);
// } else {
// FBC_Assert(src1.size() == dst.size());
// }
// for (int y = 0; y < src1.rows; y++) {
// const _Tp* pRowSrc1 = (const _Tp*)src1.ptr(y);
// const _Tp* pRowSrc2 = (const _Tp*)src2.ptr(y);
// _Tp* pRowDst = (_Tp*)dst.ptr(y);
// for (int x = 0; x < src1.cols; x++) {
// pRowDst[x] = std::sqrt(pRowSrc1[x] * pRowSrc1[x] + pRowSrc2[x] * pRowSrc2[x]);
// }
// }
// return 0;
// }
/////////////////////////////////////////// LOG ///////////////////////////////////////
// #define LOGTAB_SCALE 8
// #define LOGTAB_MASK ((1 << LOGTAB_SCALE) - 1)
// #define LOGTAB_MASK2 ((1 << (20 - LOGTAB_SCALE)) - 1)
// #define LOGTAB_MASK2_32F ((1 << (23 - LOGTAB_SCALE)) - 1)
// static const double FBC_DECL_ALIGNED(16) ifbcLogTab[] = {
// 0.0000000000000000000000000000000000000000, 1.000000000000000000000000000000000000000,
// .00389864041565732288852075271279318258166, .9961089494163424124513618677042801556420,
// .00778214044205494809292034119607706088573, .9922480620155038759689922480620155038760,
// .01165061721997527263705585198749759001657, .9884169884169884169884169884169884169884,
// .01550418653596525274396267235488267033361, .9846153846153846153846153846153846153846,
// .01934296284313093139406447562578250654042, .9808429118773946360153256704980842911877,
// .02316705928153437593630670221500622574241, .9770992366412213740458015267175572519084,
// .02697658769820207233514075539915211265906, .9733840304182509505703422053231939163498,
// .03077165866675368732785500469617545604706, .9696969696969696969696969696969696969697,
// .03455238150665972812758397481047722976656, .9660377358490566037735849056603773584906,
// .03831886430213659461285757856785494368522, .9624060150375939849624060150375939849624,
// .04207121392068705056921373852674150839447, .9588014981273408239700374531835205992509,
// .04580953603129420126371940114040626212953, .9552238805970149253731343283582089552239,
// .04953393512227662748292900118940451648088, .9516728624535315985130111524163568773234,
// .05324451451881227759255210685296333394944, .9481481481481481481481481481481481481481,
// .05694137640013842427411105973078520037234, .9446494464944649446494464944649446494465,
// .06062462181643483993820353816772694699466, .9411764705882352941176470588235294117647,
// .06429435070539725460836422143984236754475, .9377289377289377289377289377289377289377,
// .06795066190850773679699159401934593915938, .9343065693430656934306569343065693430657,
// .07159365318700880442825962290953611955044, .9309090909090909090909090909090909090909,
// .07522342123758751775142172846244648098944, .9275362318840579710144927536231884057971,
// .07884006170777602129362549021607264876369, .9241877256317689530685920577617328519856,
// .08244366921107458556772229485432035289706, .9208633093525179856115107913669064748201,
// .08603433734180314373940490213499288074675, .9175627240143369175627240143369175627240,
// .08961215868968712416897659522874164395031, .9142857142857142857142857142857142857143,
// .09317722485418328259854092721070628613231, .9110320284697508896797153024911032028470,
// .09672962645855109897752299730200320482256, .9078014184397163120567375886524822695035,
// .10026945316367513738597949668474029749630, .9045936395759717314487632508833922261484,
// .10379679368164355934833764649738441221420, .9014084507042253521126760563380281690141,
// .10731173578908805021914218968959175981580, .8982456140350877192982456140350877192982,
// .11081436634029011301105782649756292812530, .8951048951048951048951048951048951048951,
// .11430477128005862852422325204315711744130, .8919860627177700348432055749128919860627,
// .11778303565638344185817487641543266363440, .8888888888888888888888888888888888888889,
// .12124924363286967987640707633545389398930, .8858131487889273356401384083044982698962,
// .12470347850095722663787967121606925502420, .8827586206896551724137931034482758620690,
// .12814582269193003360996385708858724683530, .8797250859106529209621993127147766323024,
// .13157635778871926146571524895989568904040, .8767123287671232876712328767123287671233,
// .13499516453750481925766280255629681050780, .8737201365187713310580204778156996587031,
// .13840232285911913123754857224412262439730, .8707482993197278911564625850340136054422,
// .14179791186025733629172407290752744302150, .8677966101694915254237288135593220338983,
// .14518200984449788903951628071808954700830, .8648648648648648648648648648648648648649,
// .14855469432313711530824207329715136438610, .8619528619528619528619528619528619528620,
// .15191604202584196858794030049466527998450, .8590604026845637583892617449664429530201,
// .15526612891112392955683674244937719777230, .8561872909698996655518394648829431438127,
// .15860503017663857283636730244325008243330, .8533333333333333333333333333333333333333,
// .16193282026931324346641360989451641216880, .8504983388704318936877076411960132890365,
// .16524957289530714521497145597095368430010, .8476821192052980132450331125827814569536,
// .16855536102980664403538924034364754334090, .8448844884488448844884488448844884488449,
// .17185025692665920060697715143760433420540, .8421052631578947368421052631578947368421,
// .17513433212784912385018287750426679849630, .8393442622950819672131147540983606557377,
// .17840765747281828179637841458315961062910, .8366013071895424836601307189542483660131,
// .18167030310763465639212199675966985523700, .8338762214983713355048859934853420195440,
// .18492233849401198964024217730184318497780, .8311688311688311688311688311688311688312,
// .18816383241818296356839823602058459073300, .8284789644012944983818770226537216828479,
// .19139485299962943898322009772527962923050, .8258064516129032258064516129032258064516,
// .19461546769967164038916962454095482826240, .8231511254019292604501607717041800643087,
// .19782574332991986754137769821682013571260, .8205128205128205128205128205128205128205,
// .20102574606059073203390141770796617493040, .8178913738019169329073482428115015974441,
// .20421554142869088876999228432396193966280, .8152866242038216560509554140127388535032,
// .20739519434607056602715147164417430758480, .8126984126984126984126984126984126984127,
// .21056476910734961416338251183333341032260, .8101265822784810126582278481012658227848,
// .21372432939771812687723695489694364368910, .8075709779179810725552050473186119873817,
// .21687393830061435506806333251006435602900, .8050314465408805031446540880503144654088,
// .22001365830528207823135744547471404075630, .8025078369905956112852664576802507836991,
// .22314355131420973710199007200571941211830, .8000000000000000000000000000000000000000,
// .22626367865045338145790765338460914790630, .7975077881619937694704049844236760124611,
// .22937410106484582006380890106811420992010, .7950310559006211180124223602484472049689,
// .23247487874309405442296849741978803649550, .7925696594427244582043343653250773993808,
// .23556607131276688371634975283086532726890, .7901234567901234567901234567901234567901,
// .23864773785017498464178231643018079921600, .7876923076923076923076923076923076923077,
// .24171993688714515924331749374687206000090, .7852760736196319018404907975460122699387,
// .24478272641769091566565919038112042471760, .7828746177370030581039755351681957186544,
// .24783616390458124145723672882013488560910, .7804878048780487804878048780487804878049,
// .25088030628580937353433455427875742316250, .7781155015197568389057750759878419452888,
// .25391520998096339667426946107298135757450, .7757575757575757575757575757575757575758,
// .25694093089750041913887912414793390780680, .7734138972809667673716012084592145015106,
// .25995752443692604627401010475296061486000, .7710843373493975903614457831325301204819,
// .26296504550088134477547896494797896593800, .7687687687687687687687687687687687687688,
// .26596354849713793599974565040611196309330, .7664670658682634730538922155688622754491,
// .26895308734550393836570947314612567424780, .7641791044776119402985074626865671641791,
// .27193371548364175804834985683555714786050, .7619047619047619047619047619047619047619,
// .27490548587279922676529508862586226314300, .7596439169139465875370919881305637982196,
// .27786845100345625159121709657483734190480, .7573964497041420118343195266272189349112,
// .28082266290088775395616949026589281857030, .7551622418879056047197640117994100294985,
// .28376817313064456316240580235898960381750, .7529411764705882352941176470588235294118,
// .28670503280395426282112225635501090437180, .7507331378299120234604105571847507331378,
// .28963329258304265634293983566749375313530, .7485380116959064327485380116959064327485,
// .29255300268637740579436012922087684273730, .7463556851311953352769679300291545189504,
// .29546421289383584252163927885703742504130, .7441860465116279069767441860465116279070,
// .29836697255179722709783618483925238251680, .7420289855072463768115942028985507246377,
// .30126133057816173455023545102449133992200, .7398843930635838150289017341040462427746,
// .30414733546729666446850615102448500692850, .7377521613832853025936599423631123919308,
// .30702503529491181888388950937951449304830, .7356321839080459770114942528735632183908,
// .30989447772286465854207904158101882785550, .7335243553008595988538681948424068767908,
// .31275571000389684739317885942000430077330, .7314285714285714285714285714285714285714,
// .31560877898630329552176476681779604405180, .7293447293447293447293447293447293447293,
// .31845373111853458869546784626436419785030, .7272727272727272727272727272727272727273,
// .32129061245373424782201254856772720813750, .7252124645892351274787535410764872521246,
// .32411946865421192853773391107097268104550, .7231638418079096045197740112994350282486,
// .32694034499585328257253991068864706903700, .7211267605633802816901408450704225352113,
// .32975328637246797969240219572384376078850, .7191011235955056179775280898876404494382,
// .33255833730007655635318997155991382896900, .7170868347338935574229691876750700280112,
// .33535554192113781191153520921943709254280, .7150837988826815642458100558659217877095,
// .33814494400871636381467055798566434532400, .7130919220055710306406685236768802228412,
// .34092658697059319283795275623560883104800, .7111111111111111111111111111111111111111,
// .34370051385331840121395430287520866841080, .7091412742382271468144044321329639889197,
// .34646676734620857063262633346312213689100, .7071823204419889502762430939226519337017,
// .34922538978528827602332285096053965389730, .7052341597796143250688705234159779614325,
// .35197642315717814209818925519357435405250, .7032967032967032967032967032967032967033,
// .35471990910292899856770532096561510115850, .7013698630136986301369863013698630136986,
// .35745588892180374385176833129662554711100, .6994535519125683060109289617486338797814,
// .36018440357500774995358483465679455548530, .6975476839237057220708446866485013623978,
// .36290549368936841911903457003063522279280, .6956521739130434782608695652173913043478,
// .36561919956096466943762379742111079394830, .6937669376693766937669376693766937669377,
// .36832556115870762614150635272380895912650, .6918918918918918918918918918918918918919,
// .37102461812787262962487488948681857436900, .6900269541778975741239892183288409703504,
// .37371640979358405898480555151763837784530, .6881720430107526881720430107526881720430,
// .37640097516425302659470730759494472295050, .6863270777479892761394101876675603217158,
// .37907835293496944251145919224654790014030, .6844919786096256684491978609625668449198,
// .38174858149084833769393299007788300514230, .6826666666666666666666666666666666666667,
// .38441169891033200034513583887019194662580, .6808510638297872340425531914893617021277,
// .38706774296844825844488013899535872042180, .6790450928381962864721485411140583554377,
// .38971675114002518602873692543653305619950, .6772486772486772486772486772486772486772,
// .39235876060286384303665840889152605086580, .6754617414248021108179419525065963060686,
// .39499380824086893770896722344332374632350, .6736842105263157894736842105263157894737,
// .39762193064713846624158577469643205404280, .6719160104986876640419947506561679790026,
// .40024316412701266276741307592601515352730, .6701570680628272251308900523560209424084,
// .40285754470108348090917615991202183067800, .6684073107049608355091383812010443864230,
// .40546510810816432934799991016916465014230, .6666666666666666666666666666666666666667,
// .40806588980822172674223224930756259709600, .6649350649350649350649350649350649350649,
// .41065992498526837639616360320360399782650, .6632124352331606217616580310880829015544,
// .41324724855021932601317757871584035456180, .6614987080103359173126614987080103359173,
// .41582789514371093497757669865677598863850, .6597938144329896907216494845360824742268,
// .41840189913888381489925905043492093682300, .6580976863753213367609254498714652956298,
// .42096929464412963239894338585145305842150, .6564102564102564102564102564102564102564,
// .42353011550580327293502591601281892508280, .6547314578005115089514066496163682864450,
// .42608439531090003260516141381231136620050, .6530612244897959183673469387755102040816,
// .42863216738969872610098832410585600882780, .6513994910941475826972010178117048346056,
// .43117346481837132143866142541810404509300, .6497461928934010152284263959390862944162,
// .43370832042155937902094819946796633303180, .6481012658227848101265822784810126582278,
// .43623676677491801667585491486534010618930, .6464646464646464646464646464646464646465,
// .43875883620762790027214350629947148263450, .6448362720403022670025188916876574307305,
// .44127456080487520440058801796112675219780, .6432160804020100502512562814070351758794,
// .44378397241030093089975139264424797147500, .6416040100250626566416040100250626566416,
// .44628710262841947420398014401143882423650, .6400000000000000000000000000000000000000,
// .44878398282700665555822183705458883196130, .6384039900249376558603491271820448877805,
// .45127464413945855836729492693848442286250, .6368159203980099502487562189054726368159,
// .45375911746712049854579618113348260521900, .6352357320099255583126550868486352357320,
// .45623743348158757315857769754074979573500, .6336633663366336633663366336633663366337,
// .45870962262697662081833982483658473938700, .6320987654320987654320987654320987654321,
// .46117571512217014895185229761409573256980, .6305418719211822660098522167487684729064,
// .46363574096303250549055974261136725544930, .6289926289926289926289926289926289926290,
// .46608972992459918316399125615134835243230, .6274509803921568627450980392156862745098,
// .46853771156323925639597405279346276074650, .6259168704156479217603911980440097799511,
// .47097971521879100631480241645476780831830, .6243902439024390243902439024390243902439,
// .47341577001667212165614273544633761048330, .6228710462287104622871046228710462287105,
// .47584590486996386493601107758877333253630, .6213592233009708737864077669902912621359,
// .47827014848147025860569669930555392056700, .6198547215496368038740920096852300242131,
// .48068852934575190261057286988943815231330, .6183574879227053140096618357487922705314,
// .48310107575113581113157579238759353756900, .6168674698795180722891566265060240963855,
// .48550781578170076890899053978500887751580, .6153846153846153846153846153846153846154,
// .48790877731923892879351001283794175833480, .6139088729016786570743405275779376498801,
// .49030398804519381705802061333088204264650, .6124401913875598086124401913875598086124,
// .49269347544257524607047571407747454941280, .6109785202863961813842482100238663484487,
// .49507726679785146739476431321236304938800, .6095238095238095238095238095238095238095,
// .49745538920281889838648226032091770321130, .6080760095011876484560570071258907363420,
// .49982786955644931126130359189119189977650, .6066350710900473933649289099526066350711,
// .50219473456671548383667413872899487614650, .6052009456264775413711583924349881796690,
// .50455601075239520092452494282042607665050, .6037735849056603773584905660377358490566,
// .50691172444485432801997148999362252652650, .6023529411764705882352941176470588235294,
// .50926190178980790257412536448100581765150, .6009389671361502347417840375586854460094,
// .51160656874906207391973111953120678663250, .5995316159250585480093676814988290398126,
// .51394575110223428282552049495279788970950, .5981308411214953271028037383177570093458,
// .51627947444845445623684554448118433356300, .5967365967365967365967365967365967365967,
// .51860776420804555186805373523384332656850, .5953488372093023255813953488372093023256,
// .52093064562418522900344441950437612831600, .5939675174013921113689095127610208816705,
// .52324814376454775732838697877014055848100, .5925925925925925925925925925925925925926,
// .52556028352292727401362526507000438869000, .5912240184757505773672055427251732101617,
// .52786708962084227803046587723656557500350, .5898617511520737327188940092165898617512,
// .53016858660912158374145519701414741575700, .5885057471264367816091954022988505747126,
// .53246479886947173376654518506256863474850, .5871559633027522935779816513761467889908,
// .53475575061602764748158733709715306758900, .5858123569794050343249427917620137299771,
// .53704146589688361856929077475797384977350, .5844748858447488584474885844748858447489,
// .53932196859560876944783558428753167390800, .5831435079726651480637813211845102505695,
// .54159728243274429804188230264117009937750, .5818181818181818181818181818181818181818,
// .54386743096728351609669971367111429572100, .5804988662131519274376417233560090702948,
// .54613243759813556721383065450936555862450, .5791855203619909502262443438914027149321,
// .54839232556557315767520321969641372561450, .5778781038374717832957110609480812641084,
// .55064711795266219063194057525834068655950, .5765765765765765765765765765765765765766,
// .55289683768667763352766542084282264113450, .5752808988764044943820224719101123595506,
// .55514150754050151093110798683483153581600, .5739910313901345291479820627802690582960,
// .55738115013400635344709144192165695130850, .5727069351230425055928411633109619686801,
// .55961578793542265941596269840374588966350, .5714285714285714285714285714285714285714,
// .56184544326269181269140062795486301183700, .5701559020044543429844097995545657015590,
// .56407013828480290218436721261241473257550, .5688888888888888888888888888888888888889,
// .56628989502311577464155334382667206227800, .5676274944567627494456762749445676274945,
// .56850473535266865532378233183408156037350, .5663716814159292035398230088495575221239,
// .57071468100347144680739575051120482385150, .5651214128035320088300220750551876379691,
// .57291975356178548306473885531886480748650, .5638766519823788546255506607929515418502,
// .57511997447138785144460371157038025558000, .5626373626373626373626373626373626373626,
// .57731536503482350219940144597785547375700, .5614035087719298245614035087719298245614,
// .57950594641464214795689713355386629700650, .5601750547045951859956236323851203501094,
// .58169173963462239562716149521293118596100, .5589519650655021834061135371179039301310,
// .58387276558098266665552955601015128195300, .5577342047930283224400871459694989106754,
// .58604904500357812846544902640744112432000, .5565217391304347826086956521739130434783,
// .58822059851708596855957011939608491957200, .5553145336225596529284164859002169197397,
// .59038744660217634674381770309992134571100, .5541125541125541125541125541125541125541,
// .59254960960667157898740242671919986605650, .5529157667386609071274298056155507559395,
// .59470710774669277576265358220553025603300, .5517241379310344827586206896551724137931,
// .59685996110779382384237123915227130055450, .5505376344086021505376344086021505376344,
// .59900818964608337768851242799428291618800, .5493562231759656652360515021459227467811,
// .60115181318933474940990890900138765573500, .5481798715203426124197002141327623126338,
// .60329085143808425240052883964381180703650, .5470085470085470085470085470085470085470,
// .60542532396671688843525771517306566238400, .5458422174840085287846481876332622601279,
// .60755525022454170969155029524699784815300, .5446808510638297872340425531914893617021,
// .60968064953685519036241657886421307921400, .5435244161358811040339702760084925690021,
// .61180154110599282990534675263916142284850, .5423728813559322033898305084745762711864,
// .61391794401237043121710712512140162289150, .5412262156448202959830866807610993657505,
// .61602987721551394351138242200249806046500, .5400843881856540084388185654008438818565,
// .61813735955507864705538167982012964785100, .5389473684210526315789473684210526315789,
// .62024040975185745772080281312810257077200, .5378151260504201680672268907563025210084,
// .62233904640877868441606324267922900617100, .5366876310272536687631027253668763102725,
// .62443328801189346144440150965237990021700, .5355648535564853556485355648535564853556,
// .62652315293135274476554741340805776417250, .5344467640918580375782881002087682672234,
// .62860865942237409420556559780379757285100, .5333333333333333333333333333333333333333,
// .63068982562619868570408243613201193511500, .5322245322245322245322245322245322245322,
// .63276666957103777644277897707070223987100, .5311203319502074688796680497925311203320,
// .63483920917301017716738442686619237065300, .5300207039337474120082815734989648033126,
// .63690746223706917739093569252872839570050, .5289256198347107438016528925619834710744,
// .63897144645792069983514238629140891134750, .5278350515463917525773195876288659793814,
// .64103117942093124081992527862894348800200, .5267489711934156378600823045267489711934,
// .64308667860302726193566513757104985415950, .5256673511293634496919917864476386036961,
// .64513796137358470073053240412264131009600, .5245901639344262295081967213114754098361,
// .64718504499530948859131740391603671014300, .5235173824130879345603271983640081799591,
// .64922794662510974195157587018911726772800, .5224489795918367346938775510204081632653,
// .65126668331495807251485530287027359008800, .5213849287169042769857433808553971486762,
// .65330127201274557080523663898929953575150, .5203252032520325203252032520325203252033,
// .65533172956312757406749369692988693714150, .5192697768762677484787018255578093306288,
// .65735807270835999727154330685152672231200, .5182186234817813765182186234817813765182,
// .65938031808912778153342060249997302889800, .5171717171717171717171717171717171717172,
// .66139848224536490484126716182800009846700, .5161290322580645161290322580645161290323,
// .66341258161706617713093692145776003599150, .5150905432595573440643863179074446680080,
// .66542263254509037562201001492212526500250, .5140562248995983935742971887550200803213,
// .66742865127195616370414654738851822912700, .5130260521042084168336673346693386773547,
// .66943065394262923906154583164607174694550, .5120000000000000000000000000000000000000,
// .67142865660530226534774556057527661323550, .5109780439121756487025948103792415169661,
// .67342267521216669923234121597488410770900, .5099601593625498007968127490039840637450,
// .67541272562017662384192817626171745359900, .5089463220675944333996023856858846918489,
// .67739882359180603188519853574689477682100, .5079365079365079365079365079365079365079,
// .67938098479579733801614338517538271844400, .5069306930693069306930693069306930693069,
// .68135922480790300781450241629499942064300, .5059288537549407114624505928853754940711,
// .68333355911162063645036823800182901322850, .5049309664694280078895463510848126232742,
// .68530400309891936760919861626462079584600, .5039370078740157480314960629921259842520,
// .68727057207096020619019327568821609020250, .5029469548133595284872298624754420432220,
// .68923328123880889251040571252815425395950, .5019607843137254901960784313725490196078,
// .69314718055994530941723212145818, 5.0e-01,
// };
// #define LOGTAB_TRANSLATE(x,h) (((x) - 1.)*ifbcLogTab[(h)+1])
// static const double ln_2 = 0.69314718055994530941723212145818;
// typedef union
// {
// struct {
// int lo;
// int hi;
// } i;
// double d;
// } DBLINT;
// template<typename dump> static void Log_32f(const float *_x, float *y, int n)
// {
// static const float shift[] = { 0, -1.f / 512 };
// static const float
// A0 = 0.3333333333333333333333333f,
// A1 = -0.5f,
// A2 = 1.f;
// #undef LOGPOLY
// #define LOGPOLY(x) (((A0*(x) + A1)*(x) + A2)*(x))
// int i = 0;
// Cv32suf buf[4];
// const int* x = (const int*)_x;
// for (; i <= n - 4; i += 4) {
// double x0, x1, x2, x3;
// double y0, y1, y2, y3;
// int h0, h1, h2, h3;
// h0 = x[i];
// h1 = x[i + 1];
// buf[0].i = (h0 & LOGTAB_MASK2_32F) | (127 << 23);
// buf[1].i = (h1 & LOGTAB_MASK2_32F) | (127 << 23);
// y0 = (((h0 >> 23) & 0xff) - 127) * ln_2;
// y1 = (((h1 >> 23) & 0xff) - 127) * ln_2;
// h0 = (h0 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// h1 = (h1 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// y0 += ifbcLogTab[h0];
// y1 += ifbcLogTab[h1];
// h2 = x[i + 2];
// h3 = x[i + 3];
// x0 = LOGTAB_TRANSLATE(buf[0].f, h0);
// x1 = LOGTAB_TRANSLATE(buf[1].f, h1);
// buf[2].i = (h2 & LOGTAB_MASK2_32F) | (127 << 23);
// buf[3].i = (h3 & LOGTAB_MASK2_32F) | (127 << 23);
// y2 = (((h2 >> 23) & 0xff) - 127) * ln_2;
// y3 = (((h3 >> 23) & 0xff) - 127) * ln_2;
// h2 = (h2 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// h3 = (h3 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// y2 += ifbcLogTab[h2];
// y3 += ifbcLogTab[h3];
// x2 = LOGTAB_TRANSLATE(buf[2].f, h2);
// x3 = LOGTAB_TRANSLATE(buf[3].f, h3);
// x0 += shift[h0 == 510];
// x1 += shift[h1 == 510];
// y0 += LOGPOLY(x0);
// y1 += LOGPOLY(x1);
// y[i] = (float)y0;
// y[i + 1] = (float)y1;
// x2 += shift[h2 == 510];
// x3 += shift[h3 == 510];
// y2 += LOGPOLY(x2);
// y3 += LOGPOLY(x3);
// y[i + 2] = (float)y2;
// y[i + 3] = (float)y3;
// }
// for (; i < n; i++) {
// int h0 = x[i];
// double y0;
// float x0;
// y0 = (((h0 >> 23) & 0xff) - 127) * ln_2;
// buf[0].i = (h0 & LOGTAB_MASK2_32F) | (127 << 23);
// h0 = (h0 >> (23 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// y0 += ifbcLogTab[h0];
// x0 = (float)LOGTAB_TRANSLATE(buf[0].f, h0);
// x0 += shift[h0 == 510];
// y0 += LOGPOLY(x0);
// y[i] = (float)y0;
// }
// }
// template<typename dump> static void Log_64f(const double *x, double *y, int n)
// {
// static const double shift[] = { 0, -1. / 512 };
// static const double
// A7 = 1.0,
// A6 = -0.5,
// A5 = 0.333333333333333314829616256247390992939472198486328125,
// A4 = -0.25,
// A3 = 0.2,
// A2 = -0.1666666666666666574148081281236954964697360992431640625,
// A1 = 0.1428571428571428769682682968777953647077083587646484375,
// A0 = -0.125;
// #undef LOGPOLY
// #define LOGPOLY(x,k) ((x)+=shift[k], xq = (x)*(x),\
// (((A0*xq + A2)*xq + A4)*xq + A6)*xq + \
// (((A1*xq + A3)*xq + A5)*xq + A7)*(x))
// int i = 0;
// DBLINT buf[4];
// DBLINT *X = (DBLINT *)x;
// for (; i <= n - 4; i += 4) {
// double xq;
// double x0, x1, x2, x3;
// double y0, y1, y2, y3;
// int h0, h1, h2, h3;
// h0 = X[i].i.lo;
// h1 = X[i + 1].i.lo;
// buf[0].i.lo = h0;
// buf[1].i.lo = h1;
// h0 = X[i].i.hi;
// h1 = X[i + 1].i.hi;
// buf[0].i.hi = (h0 & LOGTAB_MASK2) | (1023 << 20);
// buf[1].i.hi = (h1 & LOGTAB_MASK2) | (1023 << 20);
// y0 = (((h0 >> 20) & 0x7ff) - 1023) * ln_2;
// y1 = (((h1 >> 20) & 0x7ff) - 1023) * ln_2;
// h2 = X[i + 2].i.lo;
// h3 = X[i + 3].i.lo;
// buf[2].i.lo = h2;
// buf[3].i.lo = h3;
// h0 = (h0 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// h1 = (h1 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// y0 += ifbcLogTab[h0];
// y1 += ifbcLogTab[h1];
// h2 = X[i + 2].i.hi;
// h3 = X[i + 3].i.hi;
// x0 = LOGTAB_TRANSLATE(buf[0].d, h0);
// x1 = LOGTAB_TRANSLATE(buf[1].d, h1);
// buf[2].i.hi = (h2 & LOGTAB_MASK2) | (1023 << 20);
// buf[3].i.hi = (h3 & LOGTAB_MASK2) | (1023 << 20);
// y2 = (((h2 >> 20) & 0x7ff) - 1023) * ln_2;
// y3 = (((h3 >> 20) & 0x7ff) - 1023) * ln_2;
// h2 = (h2 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// h3 = (h3 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// y2 += ifbcLogTab[h2];
// y3 += ifbcLogTab[h3];
// x2 = LOGTAB_TRANSLATE(buf[2].d, h2);
// x3 = LOGTAB_TRANSLATE(buf[3].d, h3);
// y0 += LOGPOLY(x0, h0 == 510);
// y1 += LOGPOLY(x1, h1 == 510);
// y[i] = y0;
// y[i + 1] = y1;
// y2 += LOGPOLY(x2, h2 == 510);
// y3 += LOGPOLY(x3, h3 == 510);
// y[i + 2] = y2;
// y[i + 3] = y3;
// }
// for (; i < n; i++) {
// int h0 = X[i].i.hi;
// double xq;
// double x0, y0 = (((h0 >> 20) & 0x7ff) - 1023) * ln_2;
// buf[0].i.hi = (h0 & LOGTAB_MASK2) | (1023 << 20);
// buf[0].i.lo = X[i].i.lo;
// h0 = (h0 >> (20 - LOGTAB_SCALE - 1)) & LOGTAB_MASK * 2;
// y0 += ifbcLogTab[h0];
// x0 = LOGTAB_TRANSLATE(buf[0].d, h0);
// y0 += LOGPOLY(x0, h0 == 510);
// y[i] = y0;
// }
// }
// // calculates the natural logarithm of the absolute value of every element of the input array
// // \f[\texttt{dst} (I) = \fork{\log |\texttt{src}(I)|}{if \(\texttt{src}(I) \ne 0\) }{\texttt{C}}{otherwise}\f]
// // support type: float/double, multi-channels
// template <typename _Tp, int chs>
// int log(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst)
// {
// FBC_Assert(typeid(float).name() == typeid(_Tp).name() || typeid(double).name() == typeid(_Tp).name());
// if (dst.empty()) {
// dst = Mat_<_Tp, chs>(src.rows, src.cols);
// } else {
// FBC_Assert(src.size() == dst.size());
// }
// if (src.isContinuous() == false || dst.isContinuous() == false) {
// fprintf(stderr, "Error: src and dst must be continuous\n");
// return -1;
// }
// const Mat_<_Tp, chs>* arrays[] = { &src, &dst, 0 };
// uchar* ptrs[2];
// ptrs[0] = src.data;
// ptrs[1] = dst.data;
// int len = (int)(src.rows * src.cols *chs);
// if (sizeof(_Tp) == 4) { // floal
// Log_32f<dump>((const float*)ptrs[0], (float*)ptrs[1], len);
// } else { // double
// Log_64f<dump>((const double*)ptrs[0], (double*)ptrs[1], len);
// }
// return 0;
// }
// find the minimum and maximum element values and their positions
//// support type: single-channel
template<typename _Tp, int chs>
int minMaxLoc(const Mat_<_Tp, chs>& _img, double* minVal, double* maxVal = 0, Point* minLoc = 0, Point* maxLoc = 0, const Mat_<uchar, 1>& mask = Mat_<uchar, 1>())
{
FBC_Assert(chs == 1);
if (!mask.empty()) {
FBC_Assert(_img.rows == mask.rows && _img.cols == mask.cols);
}
double minVal_ = INT_MAX;
double maxVal_ = INT_MIN;
Point minLoc_ = Point(-1, -1);
Point maxLoc_ = Point(-1, -1);
if (mask.empty()) {
for (int y = 0; y < _img.rows; y++) {
_Tp* p = (_Tp*)_img.ptr(y);
for (int x = 0; x < _img.cols; x++) {
if (p[x] > maxVal_) {
maxVal_ = p[x];
maxLoc_.x = x;
maxLoc_.y = y;
}
if (p[x] < minVal_) {
minVal_ = p[x];
minLoc_.x = x;
minLoc_.y = y;
}
}
}
} else {
for (int y = 0; y < _img.rows; y++) {
_Tp* p1 = (_Tp*)_img.ptr(y);
const uchar* p2 = mask.ptr(y);
for (int x = 0; x < _img.cols; x++) {
if (p2[x] && p1[x] > maxVal_) {
maxVal_ = p1[x];
maxLoc_.x = x;
maxLoc_.y = y;
}
if (p2[x] && p1[x] < minVal_) {
minVal_ = p1[x];
minLoc_.x = x;
minLoc_.y = y;
}
}
}
}
*minVal = minVal_;
if (maxVal) *maxVal = maxVal_;
if (minLoc) *minLoc = minLoc_;
if (maxLoc) *maxLoc = maxLoc_;
return 0;
}
// Normalizes the norm or value range of an array
/* \f[\| \texttt{dst} \| _{L_p}= \texttt{alpha}\f]
(where p=Inf, 1 or 2) when normType=NORM_INF, NORM_L1, or NORM_L2, respectively; or so that
\f[\min _I \texttt{dst} (I)= \texttt{alpha} , \, \, \max _I \texttt{dst} (I)= \texttt{beta}\f] */
// support type: float/double, multi-channels
template<typename _Tp1, typename _Tp2, int chs>
int normalize(const Mat_<_Tp1, chs>& _src, Mat_<_Tp2, chs>& _dst, double a = 1, double b = 0, int norm_type = NORM_L2, const Mat_<uchar, 1>& _mask = Mat_<uchar, 1>())
{
//FBC_Assert(typeid(float).name() == typeid(_Tp).name() || typeid(double).name() == typeid(_Tp).name());
if (_dst.empty()) {
_dst = Mat_<_Tp2, chs>(_src.rows, _src.cols);
} else {
FBC_Assert(_src.size() == _dst.size());
}
double scale = 1, shift = 0;
if (norm_type == FBC_MINMAX) {
double smin = 0, smax = 0;
double dmin = MIN(a, b), dmax = MAX(a, b);
minMaxLoc(_src, &smin, &smax, 0, 0, _mask);
scale = (dmax - dmin)*(smax - smin > DBL_EPSILON ? 1. / (smax - smin) : 0);
shift = dmin - smin*scale;
} else if (norm_type == FBC_L2 || norm_type == FBC_L1 || norm_type == FBC_C) {
fprintf(stderr, "Error: normalize norm no impl\n");
FBC_Assert(0); // TODO
/*scale = norm(_src, norm_type, _mask);
scale = scale > DBL_EPSILON ? a / scale : 0.;
shift = 0;*/
} else {
FBC_Error("Unknown/unsupported norm type");
}
Scalar scalar = Scalar::all(shift);
if (_mask.empty()) {
_src.convertTo(_dst, scale, scalar);
} else {
Mat_<_Tp2, chs> tmp;
_src.convertTo(tmp, scale, scalar);
for (int y = 0; y < _dst.rows; y++) {
_Tp2* p1 = (_Tp2*)_dst.ptr(y);
const _Tp2* p2 = (_Tp2*)tmp.ptr(y);
const uchar* p3 = _mask.ptr(y);
for (int x = 0; x < _dst.cols; x++) {
if (p3[x] != 0) {
p1[x] = p2[x];
}
}
}
}
return 0;
}
} // namespace yt_tinycv
#endif // FBC_CV_CORE_MATHFUNCS_HPP_

View File

@@ -0,0 +1,851 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_MATX_HPP_
#define FBC_CV_CORE_MATX_HPP_
// reference: include/opencv2/core/matx.hpp
#ifndef __cplusplus
#error matx.hpp header must be compiled as C++
#endif
#include "fbcdef.hpp"
#include "base.hpp"
#include "interface.hpp"
#include "saturate.hpp"
namespace yt_tinycv {
////////////////////////////// Small Matrix ///////////////////////////
// Template class for small matrices whose type and size are known at compilation time
template<typename _Tp, int m, int n> class Matx {
public:
enum {
rows = m,
cols = n,
channels = rows*cols,
shortdim = (m < n ? m : n)
};
typedef _Tp value_type;
typedef Matx<_Tp, m, n> mat_type;
typedef Matx<_Tp, shortdim, 1> diag_type;
//! default constructor
Matx();
Matx(_Tp v0); //!< 1x1 matrix
Matx(_Tp v0, _Tp v1); //!< 1x2 or 2x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2); //!< 1x3 or 3x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 1x4, 2x2 or 4x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4); //!< 1x5 or 5x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5); //!< 1x6, 2x3, 3x2 or 6x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6); //!< 1x7 or 7x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 1x8, 2x4, 4x2 or 8x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 1x9, 3x3 or 9x1 matrix
explicit Matx(const _Tp* vals); //!< initialize from a plain array
static Matx all(_Tp alpha);
static Matx zeros();
static Matx ones();
static Matx eye();
static Matx diag(const diag_type& d);
//! dot product computed with the default precision
_Tp dot(const Matx<_Tp, m, n>& v) const;
//! dot product computed in double-precision arithmetics
double ddot(const Matx<_Tp, m, n>& v) const;
//! conversion to another data type
template<typename T2> operator Matx<T2, m, n>() const;
//! change the matrix shape
template<int m1, int n1> Matx<_Tp, m1, n1> reshape() const;
//! extract part of the matrix
template<int m1, int n1> Matx<_Tp, m1, n1> get_minor(int i, int j) const;
//! extract the matrix row
Matx<_Tp, 1, n> row(int i) const;
//! extract the matrix column
Matx<_Tp, m, 1> col(int i) const;
//! extract the matrix diagonal
diag_type diag() const;
//! element access
const _Tp& operator ()(int i, int j) const;
_Tp& operator ()(int i, int j);
//! 1D element access
const _Tp& operator ()(int i) const;
_Tp& operator ()(int i);
_Tp val[m*n]; //< matrix elements
};
typedef Matx<float, 1, 2> Matx12f;
typedef Matx<double, 1, 2> Matx12d;
typedef Matx<float, 1, 3> Matx13f;
typedef Matx<double, 1, 3> Matx13d;
typedef Matx<float, 1, 4> Matx14f;
typedef Matx<double, 1, 4> Matx14d;
typedef Matx<float, 1, 6> Matx16f;
typedef Matx<double, 1, 6> Matx16d;
typedef Matx<float, 2, 1> Matx21f;
typedef Matx<double, 2, 1> Matx21d;
typedef Matx<float, 3, 1> Matx31f;
typedef Matx<double, 3, 1> Matx31d;
typedef Matx<float, 4, 1> Matx41f;
typedef Matx<double, 4, 1> Matx41d;
typedef Matx<float, 6, 1> Matx61f;
typedef Matx<double, 6, 1> Matx61d;
typedef Matx<float, 2, 2> Matx22f;
typedef Matx<double, 2, 2> Matx22d;
typedef Matx<float, 2, 3> Matx23f;
typedef Matx<double, 2, 3> Matx23d;
typedef Matx<float, 3, 2> Matx32f;
typedef Matx<double, 3, 2> Matx32d;
typedef Matx<float, 3, 3> Matx33f;
typedef Matx<double, 3, 3> Matx33d;
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx()
{
for (int i = 0; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0)
{
val[0] = v0;
for (int i = 1; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1)
{
FBC_StaticAssert(channels >= 2, "Matx should have at least 2 elements.");
val[0] = v0; val[1] = v1;
for (int i = 2; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2)
{
FBC_StaticAssert(channels >= 3, "Matx should have at least 3 elements.");
val[0] = v0; val[1] = v1; val[2] = v2;
for (int i = 3; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3)
{
FBC_StaticAssert(channels >= 4, "Matx should have at least 4 elements.");
val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3;
for (int i = 4; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4)
{
FBC_StaticAssert(channels >= 5, "Matx should have at least 5 elements.");
val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3; val[4] = v4;
for (int i = 5; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5)
{
FBC_StaticAssert(channels >= 6, "Matx should have at least 6 elements.");
val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3;
val[4] = v4; val[5] = v5;
for (int i = 6; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6)
{
FBC_StaticAssert(channels >= 7, "Matx should have at least 7 elements.");
val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3;
val[4] = v4; val[5] = v5; val[6] = v6;
for (int i = 7; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7)
{
FBC_StaticAssert(channels >= 8, "Matx should have at least 8 elements.");
val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3;
val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7;
for (int i = 8; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8)
{
FBC_StaticAssert(channels >= 9, "Matx should have at least 9 elements.");
val[0] = v0; val[1] = v1; val[2] = v2; val[3] = v3;
val[4] = v4; val[5] = v5; val[6] = v6; val[7] = v7;
val[8] = v8;
for (int i = 9; i < channels; i++) val[i] = _Tp(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n>::Matx(const _Tp* values)
{
for (int i = 0; i < channels; i++) val[i] = values[i];
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n> Matx<_Tp, m, n>::all(_Tp alpha)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++) M.val[i] = alpha;
return M;
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n> Matx<_Tp, m, n>::zeros()
{
return all(0);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n> Matx<_Tp, m, n>::ones()
{
return all(1);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n> Matx<_Tp, m, n>::eye()
{
Matx<_Tp, m, n> M;
for (int i = 0; i < shortdim; i++)
M(i, i) = 1;
return M;
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, n> Matx<_Tp, m, n>::diag(const typename Matx<_Tp, m, n>::diag_type& d)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < shortdim; i++)
M(i, i) = d(i, 0);
return M;
}
template<typename _Tp, int m, int n> inline
_Tp Matx<_Tp, m, n>::dot(const Matx<_Tp, m, n>& M) const
{
_Tp s = 0;
for (int i = 0; i < channels; i++) s += val[i] * M.val[i];
return s;
}
template<typename _Tp, int m, int n> inline
double Matx<_Tp, m, n>::ddot(const Matx<_Tp, m, n>& M) const
{
double s = 0;
for (int i = 0; i < channels; i++) s += (double)val[i] * M.val[i];
return s;
}
template<typename _Tp, int m, int n> template<typename T2>
inline Matx<_Tp, m, n>::operator Matx<T2, m, n>() const
{
Matx<T2, m, n> M;
for (int i = 0; i < m*n; i++) M.val[i] = saturate_cast<T2>(val[i]);
return M;
}
template<typename _Tp, int m, int n> template<int m1, int n1> inline
Matx<_Tp, m1, n1> Matx<_Tp, m, n>::reshape() const
{
FBC_StaticAssert(m1*n1 == m*n, "Input and destnarion matrices must have the same number of elements");
return (const Matx<_Tp, m1, n1>&)*this;
}
template<typename _Tp, int m, int n>
template<int m1, int n1> inline
Matx<_Tp, m1, n1> Matx<_Tp, m, n>::get_minor(int i, int j) const
{
FBC_Assert(0 <= i && i + m1 <= m && 0 <= j && j + n1 <= n);
Matx<_Tp, m1, n1> s;
for (int di = 0; di < m1; di++)
for (int dj = 0; dj < n1; dj++)
s(di, dj) = (*this)(i + di, j + dj);
return s;
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, 1, n> Matx<_Tp, m, n>::row(int i) const
{
FBC_Assert((unsigned)i < (unsigned)m);
return Matx<_Tp, 1, n>(&val[i*n]);
}
template<typename _Tp, int m, int n> inline
Matx<_Tp, m, 1> Matx<_Tp, m, n>::col(int j) const
{
FBC_Assert((unsigned)j < (unsigned)n);
Matx<_Tp, m, 1> v;
for (int i = 0; i < m; i++)
v.val[i] = val[i*n + j];
return v;
}
template<typename _Tp, int m, int n> inline
typename Matx<_Tp, m, n>::diag_type Matx<_Tp, m, n>::diag() const
{
diag_type d;
for (int i = 0; i < shortdim; i++)
d.val[i] = val[i*n + i];
return d;
}
template<typename _Tp, int m, int n> inline
const _Tp& Matx<_Tp, m, n>::operator()(int i, int j) const
{
FBC_Assert((unsigned)i < (unsigned)m && (unsigned)j < (unsigned)n);
return this->val[i*n + j];
}
template<typename _Tp, int m, int n> inline
_Tp& Matx<_Tp, m, n>::operator ()(int i, int j)
{
FBC_Assert((unsigned)i < (unsigned)m && (unsigned)j < (unsigned)n);
return val[i*n + j];
}
template<typename _Tp, int m, int n> inline
const _Tp& Matx<_Tp, m, n>::operator ()(int i) const
{
FBC_StaticAssert(m == 1 || n == 1, "Single index indexation requires matrix to be a column or a row");
FBC_Assert((unsigned)i < (unsigned)(m + n - 1));
return val[i];
}
template<typename _Tp, int m, int n> inline
_Tp& Matx<_Tp, m, n>::operator ()(int i)
{
FBC_StaticAssert(m == 1 || n == 1, "Single index indexation requires matrix to be a column or a row");
FBC_Assert((unsigned)i < (unsigned)(m + n - 1));
return val[i];
}
template<typename _Tp, int m, int n> static inline
double norm(const Matx<_Tp, m, n>& M)
{
return std::sqrt(normL2Sqr<_Tp, double>(M.val, m*n));
}
template<typename _Tp, int m, int n> static inline
double norm(const Matx<_Tp, m, n>& M, int normType)
{
switch (normType) {
case NORM_INF:
return (double)normInf<_Tp, _Tp>(M.val, m*n);
case NORM_L1:
return (double)normL1<_Tp, _Tp>(M.val, m*n);
case NORM_L2SQR:
return (double)normL2Sqr<_Tp, _Tp>(M.val, m*n);
default:
case NORM_L2:
return std::sqrt((double)normL2Sqr<_Tp, _Tp>(M.val, m*n));
}
}
///////////////////////////// Matx out-of-class operators ////////////////////////////////
template<typename _Tp1, typename _Tp2, int m, int n> static inline
Matx<_Tp1, m, n>& operator += (Matx<_Tp1, m, n>& a, const Matx<_Tp2, m, n>& b)
{
for (int i = 0; i < m*n; i++)
a.val[i] = saturate_cast<_Tp1>(a.val[i] + b.val[i]);
return a;
}
template<typename _Tp1, typename _Tp2, int m, int n> static inline
Matx<_Tp1, m, n>& operator -= (Matx<_Tp1, m, n>& a, const Matx<_Tp2, m, n>& b)
{
for (int i = 0; i < m*n; i++)
a.val[i] = saturate_cast<_Tp1>(a.val[i] - b.val[i]);
return a;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n> operator + (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++)
M.val[i] = saturate_cast<_Tp>(a.val[i] + b.val[i]);
return M;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n> operator - (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++)
M.val[i] = saturate_cast<_Tp>(a.val[i] - b.val[i]);
return M;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n>& operator *= (Matx<_Tp, m, n>& a, int alpha)
{
for (int i = 0; i < m*n; i++)
a.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return a;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n>& operator *= (Matx<_Tp, m, n>& a, float alpha)
{
for (int i = 0; i < m*n; i++)
a.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return a;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n>& operator *= (Matx<_Tp, m, n>& a, double alpha)
{
for (int i = 0; i < m*n; i++)
a.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return a;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n> operator * (const Matx<_Tp, m, n>& a, int alpha)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++)
M.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return M;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n> operator * (const Matx<_Tp, m, n>& a, float alpha)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++)
M.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return M;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n> operator * (const Matx<_Tp, m, n>& a, double alpha)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++)
M.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return M;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n> operator * (int alpha, const Matx<_Tp, m, n>& a)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++)
M.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return M;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n> operator * (float alpha, const Matx<_Tp, m, n>& a)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++)
M.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return M;
}
template<typename _Tp, int m, int n> static inline
Matx<_Tp, m, n> operator * (double alpha, const Matx<_Tp, m, n>& a)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m*n; i++)
M.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return M;
}
template<typename _Tp, int m, int n, int l> static inline
Matx<_Tp, m, n> operator * (const Matx<_Tp, m, l>& a, const Matx<_Tp, l, n>& b)
{
Matx<_Tp, m, n> M;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
{
_Tp s = 0;
for (int k = 0; k < l; k++)
s += a(i, k) * b(k, j);
M.val[i*n + j] = s;
}
return M;
}
template<typename _Tp, int m, int n> static inline
bool operator == (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b)
{
for (int i = 0; i < m*n; i++)
if (a.val[i] != b.val[i]) return false;
return true;
}
template<typename _Tp, int m, int n> static inline
bool operator != (const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b)
{
return !(a == b);
}
///////////////////////////////////////// Vec ///////////////////////////////////
// Template class for short numerical vectors, a partial case of Matx
template<typename _Tp, int cn> class Vec : public Matx<_Tp, cn, 1> {
public:
typedef _Tp value_type;
enum {
channels = cn
};
//! default constructor
Vec();
Vec(_Tp v0); //!< 1-element vector constructor
Vec(_Tp v0, _Tp v1); //!< 2-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2); //!< 3-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 4-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4); //!< 5-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5); //!< 6-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6); //!< 7-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 8-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 9-element vector constructor
explicit Vec(const _Tp* values);
Vec(const Vec<_Tp, cn>& v);
static Vec all(_Tp alpha);
//! per-element multiplication
Vec mul(const Vec<_Tp, cn>& v) const;
//! conversion to another data type
template<typename T2> operator Vec<T2, cn>() const;
/*! element access */
const _Tp& operator [](int i) const;
_Tp& operator[](int i);
const _Tp& operator ()(int i) const;
_Tp& operator ()(int i);
};
typedef Vec<uchar, 2> Vec2b;
typedef Vec<uchar, 3> Vec3b;
typedef Vec<uchar, 4> Vec4b;
typedef Vec<short, 2> Vec2s;
typedef Vec<short, 3> Vec3s;
typedef Vec<short, 4> Vec4s;
typedef Vec<ushort, 2> Vec2w;
typedef Vec<ushort, 3> Vec3w;
typedef Vec<ushort, 4> Vec4w;
typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<int, 6> Vec6i;
typedef Vec<float, 2> Vec2f;
typedef Vec<float, 3> Vec3f;
typedef Vec<float, 4> Vec4f;
typedef Vec<float, 6> Vec6f;
typedef Vec<double, 2> Vec2d;
typedef Vec<double, 3> Vec3d;
typedef Vec<double, 4> Vec4d;
typedef Vec<double, 6> Vec6d;
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec() {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0)
: Matx<_Tp, cn, 1>(v0) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1)
: Matx<_Tp, cn, 1>(v0, v1) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2)
: Matx<_Tp, cn, 1>(v0, v1, v2) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3)
: Matx<_Tp, cn, 1>(v0, v1, v2, v3) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4)
: Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5)
: Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6)
: Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7)
: Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6, v7) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8)
: Matx<_Tp, cn, 1>(v0, v1, v2, v3, v4, v5, v6, v7, v8) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(const _Tp* values)
: Matx<_Tp, cn, 1>(values) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn>::Vec(const Vec<_Tp, cn>& m)
: Matx<_Tp, cn, 1>(m.val) {}
template<typename _Tp, int cn> inline
Vec<_Tp, cn> Vec<_Tp, cn>::all(_Tp alpha)
{
Vec v;
for (int i = 0; i < cn; i++) v.val[i] = alpha;
return v;
}
template<typename _Tp, int cn> inline
Vec<_Tp, cn> Vec<_Tp, cn>::mul(const Vec<_Tp, cn>& v) const
{
Vec<_Tp, cn> w;
for (int i = 0; i < cn; i++) w.val[i] = saturate_cast<_Tp>(this->val[i] * v.val[i]);
return w;
}
template<typename _Tp, int cn> template<typename T2> inline
Vec<_Tp, cn>::operator Vec<T2, cn>() const
{
Vec<T2, cn> v;
for (int i = 0; i < cn; i++) v.val[i] = saturate_cast<T2>(this->val[i]);
return v;
}
template<typename _Tp, int cn> inline
const _Tp& Vec<_Tp, cn>::operator [](int i) const
{
FBC_Assert((unsigned)i < (unsigned)cn);
return this->val[i];
}
template<typename _Tp, int cn> inline
_Tp& Vec<_Tp, cn>::operator [](int i)
{
FBC_Assert((unsigned)i < (unsigned)cn);
return this->val[i];
}
template<typename _Tp, int cn> inline
const _Tp& Vec<_Tp, cn>::operator ()(int i) const
{
FBC_Assert((unsigned)i < (unsigned)cn);
return this->val[i];
}
template<typename _Tp, int cn> inline
_Tp& Vec<_Tp, cn>::operator ()(int i)
{
FBC_Assert((unsigned)i < (unsigned)cn);
return this->val[i];
}
////////////////////////////// Vec out-of-class operators ////////////////////////////////
template<typename _Tp1, typename _Tp2, int cn> static inline
Vec<_Tp1, cn>& operator += (Vec<_Tp1, cn>& a, const Vec<_Tp2, cn>& b)
{
for (int i = 0; i < cn; i++)
a.val[i] = saturate_cast<_Tp1>(a.val[i] + b.val[i]);
return a;
}
template<typename _Tp1, typename _Tp2, int cn> static inline
Vec<_Tp1, cn>& operator -= (Vec<_Tp1, cn>& a, const Vec<_Tp2, cn>& b)
{
for (int i = 0; i < cn; i++)
a.val[i] = saturate_cast<_Tp1>(a.val[i] - b.val[i]);
return a;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator + (const Vec<_Tp, cn>& a, const Vec<_Tp, cn>& b)
{
Vec<_Tp, cn> v;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] + b.val[i]);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator - (const Vec<_Tp, cn>& a, const Vec<_Tp, cn>& b)
{
Vec<_Tp, cn> v;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] - b.val[i]);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn>& operator *= (Vec<_Tp, cn>& a, int alpha)
{
for (int i = 0; i < cn; i++)
a[i] = saturate_cast<_Tp>(a[i] * alpha);
return a;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn>& operator *= (Vec<_Tp, cn>& a, float alpha)
{
for (int i = 0; i < cn; i++)
a[i] = saturate_cast<_Tp>(a[i] * alpha);
return a;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn>& operator *= (Vec<_Tp, cn>& a, double alpha)
{
for (int i = 0; i < cn; i++)
a[i] = saturate_cast<_Tp>(a[i] * alpha);
return a;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn>& operator /= (Vec<_Tp, cn>& a, int alpha)
{
double ialpha = 1. / alpha;
for (int i = 0; i < cn; i++)
a[i] = saturate_cast<_Tp>(a[i] * ialpha);
return a;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn>& operator /= (Vec<_Tp, cn>& a, float alpha)
{
float ialpha = 1.f / alpha;
for (int i = 0; i < cn; i++)
a[i] = saturate_cast<_Tp>(a[i] * ialpha);
return a;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn>& operator /= (Vec<_Tp, cn>& a, double alpha)
{
double ialpha = 1. / alpha;
for (int i = 0; i < cn; i++)
a[i] = saturate_cast<_Tp>(a[i] * ialpha);
return a;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator * (const Vec<_Tp, cn>& a, int alpha)
{
Vec<_Tp, cn> v;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator * (int alpha, const Vec<_Tp, cn>& a)
{
Vec<_Tp, cn> v;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator * (const Vec<_Tp, cn>& a, float alpha)
{
Vec<_Tp, cn> v;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator * (float alpha, const Vec<_Tp, cn>& a)
{
Vec<_Tp, cn> v;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator * (const Vec<_Tp, cn>& a, double alpha)
{
Vec<_Tp, cn> v;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator * (double alpha, const Vec<_Tp, cn>& a)
{
Vec<_Tp, cn> v;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * alpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator / (const Vec<_Tp, cn>& a, int alpha)
{
Vec<_Tp, cn> v;
double ialpha = 1. / alpha;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * ialpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator / (const Vec<_Tp, cn>& a, float alpha)
{
Vec<_Tp, cn> v;
float ialpha = 1.f / alpha;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * ialpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator / (const Vec<_Tp, cn>& a, double alpha)
{
Vec<_Tp, cn> v;
double ialpha = 1. / alpha;
for (int i = 0; i < cn; i++)
v.val[i] = saturate_cast<_Tp>(a.val[i] * ialpha);
return v;
}
template<typename _Tp, int cn> static inline
Vec<_Tp, cn> operator - (const Vec<_Tp, cn>& a)
{
Vec<_Tp, cn> t;
for (int i = 0; i < cn; i++) t.val[i] = saturate_cast<_Tp>(-a.val[i]);
return t;
}
} //yt_tinycv
#endif //FBC_CV_CORE_MATX_HPP_

View File

@@ -0,0 +1,470 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_RESIZE_HPP_
#define FBC_CV_RESIZE_HPP_
/* reference: imgproc/include/opencv2/imgproc.hpp
imgproc/src/imgwarp.cpp
*/
#include <typeinfo>
#include "mat.hpp"
#include "base.hpp"
#include "saturate.hpp"
#include "utility.hpp"
#include "imgproc.hpp"
namespace yt_tinycv {
static const int MAX_ESIZE = 16;
// interpolation formulas and tables
const int INTER_RESIZE_COEF_BITS = 11;
const int INTER_RESIZE_COEF_SCALE = 1 << INTER_RESIZE_COEF_BITS;
template<typename _Tp, int chs> static int resize_nearest(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst);
template<typename _Tp, int chs> static int resize_linear(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst);
// resize the image src down to or up to the specified size
// support type: uchar/float
template<typename _Tp, int chs>
int resize(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst, int interpolation = INTER_LINEAR)
{
FBC_Assert((interpolation >= 0) && (interpolation < 5));
FBC_Assert((src.rows >= 4 && src.cols >= 4) && (dst.rows >= 4 && dst.cols >= 4));
FBC_Assert(typeid(uchar).name() == typeid(_Tp).name() || typeid(float).name() == typeid(_Tp).name()); // uchar || float
Size ssize = src.size();
Size dsize = dst.size();
if (dsize == ssize) {
// Source and destination are of same size. Use simple copy.
src.copyTo(dst);
return 0;
}
switch (interpolation) {
case 0: {
resize_nearest(src, dst);
break;
}
case 1: {
resize_linear(src, dst);
break;
}
default:
return -1;
}
return 0;
}
template<typename ST, typename DT> struct Cast
{
typedef ST type1;
typedef DT rtype;
DT operator()(ST val) const { return saturate_cast<DT>(val); }
};
template<typename ST, typename DT, int bits> struct FixedPtCast
{
typedef ST type1;
typedef DT rtype;
enum { SHIFT = bits, DELTA = 1 << (bits - 1) };
DT operator()(ST val) const { return saturate_cast<DT>((val + DELTA) >> SHIFT); }
};
template<typename type>
static type clip(type x, type a, type b)
{
return x >= a ? (x < b ? x : b - 1) : a;
}
template<typename T, typename WT, typename AT>
struct HResizeLinear
{
typedef T value_type;
typedef WT buf_type;
typedef AT alpha_type;
void operator()(const T** src, WT** dst, int count,
const int* xofs, const AT* alpha,
int swidth, int dwidth, int cn, int xmin, int xmax, int ONE) const
{
int dx, k;
int dx0 = 0;
for (k = 0; k <= count - 2; k++) {
const T *S0 = src[k], *S1 = src[k + 1];
WT *D0 = dst[k], *D1 = dst[k + 1];
for (dx = dx0; dx < xmax; dx++) {
int sx = xofs[dx];
WT a0 = alpha[dx * 2], a1 = alpha[dx * 2 + 1];
WT t0 = S0[sx] * a0 + S0[sx + cn] * a1;
WT t1 = S1[sx] * a0 + S1[sx + cn] * a1;
D0[dx] = t0; D1[dx] = t1;
}
for (; dx < dwidth; dx++) {
int sx = xofs[dx];
D0[dx] = WT(S0[sx] * ONE); D1[dx] = WT(S1[sx] * ONE);
}
}
for (; k < count; k++) {
const T *S = src[k];
WT *D = dst[k];
for (dx = 0; dx < xmax; dx++) {
int sx = xofs[dx];
D[dx] = S[sx] * alpha[dx * 2] + S[sx + cn] * alpha[dx * 2 + 1];
}
for (; dx < dwidth; dx++) {
D[dx] = WT(S[xofs[dx]] * ONE);
}
}
}
};
template<typename T, typename WT, typename AT, class CastOp>
struct VResizeLinear
{
typedef T value_type;
typedef WT buf_type;
typedef AT alpha_type;
void operator()(const WT** src, T* dst, const AT* beta, int width) const
{
WT b0 = beta[0], b1 = beta[1];
const WT *S0 = src[0], *S1 = src[1];
CastOp castOp;
int x = 0;
for (; x <= width - 4; x += 4) {
WT t0, t1;
t0 = S0[x] * b0 + S1[x] * b1;
t1 = S0[x + 1] * b0 + S1[x + 1] * b1;
dst[x] = castOp(t0); dst[x + 1] = castOp(t1);
t0 = S0[x + 2] * b0 + S1[x + 2] * b1;
t1 = S0[x + 3] * b0 + S1[x + 3] * b1;
dst[x + 2] = castOp(t0); dst[x + 3] = castOp(t1);
}
for (; x < width; x++) {
dst[x] = castOp(S0[x] * b0 + S1[x] * b1);
}
}
};
template<>
struct VResizeLinear<uchar, int, short, FixedPtCast<int, uchar, INTER_RESIZE_COEF_BITS * 2>>
{
typedef uchar value_type;
typedef int buf_type;
typedef short alpha_type;
void operator()(const buf_type** src, value_type* dst, const alpha_type* beta, int width) const
{
alpha_type b0 = beta[0], b1 = beta[1];
const buf_type *S0 = src[0], *S1 = src[1];
int x = 0;
for (; x <= width - 4; x += 4) {
dst[x + 0] = uchar((((b0 * (S0[x + 0] >> 4)) >> 16) + ((b1 * (S1[x + 0] >> 4)) >> 16) + 2) >> 2);
dst[x + 1] = uchar((((b0 * (S0[x + 1] >> 4)) >> 16) + ((b1 * (S1[x + 1] >> 4)) >> 16) + 2) >> 2);
dst[x + 2] = uchar((((b0 * (S0[x + 2] >> 4)) >> 16) + ((b1 * (S1[x + 2] >> 4)) >> 16) + 2) >> 2);
dst[x + 3] = uchar((((b0 * (S0[x + 3] >> 4)) >> 16) + ((b1 * (S1[x + 3] >> 4)) >> 16) + 2) >> 2);
}
for (; x < width; x++) {
dst[x] = uchar((((b0 * (S0[x] >> 4)) >> 16) + ((b1 * (S1[x] >> 4)) >> 16) + 2) >> 2);
}
}
};
template<typename _Tp, typename value_type, typename buf_type, typename alpha_type, int chs>
static void resizeGeneric_Linear(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst,
const int* xofs, const void* _alpha, const int* yofs, const void* _beta, int xmin, int xmax, int ksize, int ONE)
{
Size ssize = src.size(), dsize = dst.size();
int dy, cn = src.channels;
ssize.width *= cn;
dsize.width *= cn;
xmin *= cn;
xmax *= cn;
// image resize is a separable operation. In case of not too strong
Range range(0, dsize.height);
int bufstep = (int)alignSize(dsize.width, 16);
AutoBuffer<buf_type> _buffer(bufstep*ksize);
const value_type* srows[MAX_ESIZE] = { 0 };
buf_type* rows[MAX_ESIZE] = { 0 };
int prev_sy[MAX_ESIZE];
for (int k = 0; k < ksize; k++) {
prev_sy[k] = -1;
rows[k] = (buf_type*)_buffer + bufstep*k;
}
const alpha_type* beta = (const alpha_type*)_beta + ksize * range.start;
HResizeLinear<value_type, buf_type, alpha_type> hresize;
VResizeLinear<value_type, buf_type, alpha_type, FixedPtCast<int, uchar, INTER_RESIZE_COEF_BITS * 2>> vresize1;
VResizeLinear<value_type, buf_type, alpha_type, Cast<float, float>> vresize2;
for (dy = range.start; dy < range.end; dy++, beta += ksize) {
int sy0 = yofs[dy], k0 = ksize, k1 = 0, ksize2 = ksize / 2;
for (int k = 0; k < ksize; k++) {
int sy = clip<int>(sy0 - ksize2 + 1 + k, 0, ssize.height);
for (k1 = std::max(k1, k); k1 < ksize; k1++) {
if (sy == prev_sy[k1]) { // if the sy-th row has been computed already, reuse it.
if (k1 > k) {
memcpy(rows[k], rows[k1], bufstep*sizeof(rows[0][0]));
}
break;
}
}
if (k1 == ksize) {
k0 = std::min(k0, k); // remember the first row that needs to be computed
}
srows[k] = (const value_type*)src.ptr(sy);
prev_sy[k] = sy;
}
if (k0 < ksize) {
hresize((const value_type**)(srows + k0), (buf_type**)(rows + k0), ksize - k0, xofs, (const alpha_type*)(_alpha),
ssize.width, dsize.width, cn, xmin, xmax, ONE);
}
if (sizeof(_Tp) == 1) { // uchar
vresize1((const buf_type**)rows, (value_type*)(dst.data + dst.step*dy), beta, dsize.width);
} else { // float
vresize2((const buf_type**)rows, (value_type*)(dst.data + dst.step*dy), beta, dsize.width);
}
}
}
template<typename _Tp, int chs>
static int resize_nearest(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst)
{
Size ssize = src.size();
Size dsize = dst.size();
double fx = (double)dsize.width / ssize.width;
double fy = (double)dsize.height / ssize.height;
AutoBuffer<int> _x_ofs(dsize.width);
int* x_ofs = _x_ofs;
int pix_size = (int)src.elemSize();
int pix_size4 = (int)(pix_size / sizeof(int));
double ifx = 1. / fx, ify = 1. / fy;
for (int x = 0; x < dsize.width; x++) {
int sx = fbcFloor(x*ifx);
x_ofs[x] = std::min(sx, ssize.width - 1)*pix_size;
}
Range range(0, dsize.height);
int x, y;
for (y = range.start; y < range.end; y++) {
uchar* D = dst.data + dst.step*y;
int sy = std::min(fbcFloor(y*ify), ssize.height - 1);
const uchar* S = src.ptr(sy);
switch (pix_size) {
case 1:
for (x = 0; x <= dsize.width - 2; x += 2) {
uchar t0 = S[x_ofs[x]];
uchar t1 = S[x_ofs[x + 1]];
D[x] = t0;
D[x + 1] = t1;
}
for (; x < dsize.width; x++) {
D[x] = S[x_ofs[x]];
}
break;
case 2:
for (x = 0; x < dsize.width; x++) {
*(ushort*)(D + x * 2) = *(ushort*)(S + x_ofs[x]);
}
break;
case 3:
for (x = 0; x < dsize.width; x++, D += 3) {
const uchar* _tS = S + x_ofs[x];
D[0] = _tS[0]; D[1] = _tS[1]; D[2] = _tS[2];
}
break;
case 4:
for (x = 0; x < dsize.width; x++) {
*(int*)(D + x * 4) = *(int*)(S + x_ofs[x]);
}
break;
case 6:
for (x = 0; x < dsize.width; x++, D += 6) {
const ushort* _tS = (const ushort*)(S + x_ofs[x]);
ushort* _tD = (ushort*)D;
_tD[0] = _tS[0]; _tD[1] = _tS[1]; _tD[2] = _tS[2];
}
break;
case 8:
for (x = 0; x < dsize.width; x++, D += 8) {
const int* _tS = (const int*)(S + x_ofs[x]);
int* _tD = (int*)D;
_tD[0] = _tS[0]; _tD[1] = _tS[1];
}
break;
case 12:
for (x = 0; x < dsize.width; x++, D += 12) {
const int* _tS = (const int*)(S + x_ofs[x]);
int* _tD = (int*)D;
_tD[0] = _tS[0]; _tD[1] = _tS[1]; _tD[2] = _tS[2];
}
break;
default:
for (x = 0; x < dsize.width; x++, D += pix_size) {
const int* _tS = (const int*)(S + x_ofs[x]);
int* _tD = (int*)D;
for (int k = 0; k < pix_size4; k++)
_tD[k] = _tS[k];
}
}
}
return 0;
}
template<typename _Tp, int chs>
static int resize_linear(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst)
{
Size ssize = src.size();
Size dsize = dst.size();
double inv_scale_x = (double)dsize.width / ssize.width;
double inv_scale_y = (double)dsize.height / ssize.height;
double scale_x = 1. / inv_scale_x, scale_y = 1. / inv_scale_y;
int iscale_x = saturate_cast<int>(scale_x);
int iscale_y = saturate_cast<int>(scale_y);
bool is_area_fast = std::abs(scale_x - iscale_x) < DBL_EPSILON && std::abs(scale_y - iscale_y) < DBL_EPSILON;
// in case of scale_x && scale_y is equal to 2
// INTER_AREA (fast) also is equal to INTER_LINEAR
// if (is_area_fast && iscale_x == 2 && iscale_y == 2) {
// resize_area(src, dst);
// return 0;
// }
int cn = dst.channels;
int k, sx, sy, dx, dy;
int xmin = 0, xmax = dsize.width, width = dsize.width*cn;
bool fixpt = sizeof(_Tp) == 1 ? true : false;
float fx, fy;
int ksize = 2, ksize2;
ksize2 = ksize / 2;
AutoBuffer<uchar> _buffer((width + dsize.height)*(sizeof(int) + sizeof(float)*ksize));
int* xofs = (int*)(uchar*)_buffer;
int* yofs = xofs + width;
float* alpha = (float*)(yofs + dsize.height);
short* ialpha = (short*)alpha;
float* beta = alpha + width*ksize;
short* ibeta = ialpha + width*ksize;
float cbuf[MAX_ESIZE];
for (dx = 0; dx < dsize.width; dx++) {
fx = (float)((dx + 0.5)*scale_x - 0.5);
sx = fbcFloor(fx);
fx -= sx;
if (sx < ksize2 - 1) {
xmin = dx + 1;
if (sx < 0) {
fx = 0, sx = 0;
}
}
if (sx + ksize2 >= ssize.width) {
xmax = std::min(xmax, dx);
if (sx >= ssize.width - 1) {
fx = 0, sx = ssize.width - 1;
}
}
for (k = 0, sx *= cn; k < cn; k++) {
xofs[dx*cn + k] = sx + k;
}
cbuf[0] = 1.f - fx;
cbuf[1] = fx;
if (fixpt) {
for (k = 0; k < ksize; k++) {
ialpha[dx*cn*ksize + k] = saturate_cast<short>(cbuf[k] * INTER_RESIZE_COEF_SCALE);
}
for (; k < cn*ksize; k++) {
ialpha[dx*cn*ksize + k] = ialpha[dx*cn*ksize + k - ksize];
}
} else {
for (k = 0; k < ksize; k++) {
alpha[dx*cn*ksize + k] = cbuf[k];
}
for (; k < cn*ksize; k++) {
alpha[dx*cn*ksize + k] = alpha[dx*cn*ksize + k - ksize];
}
}
}
for (dy = 0; dy < dsize.height; dy++) {
fy = (float)((dy + 0.5)*scale_y - 0.5);
sy = fbcFloor(fy);
fy -= sy;
yofs[dy] = sy;
cbuf[0] = 1.f - fy;
cbuf[1] = fy;
if (fixpt) {
for (k = 0; k < ksize; k++) {
ibeta[dy*ksize + k] = saturate_cast<short>(cbuf[k] * INTER_RESIZE_COEF_SCALE);
}
} else {
for (k = 0; k < ksize; k++) {
beta[dy*ksize + k] = cbuf[k];
}
}
}
if (sizeof(_Tp) == 1) { // uchar
typedef uchar value_type; // HResizeLinear/VResizeLinear
typedef int buf_type;
typedef short alpha_type;
int ONE = INTER_RESIZE_COEF_SCALE;
resizeGeneric_Linear<_Tp, value_type, buf_type, alpha_type, chs>(src, dst,
xofs, fixpt ? (void*)ialpha : (void*)alpha, yofs, fixpt ? (void*)ibeta : (void*)beta, xmin, xmax, ksize, ONE);
} else if (sizeof(_Tp) == 4) { // float
typedef float value_type; // HResizeLinear/VResizeLinear
typedef float buf_type;
typedef float alpha_type;
int ONE = 1;
resizeGeneric_Linear<_Tp, value_type, buf_type, alpha_type, chs>(src, dst,
xofs, fixpt ? (void*)ialpha : (void*)alpha, yofs, fixpt ? (void*)ibeta : (void*)beta, xmin, xmax, ksize, ONE);
} else {
fprintf(stderr, "not support type\n");
return -1;
}
return 0;
}
} // namespace yt_tinycv
#endif // FBC_CV_RESIZE_HPP_

View File

@@ -0,0 +1,64 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_SATURATE_HPP_
#define FBC_CV_CORE_SATURATE_HPP_
// reference: include/opencv2/core/saturate.hpp
#include <algorithm>
#include <limits.h>
#include "fbcdef.hpp"
#include "interface.hpp"
#include "fast_math.hpp"
namespace yt_tinycv
{
template<typename _Tp> static inline _Tp saturate_cast(uchar v) { return _Tp(v); }
template<typename _Tp> static inline _Tp saturate_cast(schar v) { return _Tp(v); }
template<typename _Tp> static inline _Tp saturate_cast(ushort v) { return _Tp(v); }
template<typename _Tp> static inline _Tp saturate_cast(short v) { return _Tp(v); }
template<typename _Tp> static inline _Tp saturate_cast(unsigned int v) { return _Tp(v); }
template<typename _Tp> static inline _Tp saturate_cast(int v) { return _Tp(v); }
template<typename _Tp> static inline _Tp saturate_cast(float v) { return _Tp(v); }
template<typename _Tp> static inline _Tp saturate_cast(double v) { return _Tp(v); }
template<> inline uchar saturate_cast<uchar>(schar v) { return (uchar)std::max((int)v, 0); }
template<> inline uchar saturate_cast<uchar>(ushort v) { return (uchar)std::min((unsigned)v, (unsigned)UCHAR_MAX); }
template<> inline uchar saturate_cast<uchar>(int v) { return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); }
template<> inline uchar saturate_cast<uchar>(short v) { return saturate_cast<uchar>((int)v); }
template<> inline uchar saturate_cast<uchar>(unsigned int v) { return (uchar)std::min(v, (unsigned)UCHAR_MAX); }
template<> inline uchar saturate_cast<uchar>(float v) { int iv = fbcRound(v); return saturate_cast<uchar>(iv); }
template<> inline uchar saturate_cast<uchar>(double v) { int iv = fbcRound(v); return saturate_cast<uchar>(iv); }
template<> inline schar saturate_cast<schar>(uchar v) { return (schar)std::min((int)v, SCHAR_MAX); }
template<> inline schar saturate_cast<schar>(ushort v) { return (schar)std::min((unsigned)v, (unsigned)SCHAR_MAX); }
template<> inline schar saturate_cast<schar>(int v) { return (schar)((unsigned)(v-SCHAR_MIN) <= (unsigned)UCHAR_MAX ? v : v > 0 ? SCHAR_MAX : SCHAR_MIN); }
template<> inline schar saturate_cast<schar>(short v) { return saturate_cast<schar>((int)v); }
template<> inline schar saturate_cast<schar>(unsigned v) { return (schar)std::min(v, (unsigned)SCHAR_MAX); }
template<> inline schar saturate_cast<schar>(float v) { int iv = fbcRound(v); return saturate_cast<schar>(iv); }
template<> inline schar saturate_cast<schar>(double v) { int iv = fbcRound(v); return saturate_cast<schar>(iv); }
template<> inline ushort saturate_cast<ushort>(schar v) { return (ushort)std::max((int)v, 0); }
template<> inline ushort saturate_cast<ushort>(short v) { return (ushort)std::max((int)v, 0); }
template<> inline ushort saturate_cast<ushort>(int v) { return (ushort)((unsigned)v <= (unsigned)USHRT_MAX ? v : v > 0 ? USHRT_MAX : 0); }
template<> inline ushort saturate_cast<ushort>(unsigned v) { return (ushort)std::min(v, (unsigned)USHRT_MAX); }
template<> inline ushort saturate_cast<ushort>(float v) { int iv = fbcRound(v); return saturate_cast<ushort>(iv); }
template<> inline ushort saturate_cast<ushort>(double v) { int iv = fbcRound(v); return saturate_cast<ushort>(iv); }
template<> inline short saturate_cast<short>(ushort v) { return (short)std::min((int)v, SHRT_MAX); }
template<> inline short saturate_cast<short>(int v) { return (short)((unsigned)(v - SHRT_MIN) <= (unsigned)USHRT_MAX ? v : v > 0 ? SHRT_MAX : SHRT_MIN); }
template<> inline short saturate_cast<short>(unsigned v) { return (short)std::min(v, (unsigned)SHRT_MAX); }
template<> inline short saturate_cast<short>(float v) { int iv = fbcRound(v); return saturate_cast<short>(iv); }
template<> inline short saturate_cast<short>(double v) { int iv = fbcRound(v); return saturate_cast<short>(iv); }
template<> inline int saturate_cast<int>(float v) { return fbcRound(v); }
template<> inline int saturate_cast<int>(double v) { return fbcRound(v); }
template<> inline unsigned saturate_cast<unsigned>(float v) { return fbcRound(v); }
template<> inline unsigned saturate_cast<unsigned>(double v) { return fbcRound(v); }
} // yt_tinycv
#endif // FBC_CV_CORE_SATURATE_HPP_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,189 @@
// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com
#ifndef FBC_CV_CORE_UTILITY_HPP_
#define FBC_CV_CORE_UTILITY_HPP_
// reference: include/opencv2/core/utility.hpp
#ifndef __cplusplus
#error utility.hpp header must be compiled as C++
#endif
#include "fbcdef.hpp"
#include "base.hpp"
namespace yt_tinycv {
// The function returns the aligned pointer of the same type as the input pointer
template<typename _Tp> static inline _Tp* alignPtr(_Tp* ptr, int n = (int)sizeof(_Tp))
{
return (_Tp*)(((size_t)ptr + n - 1) & -n);
}
// The function returns the minimum number that is greater or equal to sz and is divisible by n
static inline size_t alignSize(size_t sz, int n)
{
FBC_Assert((n & (n - 1)) == 0); // n is a power of 2
return (sz + n - 1) & -n;
}
// Automatically Allocated Buffer Class
// The class is used for temporary buffers in functions and methods.
template<typename _Tp, size_t fixed_size = 1024 / sizeof(_Tp) + 8> class AutoBuffer {
public:
typedef _Tp value_type;
// the default constructor
AutoBuffer();
// constructor taking the real buffer size
AutoBuffer(size_t _size);
// the copy constructor
AutoBuffer(const AutoBuffer<_Tp, fixed_size>& buf);
// the assignment operator
AutoBuffer<_Tp, fixed_size>& operator = (const AutoBuffer<_Tp, fixed_size>& buf);
// destructor. calls deallocate()
~AutoBuffer();
// allocates the new buffer of size _size. if the _size is small enough, stack-allocated buffer is used
void allocate(size_t _size);
// deallocates the buffer if it was dynamically allocated
void deallocate();
// resizes the buffer and preserves the content
void resize(size_t _size);
// returns the current buffer size
size_t size() const;
// returns pointer to the real buffer, stack-allocated or head-allocated
operator _Tp* ();
// returns read-only pointer to the real buffer, stack-allocated or head-allocated
operator const _Tp* () const;
protected:
// pointer to the real buffer, can point to buf if the buffer is small enough
_Tp* ptr;
// size of the real buffer
size_t sz;
//! pre-allocated buffer. At least 1 element to confirm C++ standard reqirements
_Tp buf[(fixed_size > 0) ? fixed_size : 1];
};
template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::AutoBuffer()
{
ptr = buf;
sz = fixed_size;
}
template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::AutoBuffer(size_t _size)
{
ptr = buf;
sz = fixed_size;
allocate(_size);
}
template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::AutoBuffer(const AutoBuffer<_Tp, fixed_size>& abuf)
{
ptr = buf;
sz = fixed_size;
allocate(abuf.size());
for (size_t i = 0; i < sz; i++) {
ptr[i] = abuf.ptr[i];
}
}
template<typename _Tp, size_t fixed_size> inline AutoBuffer<_Tp, fixed_size>&
AutoBuffer<_Tp, fixed_size>::operator = (const AutoBuffer<_Tp, fixed_size>& abuf)
{
if (this != &abuf) {
deallocate();
allocate(abuf.size());
for (size_t i = 0; i < sz; i++) {
ptr[i] = abuf.ptr[i];
}
}
return *this;
}
template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::~AutoBuffer()
{
deallocate();
}
template<typename _Tp, size_t fixed_size> inline void
AutoBuffer<_Tp, fixed_size>::allocate(size_t _size)
{
if (_size <= sz) {
sz = _size;
return;
}
deallocate();
if (_size > fixed_size) {
ptr = new _Tp[_size];
sz = _size;
}
}
template<typename _Tp, size_t fixed_size> inline void
AutoBuffer<_Tp, fixed_size>::deallocate()
{
if (ptr != buf) {
delete[] ptr;
ptr = buf;
sz = fixed_size;
}
}
template<typename _Tp, size_t fixed_size> inline void
AutoBuffer<_Tp, fixed_size>::resize(size_t _size)
{
if (_size <= sz) {
sz = _size;
return;
}
size_t i, prevsize = sz, minsize = MIN(prevsize, _size);
_Tp* prevptr = ptr;
ptr = _size > fixed_size ? new _Tp[_size] : buf;
sz = _size;
if (ptr != prevptr) {
for (i = 0; i < minsize; i++) {
ptr[i] = prevptr[i];
}
}
for (i = prevsize; i < _size; i++) {
ptr[i] = _Tp();
}
if (prevptr != buf) {
delete[] prevptr;
}
}
template<typename _Tp, size_t fixed_size> inline size_t
AutoBuffer<_Tp, fixed_size>::size() const
{
return sz;
}
template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::operator _Tp* ()
{
return ptr;
}
template<typename _Tp, size_t fixed_size> inline
AutoBuffer<_Tp, fixed_size>::operator const _Tp* () const
{
return ptr;
}
} // yt_tinycv
#endif // FBC_CV_CORE_UTILITY_HPP_

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>YTCv</string>
<key>CFBundleIdentifier</key>
<string>com.tencent.youtu.cv</string>
<key>CFBundleExecutable</key>
<string>YTCv</string>
<key>CFBundleVersion</key>
<string>v0.0.7-2-g3bdc755</string>
<key>CFBundleShortVersionString</key>
<string>v0.0.7-2-g3bdc755</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
</dict>
</plist>

View File

@@ -0,0 +1,43 @@
#ifndef _YT_COMMON_H_
#define _YT_COMMON_H_
typedef void *yt_handle;
typedef enum {
YT_IMG_BGR_8UC3,
YT_IMG_RGB_8UC3,
YT_IMG_GRAY_8UC1,
YT_IMG_DEPTH_16UC1,
YT_IMG_BGRA_8UC4,
YT_IMG_RGBA_8UC4,
YT_IMG_NV21,
YT_IMG_NV12,
YT_IMG_UNKNOWN,
} yt_img_type;
typedef struct yt_image_t {
unsigned char *data;
int width;
int height;
yt_img_type type;
} yt_image;
typedef struct yt_rect_t {
int x;
int y;
int width;
int height;
} yt_rect;
typedef struct yt_pointf_t {
float x;
float y;
} yt_pointf;
typedef struct yt_point3f_t {
float x;
float y;
float z;
} yt_point3f;
#endif // _YT_COMMON_H_

View File

@@ -0,0 +1,74 @@
#ifndef _YT_DEFINES_H_
#define _YT_DEFINES_H_
// ----------------------------------------------------------------------------
// YouTu for cross platform defines export c api.
// windows @see: http://geoffair.net/ms/declspec.htm
// ----------------------------------------------------------------------------
#if (defined(WIN32) || defined(WIN64))
#ifdef YT_EXPORT
#define YT_PUBLIC_ __declspec(dllexport)
#else
#define YT_PUBLIC_ __declspec(dllimport)
#endif
#else
#ifdef YT_EXPORT
#define YT_PUBLIC_ __attribute__((visibility("default")))
#else
#define YT_PUBLIC_
#endif
#endif
#ifdef __cplusplus
#define YT_PUBLIC extern "C" YT_PUBLIC_
#else
#define YT_PUBLIC YT_PUBLIC_
#endif
// ----------------------------------------------------------------------------
// YouTu error code defines
// ----------------------------------------------------------------------------
#define YT_SUCCESS 0
#define YT_ERROR -1
// init error code: [-10, -99]
#define YT_ERROR_OPEN_FILE -10
#define YT_ERROR_READ_FILE -11
#define YT_ERROR_FILE_EMPTY -12
#define YT_ERROR_RPN_NET_INIT -20
#define YT_ERROR_RPN_NET_NOT_INIT -21
#define YT_ERROR_RPN_INST_INIT -22
#define YT_ERROR_RPN_INST_NOT_INIT -23
#define YT_ERROR_RPN_FORWARD -24
#define YT_ERROR_TNN_MEMORY_ALLOC_FAILED -25
#define YT_ERROR_INVALID_INSTANCE -99
// arguments error code: [-100, -999]
#define YT_ERROR_MUST_NOT_NULL -100
#define YT_ERROR_IMAGE_TYPE -110
#define YT_ERROR_IMAGE_DATA -111
#define YT_ERROR_FACE_POINTS -120
#define YT_ERROR_FACE_FIVE_POINTS -121
#define YT_ERROR_FACE_NINETY_POINTS -122
#define YT_ERROR_FACE_RECT -123
#define YT_ERROR_INVALID_MODEL_VERSION -130
#define YT_ERROR_MODEL_THRESHOLDS_SIZE -131
// auth error code
#define YT_ERROR_AUTH_FAILED -1024
// ----------------------------------------------------------------------------
// YouTu common code defines
// ----------------------------------------------------------------------------
#define YT_FACE_FEATURE_SIZE_512 512
#define YT_FACE_FEATURE_SIZE_1024 1024
#define YT_FACE_FIVE_POINTS_SIZE 5
#define YT_FACE_NINETY_POINTS_SIZE 90
#endif // _YT_DEFINES_H_

View File

@@ -0,0 +1,224 @@
#ifndef _YT_FACE_ALIGNMENT_TINY_H_
#define _YT_FACE_ALIGNMENT_TINY_H_
#include "yt_common.h"
#include "yt_defines.h"
// 人脸配准模式
#define YT_FACE_ALIGNMENT_MODE_SPARSE 1
#define YT_FACE_ALIGNMENT_MODE_DENSE 2
// 人脸追踪过程,置信度不满足阈值要求时的失败结果
#define YT_ERROR_FACE_ALIGNMENT_TRACK_CONF -10000
// 人脸稠密点点位数量
// 左眉毛,右眉毛,左眼,右眼
// 鼻子,嘴巴,轮廓,前额,瞳孔
#define YT_DENSE_EYEBROW_POINTS_NUM 16
#define YT_DENSE_EYE_POINTS_NUM 24
#define YT_DENSE_NOSE_POINTS_NUM 22
#define YT_DENSE_MOUTH_POINTS_NUM 72
#define YT_DENSE_PROFILE_POINTS_NUM 41
#define YT_DENSE_FOREHEAD_POINTS_NUM 7
#define YT_DENSE_PUPIL_POINTS_NUM 34
typedef struct yt_face_shape_tiny_t_liveness {
int eye_size; ///< 眼睛点数(左眼,右眼)
int eyebrow_size; ///< 眉毛点数(左眉,右眉)
int nose_size; ///< 鼻子点数
int mouth_size; ///< 嘴巴点数
int profile_size; ///< 轮廓点数
int forehead_size; ///< 前额点数
int pupil_size; ///< 瞳孔点数
yt_pointf left_eyebrow[YT_DENSE_EYEBROW_POINTS_NUM];
yt_pointf right_eyebrow[YT_DENSE_EYEBROW_POINTS_NUM];
yt_pointf left_eye[YT_DENSE_EYE_POINTS_NUM];
yt_pointf right_eye[YT_DENSE_EYE_POINTS_NUM];
yt_pointf nose[YT_DENSE_NOSE_POINTS_NUM];
yt_pointf mouth[YT_DENSE_MOUTH_POINTS_NUM];
yt_pointf profile[YT_DENSE_PROFILE_POINTS_NUM];
yt_pointf forehead[YT_DENSE_FOREHEAD_POINTS_NUM];
yt_pointf pupil[YT_DENSE_PUPIL_POINTS_NUM];
float left_eyebrow_vis[YT_DENSE_EYEBROW_POINTS_NUM];
float right_eyebrow_vis[YT_DENSE_EYEBROW_POINTS_NUM];
float left_eye_vis[YT_DENSE_EYE_POINTS_NUM];
float right_eye_vis[YT_DENSE_EYE_POINTS_NUM];
float nose_vis[YT_DENSE_NOSE_POINTS_NUM];
float mouth_vis[YT_DENSE_MOUTH_POINTS_NUM];
float profile_vis[YT_DENSE_PROFILE_POINTS_NUM];
float forehead_vis[YT_DENSE_FOREHEAD_POINTS_NUM];
float pupil_vis[YT_DENSE_PUPIL_POINTS_NUM];
float confidence; ///< 置信度
float occuRatio; ///< 遮挡比例
} Yt_face_shape_tiny_liveness;
typedef struct yt_face_shape_3d_tiny_t_liveness {
yt_point3f dense_points[1000]; // 三维姿态点位
float pitch; // Up < 0 | Down > 0, 范围在 [-60 ~ 60 ] 内会更加准确
float yaw; // Left > 0 | Right < 0, 范围在 [-60 ~ 60] 内会更加准确
float roll; // Anti-clockwise < 0 | Clockwise > 0
float transform[4][4];
} Yt_face_shape_3d_tiny_liveness;
/**
* @brief 获取版本
*
* @param[in] handle 实例句柄,获得 SDK 版本
* @return SDK 版本
*/
// YT_PUBLIC const char *yt_face_alignment_tiny_get_version();
YT_PUBLIC const char *Yt_face_alignment_tiny_get_version_liveness();
/**
* @brief 初始化SDK每个进程只需调用一次
*
* @param[in] model_dirpath 传入模型绝对路径或者相对路径,例如:`./model/face-xxx`
* @param[in] config_filename 传入模型路径下的配置文件名称,例如:`config.ini`
* @return YT_SUCCESS成功其他失败
*/
// YT_PUBLIC int yt_face_alignment_tiny_create_handle(yt_handle *handle, const char *model_dirpath, const char *config_filename);
YT_PUBLIC int Yt_face_alignment_tiny_create_handle_liveness(yt_handle *handle, const char *model_dirpath, const char *config_filename);
#ifdef __ANDROID__
#include <android/asset_manager.h>
/**
* @brief 初始化SDK每个进程只需调用一次该接口用于 android 加载 assets 目录下模型文件
* 如有 jni 开发需求,可以通过此接口加载模型
*
* @param[in] mgr 通过 `AAssetManager *mgr = AAssetManager_fromJava(env, assetManager);` 获得
* @param[in] assets_model_dirpath 传入模型相对于 `assets` 目录的路径,例如:`models/face-xxx`
* @param[in] assets_config_filename 传入模型路径下的配置文件名称,例如:`config.ini`
* @return YT_SUCCESS成功其他失败
*/
YT_PUBLIC int Yt_face_alignment_tiny_create_handle_android_liveness(yt_handle *handle, AAssetManager *mgr, const char *model_dirpath, const char *config_filename);
// YT_PUBLIC int yt_face_alignment_tiny_create_handle_android(yt_handle *handle, AAssetManager *mgr, const char *model_dirpath, const char *config_filename);
#endif
#ifdef UNIVERSE_IO
#include <io/io.hpp>
YT_PUBLIC int Yt_face_alignment_tiny_create_handle_io_liveness(yt_handle *handle, const char *model_dirpath, const char *config_filename, IO* io);
#endif
/**
* @brief 销毁实例
*
* @param[in] handle 实例句柄
* @return
*/
YT_PUBLIC void Yt_face_alignment_tiny_destroy_handle_liveness(yt_handle handle);
// YT_PUBLIC void yt_face_alignment_tiny_destroy_handle(yt_handle handle);
/**
* @brief 设置实例出来的人脸配准点的置信度阈值
*
* @param[in] handle 实例句柄
* @param[in] threshold 人脸配准置信度阈值
* @return YT_SUCCESS成功其他失败
*/
YT_PUBLIC int Yt_face_alignment_tiny_set_threshold_liveness(yt_handle handle, float threshold);
// YT_PUBLIC int yt_face_alignment_tiny_set_threshold(yt_handle handle, float threshold);
/**
* @brief 设置实例align和track接口的配准模式
*
* @param[in] handle 实例句柄
* @param[in] mode 1代表 SPARSE/130 点配准2代表 DENSE/256 点配准
* 可选择模式取决于初始化时 config 文件中的 typeDENSE兼容模式1、2SPARSE只支持模式1
* @return YT_SUCCESS成功其他失败
*/
YT_PUBLIC int Yt_face_alignment_tiny_set_mode_liveness(yt_handle handle, int mode);
// YT_PUBLIC int yt_face_alignment_tiny_set_mode(yt_handle handle, int mode);
/**
* @brief 配准接口,用于人脸框得到人脸信息
*
* @param[in] handle 实例句柄
* @param[in] image 图片,推荐 YT_IMG_BGR_8UC3 / YT_IMG_RGB_8UC3 / YT_IMG_GRAY_8UC1
* @param[in] rect 人脸框
* @param[out] face 人脸信息
* @return YT_PUBLIC yt_face_alignment_tiny_align
*/
YT_PUBLIC int Yt_face_alignment_tiny_align_liveness(yt_handle handle, const yt_image image, const yt_rect rect, Yt_face_shape_tiny_liveness *face);
// YT_PUBLIC int yt_face_alignment_tiny_align(yt_handle handle, const yt_image image, const yt_rect rect, yt_face_shape_tiny *face);
/**
* @brief 追踪配准接口
* @example 当配合 YTFaceDetector SDK 使用时候的调用示例
*
* ```c++
* int ret;
* // step 1: 获取输入图片上检测到的人脸
* yt_rect *rects;
* int rect_count = 0;
* ret = yt_face_detector_detect(yt_detect_handle, image, param, &rects, &rect_count);
*
* // step 2: 使用 rect 进行配准,首帧时要求 rect 准确
* yt_face_shape_tiny *face_shapes = new yt_face_shape_tiny[rect_count];
* for (int i = 0; i < rect_count; i++) {
* int face_id = i;
* yt_rect face_rect = rect[face_id];
* ret = yt_face_alignment_tiny_track(yt_align_hanele, image, face_id, face_rect, &face_shapes[face_id]);
* }
*
* // step 3: 释放
* delete[] rects;
* for (int i = 0; i < rect_count; i++) {
* yt_face_alignment_tiny_release(face_shapes[i]);
* }
* delete[] face_shapes;
* ```c++
*
* @param[in] handle 实例句柄
* @param[in] image 图片,推荐 YT_IMG_BGR_8UC3 / YT_IMG_RGB_8UC3 / YT_IMG_GRAY_8UC1
* @param[in] face_id 需要追踪的人脸框 ID
* @param[in] face_rect 追踪的人脸框
* @param[out] faces 每个框对应的人脸配准点
* @return YT_SUCCESS成功
* -10000人脸追踪过程置信度不满足阈值要求时的失败结果
* 其他:失败
*/
YT_PUBLIC int Yt_face_alignment_tiny_track_liveness(yt_handle handle, const yt_image image, const int face_id, const yt_rect face_rect, Yt_face_shape_tiny_liveness *face_shape);
// YT_PUBLIC int yt_face_alignment_tiny_track(yt_handle handle, const yt_image image, const int face_id, const yt_rect face_rect,
// yt_face_shape_tiny *face_shape);
// /**
// * @brief 释放检测结果
// *
// * @param[in] yt_face_shape_tiny
// */
// YT_PUBLIC void yt_face_alignment_tiny_release(yt_face_shape_tiny *face);
/**
* @brief 重置追踪状态
*
* @param[in] handle 实例句柄
* @return YT_SUCCESS成功其他失败
*/
YT_PUBLIC int Yt_face_alignment_tiny_reset_liveness(yt_handle handle);
// YT_PUBLIC int yt_face_alignment_tiny_reset(yt_handle handle);
/**
* @brief 人脸透视投影姿态估计接口函数,输出三维角度
*
* @param[in] handle 实例句柄
* @param[in] face_shape 人脸配准点
* @param[in] focal 摄像头像素焦距,如 600
* @param[in] center_x 图像中点x如 image.width / 2
* @param[in] center_y 图像中点y如 image.height / 2
* @param[in] is_deg true : 以角度形式输出
* false : 以弧度形式输出
* @param[out] face_shape_3d 三维角度及3D平移shape
* @return YT_SUCCESS成功其他失败
*/
YT_PUBLIC int Yt_face_alignment_tiny_get_face_shape_3d_liveness(yt_handle handle, const Yt_face_shape_tiny_liveness face_shape, float focal, float center_x, float center_y, bool is_deg, Yt_face_shape_3d_tiny_liveness *face_shape_3d);
// YT_PUBLIC int yt_face_alignment_tiny_get_face_shape_3d(yt_handle handle, const yt_face_shape_tiny face_shape,
// float focal, float center_x, float center_y, bool is_deg,
// yt_face_shape_3d_tiny *face_shape_3d);
#endif // _YT_FACE_ALIGNMENT_H_

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>YTFaceAlignmentTiny</string>
<key>CFBundleIdentifier</key>
<string>com.tencent.youtu.alignment</string>
<key>CFBundleExecutable</key>
<string>YTFaceAlignmentTinyLiveness</string>
<key>CFBundleVersion</key>
<string>v3.0.2-mini.5-2-g7035ab4</string>
<key>CFBundleShortVersionString</key>
<string>v3.0.2-mini.5-2-g7035ab4</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
</dict>
</plist>

View File

@@ -0,0 +1,43 @@
#ifndef _YT_COMMON_H_
#define _YT_COMMON_H_
typedef void *yt_handle;
typedef enum {
YT_IMG_BGR_8UC3,
YT_IMG_RGB_8UC3,
YT_IMG_GRAY_8UC1,
YT_IMG_DEPTH_16UC1,
YT_IMG_BGRA_8UC4,
YT_IMG_RGBA_8UC4,
YT_IMG_NV21,
YT_IMG_NV12,
YT_IMG_UNKNOWN,
} yt_img_type;
typedef struct yt_image_t {
unsigned char *data;
int width;
int height;
yt_img_type type;
} yt_image;
typedef struct yt_rect_t {
int x;
int y;
int width;
int height;
} yt_rect;
typedef struct yt_pointf_t {
float x;
float y;
} yt_pointf;
typedef struct yt_point3f_t {
float x;
float y;
float z;
} yt_point3f;
#endif // _YT_COMMON_H_

View File

@@ -0,0 +1,74 @@
#ifndef _YT_DEFINES_H_
#define _YT_DEFINES_H_
// ----------------------------------------------------------------------------
// YouTu for cross platform defines export c api.
// windows @see: http://geoffair.net/ms/declspec.htm
// ----------------------------------------------------------------------------
#if (defined(WIN32) || defined(WIN64))
#ifdef YT_EXPORT
#define YT_PUBLIC_ __declspec(dllexport)
#else
#define YT_PUBLIC_ __declspec(dllimport)
#endif
#else
#ifdef YT_EXPORT
#define YT_PUBLIC_ __attribute__((visibility("default")))
#else
#define YT_PUBLIC_
#endif
#endif
#ifdef __cplusplus
#define YT_PUBLIC extern "C" YT_PUBLIC_
#else
#define YT_PUBLIC YT_PUBLIC_
#endif
// ----------------------------------------------------------------------------
// YouTu error code defines
// ----------------------------------------------------------------------------
#define YT_SUCCESS 0
#define YT_ERROR -1
// init error code: [-10, -99]
#define YT_ERROR_OPEN_FILE -10
#define YT_ERROR_READ_FILE -11
#define YT_ERROR_FILE_EMPTY -12
#define YT_ERROR_RPN_NET_INIT -20
#define YT_ERROR_RPN_NET_NOT_INIT -21
#define YT_ERROR_RPN_INST_INIT -22
#define YT_ERROR_RPN_INST_NOT_INIT -23
#define YT_ERROR_RPN_FORWARD -24
#define YT_ERROR_TNN_MEMORY_ALLOC_FAILED -25
#define YT_ERROR_INVALID_INSTANCE -99
// arguments error code: [-100, -999]
#define YT_ERROR_MUST_NOT_NULL -100
#define YT_ERROR_IMAGE_TYPE -110
#define YT_ERROR_IMAGE_DATA -111
#define YT_ERROR_FACE_POINTS -120
#define YT_ERROR_FACE_FIVE_POINTS -121
#define YT_ERROR_FACE_NINETY_POINTS -122
#define YT_ERROR_FACE_RECT -123
#define YT_ERROR_INVALID_MODEL_VERSION -130
#define YT_ERROR_MODEL_THRESHOLDS_SIZE -131
// auth error code
#define YT_ERROR_AUTH_FAILED -1024
// ----------------------------------------------------------------------------
// YouTu common code defines
// ----------------------------------------------------------------------------
#define YT_FACE_FEATURE_SIZE_512 512
#define YT_FACE_FEATURE_SIZE_1024 1024
#define YT_FACE_FIVE_POINTS_SIZE 5
#define YT_FACE_NINETY_POINTS_SIZE 90
#endif // _YT_DEFINES_H_

View File

@@ -0,0 +1,87 @@
#ifndef _YT_FACE_DETECTOR_H_
#define _YT_FACE_DETECTOR_H_
#include "yt_common.h"
#include "yt_defines.h"
typedef struct yt_face_detector_param_t_liveness {
int min_face_size; ///< 最小搜索步长,建议使用默认值
int max_face_size; ///< 最大搜索步长,建议使用默认值
int bigger_face_mode; ///< 检测模式0:完整检测, 1:快速检测
bool non_square_rect; ///< 检测框:是否为正方形框
float threshold; ///< 检测阈值:建议使用默认值
} Yt_face_detector_param_liveness;
/**
* @brief 获取版本
*
* @param[in] handle 实例句柄,获得 SDK 版本
* @return SDK 版本
*/
YT_PUBLIC const char *Yt_face_detector_get_version_liveness();
/**
* @brief 初始化SDK每个进程只需调用一次
*
* @param[in] model_dirpath 传入模型绝对路径或者相对路径,例如:`./model/face-xxx`
* @param[in] config_filename 传入模型路径下的配置文件名称,例如:`config.ini`
* @return YT_SUCCESS成功其他失败
*/
YT_PUBLIC int Yt_face_detector_create_handle_liveness(yt_handle *handle, const char *model_dirpath, const char *config_filename);
#ifdef __ANDROID__
#include <android/asset_manager.h>
/**
* @brief 初始化SDK每个进程只需调用一次该接口用于 android 加载 assets 目录下模型文件
* 如有 jni 开发需求,可以通过此接口加载模型
*
* @param[in] mgr 通过 `AAssetManager *mgr = AAssetManager_fromJava(env, assetManager);` 获得
* @param[in] assets_model_dirpath 传入模型相对于 `assets` 目录的路径,例如:`models/face-xxx`
* @param[in] assets_config_filename 传入模型路径下的配置文件名称,例如:`config.ini`
* @return YT_SUCCESS成功其他失败
*/
YT_PUBLIC int Yt_face_detector_create_handle_android_liveness(yt_handle *handle, AAssetManager *mgr, const char *model_dirpath, const char *config_filename);
#endif
#ifdef UNIVERSE_IO
#include <io/io.hpp>
YT_PUBLIC int Yt_face_detector_create_handle_io_liveness(yt_handle* handle, const char* model_dirpath, const char* config_filename, IO* io);
#endif
/**
* @brief 销毁实例
*
* @param[in] handle 实例句柄
*/
YT_PUBLIC void Yt_face_detector_destroy_handle_liveness(yt_handle handle);
/**
* @brief 获取参数
*
* @param[in] handle 实例句柄
* @param[out] param 默认参数
* @return YT_SUCCESS成功其他失败
*/
YT_PUBLIC int Yt_face_detector_get_default_param_liveness(yt_handle handle, Yt_face_detector_param_liveness *param);
/**
* @brief 检测接口,单帧图片检测
*
* @param[in] handle 实例句柄
* @param[in] image 图片图片类型YT_IMG_BGR_8UC3 or YT_IMG_RGB_8UC3
* @param[in] param 自定义的参数
* @param[out] tracked_faces 检测到的人脸信息
* @param[out] tracked_faces_count 检测到的人脸数量
* @return YT_SUCCESS成功其他失败
*/
YT_PUBLIC int Yt_face_detector_detect_liveness(yt_handle handle, const yt_image image, const Yt_face_detector_param_liveness param,
yt_rect **rects, int *count);
/**
* @brief 释放检测结果
*
* @param[in] rects
*/
YT_PUBLIC void Yt_face_detector_release_rects_liveness(yt_rect *rects);
#endif // _YT_FACE_DETECTOR_H_

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>YTFaceDetector</string>
<key>CFBundleIdentifier</key>
<string>com.tencent.youtu.detector</string>
<key>CFBundleExecutable</key>
<string>YTFaceDetectorLiveness</string>
<key>CFBundleVersion</key>
<string>v1.2.0-mini.5-2-g4e1d28c</string>
<key>CFBundleShortVersionString</key>
<string>v1.2.0-mini.5-2-g4e1d28c</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
</dict>
</plist>

View File

@@ -0,0 +1,76 @@
//
// DataDef.h
// FaceVideoTest
//
// Created by starimeliu on 2017/4/13.
// Copyright © 2017年 Tencent. All rights reserved.
//
#ifndef DataDef_h
#define DataDef_h
#include <vector>
#include <string>
#ifdef __APPLE__
#include <YTCv/core.hpp>
#endif
// ===== Observation Pack ======
struct YTRawImgData // === N pairs of images along with their landmarks ===
{
#ifdef __APPLE__
yt_tinycv::Mat3BGR frameMat;//iOS新一闪逐帧回调专用 用于OC层转UIImage对象再转jpeg android用JNI回调的方式在cpp方法内部做了jpeg图像转换
#endif
std::vector<unsigned char> frame_buffer; // Frame data in buffer
std::string frame_buffer_string; //frame_buffer的std::string类型值
std::string checksum;
long long CaptureTime;
int x;
int y;
};
struct RawYuvData
{
std::vector<unsigned char> yuvData;
int width;
int height;
};
struct YTDataPack
{
std::vector<YTRawImgData> VideoData; // Length = 2*N
long long BeginTime;
long long ChangePointTime;
std::vector<long long> ChangePointTimeList;
float OffsetSys;
int config_begin;
int frameNum; // Number of frames = 2*N
int LandMarkNum; // Length of landmark points = 90 here
int width;
int height;
const char *log; // text log info
const char *SeqID;
const char *version;
};
// ===== CAPTCHA Pack ======
struct YTCAPTCHA{
int fixedInterval;
int unit;
int rand_shift;
int rand_inv;
std::vector<int> intervals;
const char *SeqID;
};
// ===== Full Pack ======
struct YTFullPack{
YTDataPack AGin;
YTCAPTCHA CP;
};
#endif /* DataDef_h */

View File

@@ -0,0 +1,13 @@
//
// Version.h
// YTFaceLiveReflect
//
// Created by sunnydu on 2022/10/13.
// Copyright © 2022 Patrick Yang. All rights reserved.
//
#define R_FRAMEWORK_VERSION "1.1.15.175.1"
#ifndef Version_h
#define Version_h
#endif /* Version_h */

View File

@@ -0,0 +1,19 @@
//
// YTAGReflectDeviceDelegate.h
// FaceVideoTest
//
// Created by CosperYu on 2019/02/28.
// Copyright © 2019 Tencent. All rights reserved.
//
#ifndef YTAGReflectDeviceDelegate_h
#define YTAGReflectDeviceDelegate_h
@protocol YTAGReflectDeviceDelegate <NSObject>
//设置camera的曝光时间和iso
- (void)setCameraSettings:(long)expTime1000thSec iso:(int)isoValue;
//用于获取iso等摄像头信息该接口不会进行任何device设置只会读取device信息;
- (AVCaptureDevice *_Nonnull)getCaptureDevice;
@end
#endif /* YTAGReflectDeviceDelegate_h */

View File

@@ -0,0 +1,41 @@
//
// YTBrightnessManager.h
// YTFaceLiveReflect
//
// Created by CosperYu on 2019/01/03.
// Copyright © 2019年 Patrick Yang. All rights reserved.
//
#import <Foundation/Foundation.h>
#include <vector>
NS_ASSUME_NONNULL_BEGIN
@protocol YTOnGetBrightness <NSObject>
-(void)onGetBrightness:(float)brightness; //获取到光线强度
-(void)getBrightnessOverTime; //获取超时
@end
@class BrightnessDevice;
@interface YTBrightnessManager : NSObject {
std::vector<float> vec;
}
@property (nonatomic, weak) id<YTOnGetBrightness> onGetBrightnessDelegate;
@property (nonatomic, strong, nullable) BrightnessDevice *brightnessDevice;
@property (nonatomic, strong, nullable) NSTimer *timer;
//@property (nonatomic, assign) std::vector<float> vec;
@property (nonatomic, assign) int recordCount;
+ (NSDictionary*)getUploadDic:(float)brightnessValue;
//overTime 超时时间(单位:ms超时后回调getBrightnessOverTime。
//启动后会调用前置摄像头传感设备获取信息如果当前正在使用前置摄像头可能会造成短时间7plus上1秒内的显示卡顿
- (int)getBrightness:(id<YTOnGetBrightness>)onGetBrightness overTime:(NSTimeInterval)overTime;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,190 @@
//
// YTFaceHandle.h
// FaceVideoTest
//
// Created by CosperYu on 2019/02/28.
// Copyright © 2019 Tencent. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "DataDef.h"
#import <AVFoundation/AVFoundation.h>
#import <sys/utsname.h>
#import "YTAGReflectDeviceDelegate.h"
#import <CommonCrypto/CommonCrypto.h>
#ifndef YTFaceHandle_h
#define YTFaceHandle_h
//#define YT_ENCODE_REFLECT_DATA
using namespace std;
// Comment this version define avoid redefined and use interfaces instead.
#define YT_FACE_REFLECT_VERSION @"3.7.4"
//活体类型
enum YTLIVETYPE {
LIVETYPE_REFLECT = 1, //反光
LIVETYPE_POSE = 2, //动作
};
//服务器回调验证
enum YTSERVERCHECK_TYPE {
YTSERVERCHECK_INPUTPARAM_NULL = -1, //入参为空
YTSERVERCHECK_CHECKPASS = 0, //检测通过
//反光验证使用
YTSERVERCHECK_REFLECT_FAILED = 1, //反光验证失败
YTSERVERCHECK_PICTURE_FAILED = 2, //防翻拍验证失败
YTSERVERCHECK_COMPARE_FAILED = 3, //对比失败
};
enum YTREFLECT_SAFETY_LEVEL {
YTREFLECT_SAFETY_RECOMMAND = 0, //推荐大小反光上传数据大概500K
YTREFLECT_SAFETY_LOW = 1, //低安全性上传包体大概300K。若网络环境或者破解要求没那么高的场景使用
YTREFLECT_SAFETY_HIGH = 2, //高安全性上传包体可能会到2M。微信在用
YTREFLECT_SAFETY_COUNT = 3
};
/*
@brief 反光结束时的回调
@param ret: 反光序列字符串
0 成功
-1 调用了clearAG终止反光
-1491 反光图片序列检验的时候检查不到人脸
-1493 时间戳数量跟图片数量对不上通常是sdk内部错误
-1494 iso变光点时序不正确通常是sdk内部错误造成
@param fullPack: 反光结果图
*/
typedef void (^onFinish)(int ret, YTFullPack fullPack);
typedef void (^onDalayCalc)();
typedef void (^onReflectLiveImgData)(YTRawImgData frame);
/*
@brief 解析rgb请求
@param rgbconfig: 解析后的rgb序列
@param error: 解析产生错误或者服务器回调错误。如果无错误则为nil
*/
typedef void (^YTRgbconfigParseResult)(NSString* _Nullable rgbconfig, NSError *_Nullable error);
/**
@brief 反光事件回调接口
@param rgb 屏幕颜色
@param light 屏幕亮度
*/
typedef void (^YTReflectEventCallback)(uint argb ,CGFloat light);
/**
@brief 反光SDK日志注册回调
@param level 日志等级 0 - error 1 - warn 2 - info 3 - error)
@param message 日志信息
*/
typedef void (^OnYTFaceReflectSDKLoggerEventBlock)(int level, NSString * _Nonnull message);
@interface YTFaceHandle : NSObject
#pragma mark - Global Interface
/**
* 0 RGB
* 1 BGR
*/
@property (assign, nonatomic) int innerImgType;
@property (assign, nonatomic) float compressReflectionImageScore;
/**
@brief 日志注册接口
@param level 日志等级 0 - error 1 - warn 2 - info 3 - error)
@param listener 日志回调
*/
+ (void)registerSDKLogger:(int) level withListener:(OnYTFaceReflectSDKLoggerEventBlock _Nullable)listener;
+ (NSString * _Nonnull)checksum:(NSString * _Nonnull)act_str withData:(id _Nonnull)data;
#pragma mark - Life Circle
/**
* 更新配置
* @param key is_alone_raw_push是否流式传输(边压帧边吐帧) 1打开 is_shorten_strategy 当流式传输时生效(解决性能问题) 1开启抽帧
* @param value
*/
- (void)updateParam:(NSString * _Nonnull)key withValue:(NSString * _Nonnull)value;
/**
@brief 初始化反光实例
@param appId: 应用的appid需要在优图后台申请
@param extraData: ppl version
*/
- (id _Nullable )initWithAppId:(NSString*_Nonnull)appId withExtraData:(NSString *_Nullable)extraData;
/**
@brief 反光事件回调注册函数
@param callback 反光事件回调
*/
- (void)setReflectEvent:(YTReflectEventCallback _Nonnull)callback;
/**
@brief 获取sdk版本
@return 返回版本信息
*/
- (const NSString * _Nonnull)getVersion;
/**
@brief 初始化并且开始反光过程
@param rgbConfig: 反光序列字符串
@param device:遵循YTAGReflectDeviceDelegate协议的对象
@param shapeView: 用于控制屏幕颜色变化的view
@param onDalayCalc: 开始延迟计算过程
@param onFinish: 前段反光过程完成具体返回内容含义参照onFinish定义。回调发生在主线程
@return error code:
0 成功
-1 CP_string格式组成不正确
-2 device为空
-3 shapeView为空
-4 onDalayCalc为空
-5 onFinish为空
-1024 授权验证失败
@warning 1、请在主线程调用
2、反光活体暂不支持多线程同时使用
*/
- (NSInteger)initAG:(NSString *_Nonnull)rgbConfig
device:(id<YTAGReflectDeviceDelegate> _Nonnull)device
shapeView:(UIView* _Nullable)shapeView
onDalayCalc:(onDalayCalc _Nonnull)onDalayCalc
onFinish:(onFinish _Nonnull)onFinish
onReflectLiveImgData:(onReflectLiveImgData _Nonnull)onReflectLiveImgData
outputDurationMS:(long &)durationMS;
/**
@brief 自动生成反光序列
@return 返回反光序列
*/
- (NSString * _Nonnull)AutoGenRgb:(int)rgbNum mode:(NSString * _Nonnull)mode;
/**
@brief 反光过程压帧接口
@param faceImageCrop: 反光开始后的每帧数据
@param faceAlign: 当前帧的配准结果
@param timeStamp: 当前帧时间戳
*/
- (void)PushImgSequence:(void*_Nonnull)faceRgbMat faceAlign:(NSMutableArray* _Nonnull)faceAlign timeStamp:(uint64_t)timeStamp;
//终止反光并清理反光数据调用后如需再次反光需要重新调用initAG
//可以在反光过程的任意阶段调用,如用户反光过程来电或者其他原因希望结束反光验证时
//正常流程下依然建议使用demo的方式反光过程进行界面锁定避免用户不必要的操作
- (void)clearAG;
#pragma mark - Settings
//安全性设置,参照 YTSAFETYLEVEL
- (void)setSafety:(YTREFLECT_SAFETY_LEVEL) value;
- (int)getSafety;
#pragma mark - Utility
//检测是否睁眼
//反光开始前需要用户睁眼,以避免沉睡状态下通过了反光验证
- (float) precheckCloseEye:(const NSMutableArray* _Nonnull) att;
////临时存储图的路径(测试用)
//-(void)setSavePath:(NSString* _Nonnull)savePath;
@end
#endif /* YTFaceHandle_h */

View File

@@ -0,0 +1,43 @@
#ifndef _YT_COMMON_H_
#define _YT_COMMON_H_
typedef void *yt_handle;
typedef enum {
YT_IMG_BGR_8UC3,
YT_IMG_RGB_8UC3,
YT_IMG_GRAY_8UC1,
YT_IMG_DEPTH_16UC1,
YT_IMG_BGRA_8UC4,
YT_IMG_RGBA_8UC4,
YT_IMG_NV21,
YT_IMG_NV12,
YT_IMG_UNKNOWN,
} yt_img_type;
typedef struct yt_image_t {
unsigned char *data;
int width;
int height;
yt_img_type type;
} yt_image;
typedef struct yt_rect_t {
int x;
int y;
int width;
int height;
} yt_rect;
typedef struct yt_pointf_t {
float x;
float y;
} yt_pointf;
typedef struct yt_point3f_t {
float x;
float y;
float z;
} yt_point3f;
#endif // _YT_COMMON_H_

View File

@@ -0,0 +1,74 @@
#ifndef _YT_DEFINES_H_
#define _YT_DEFINES_H_
// ----------------------------------------------------------------------------
// YouTu for cross platform defines export c api.
// windows @see: http://geoffair.net/ms/declspec.htm
// ----------------------------------------------------------------------------
#if (defined(WIN32) || defined(WIN64))
#ifdef YT_EXPORT
#define YT_PUBLIC_ __declspec(dllexport)
#else
#define YT_PUBLIC_ __declspec(dllimport)
#endif
#else
#ifdef YT_EXPORT
#define YT_PUBLIC_ __attribute__((visibility("default")))
#else
#define YT_PUBLIC_
#endif
#endif
#ifdef __cplusplus
#define YT_PUBLIC extern "C" YT_PUBLIC_
#else
#define YT_PUBLIC YT_PUBLIC_
#endif
// ----------------------------------------------------------------------------
// YouTu error code defines
// ----------------------------------------------------------------------------
#define YT_SUCCESS 0
#define YT_ERROR -1
// init error code: [-10, -99]
#define YT_ERROR_OPEN_FILE -10
#define YT_ERROR_READ_FILE -11
#define YT_ERROR_FILE_EMPTY -12
#define YT_ERROR_RPN_NET_INIT -20
#define YT_ERROR_RPN_NET_NOT_INIT -21
#define YT_ERROR_RPN_INST_INIT -22
#define YT_ERROR_RPN_INST_NOT_INIT -23
#define YT_ERROR_RPN_FORWARD -24
#define YT_ERROR_TNN_MEMORY_ALLOC_FAILED -25
#define YT_ERROR_INVALID_INSTANCE -99
// arguments error code: [-100, -999]
#define YT_ERROR_MUST_NOT_NULL -100
#define YT_ERROR_IMAGE_TYPE -110
#define YT_ERROR_IMAGE_DATA -111
#define YT_ERROR_FACE_POINTS -120
#define YT_ERROR_FACE_FIVE_POINTS -121
#define YT_ERROR_FACE_NINETY_POINTS -122
#define YT_ERROR_FACE_RECT -123
#define YT_ERROR_INVALID_MODEL_VERSION -130
#define YT_ERROR_MODEL_THRESHOLDS_SIZE -131
// auth error code
#define YT_ERROR_AUTH_FAILED -1024
// ----------------------------------------------------------------------------
// YouTu common code defines
// ----------------------------------------------------------------------------
#define YT_FACE_FEATURE_SIZE_512 512
#define YT_FACE_FEATURE_SIZE_1024 1024
#define YT_FACE_FIVE_POINTS_SIZE 5
#define YT_FACE_NINETY_POINTS_SIZE 90
#endif // _YT_DEFINES_H_

View File

@@ -0,0 +1,125 @@
#ifndef _YT_FACE_TRACKER_H_
#define _YT_FACE_TRACKER_H_
#include "yt_common.h"
#include "yt_defines.h"
#define YT_MINI_NAMESPACE liveness
#define SUFFIX_HELPER_(x, y) x##_##y
#define SUFFIX_HELPER(x, y) SUFFIX_HELPER_(x, y)
#define SUFFIX(x) SUFFIX_HELPER(x, YT_MINI_NAMESPACE)
typedef struct yt_face_tracker_param_t_liveness {
int min_face_size; ///< 最小物体大小,建议使用默认值
int max_face_size; ///< 最大物体大小,建议使用默认值
int bigger_face_mode; ///< 检测模式0:完整检测, 1:快速检测
bool non_square_rect; ///< 检测框:是否为正方形框
float threshold; ///< 检测阈值:建议使用默认值
int detect_interval; ///< 检测间隔默认6; detect_interval为-1时只在第一帧或没有人时做检测
int noface_detect_interval; /// < 检测间隔, 默认0,未检测到人脸后下一次检测间隔
} SUFFIX(Yt_face_tracker_param);
typedef struct yt_tracked_face_t_liveness {
int shape_size; ///< 人脸配准点有效位数 130 or 256
yt_pointf face_shape[256]; ///< 人脸配准点
float face_vis[256]; ///< 人脸配准点置信度
yt_rect face_rect; ///< 人脸框
int frame_id; ///< 帧ID
int trace_id; ///< 轨迹ID
float pitch; ///< 人脸俯仰角
float yaw; ///< 人脸偏航角
float roll; ///< 人脸翻滚角
} SUFFIX(Yt_tracked_face);
/**
* @brief 获取sdk版本
*
* @return yt_sdk_version
*/
YT_PUBLIC const char *SUFFIX(Yt_face_tracker_get_version)();
/**
* @brief 创建实例,每个线程需要单独的实例
*
* @param[out] handle 创建的handle每个线程需要独立的handle
* @param[in] model_dirpath 传入模型绝对路径或者相对路径,例如:./model/
* @param[in] config_filename 传入模型绝对路径或者相对路径下的配置文件名称例如config.ini
* @param[in] param 模型初始化参数其中的image_width、image_height和image_pading属性要根据视频长宽调整
* @return YT_SUCCESS成功其他失败
*/
YT_PUBLIC int SUFFIX(Yt_face_tracker_create_handle)(yt_handle *handle, const char *model_dirpath, const char *config_filename);
#ifdef __ANDROID__
#include <android/asset_manager.h>
/**
* @brief 创建实例,每个线程需要单独的实例,该接口用于 android 加载 assets 目录下模型文件
* 如有 jni 开发需求,可以通过此接口加载模型
*
* @param[in] mgr 通过 `AAssetManager *mgr = AAssetManager_fromJava(env, assetManager);` 获得
* @param[in] model_dirpath 传入模型相对于 `assets` 目录的路径,例如:`models/face-xxx`
* @param[in] config_filename 传入模型路径下的配置文件名称,例如:`config.ini`
* @return YT_SUCCESS成功其他失败
*/
YT_PUBLIC int SUFFIX(Yt_face_tracker_create_handle_android)(yt_handle *handle, AAssetManager *mgr, const char *model_dirpath, const char *config_filename);
#endif
#ifdef UNIVERSE_IO
# include "io.hpp"
YT_PUBLIC int SUFFIX(Yt_face_tracker_create_handle_io)(yt_handle* handle, const char* model_dirpath, const char* config_filename, IO* io);
#endif
/**
* @brief 销毁实例
*
* @param[in] handle 实例句柄
*/
YT_PUBLIC void SUFFIX(Yt_face_tracker_destroy_handle)(yt_handle handle);
/**
* @brief 获取参数
*
* @param[in] handle 实例句柄
* @param[out] param 当前实例的参数
* @return YT_SUCCESS成功其他失败
*/
YT_PUBLIC int SUFFIX(Yt_face_tracker_get_param)(yt_handle handle, SUFFIX(Yt_face_tracker_param) *param);
/**
* @brief 设置参数,推荐先获取参数,再设置
*
* @param[in] handle 实例句柄
* @param[in] param 自定义的参数
* @return YT_SUCCESS成功其他失败
*/
YT_PUBLIC int SUFFIX(Yt_face_tracker_set_param)(yt_handle handle, const SUFFIX(Yt_face_tracker_param) param);
/**
* @brief 追踪接口适合于视频流检测内部封装了检测、5点配准、稳定模块具有内部状态
*
* @param[in] handle 实例句柄
* @param[in] image 图片图片类型YT_IMG_BGR_8UC3 or YT_IMG_RGB_8UC3
* @param[out] tracked_faces 人脸追踪结果
* @param[out] tracked_faces_count 检测到的人脸数量
* @return YT_SUCCESS成功其他失败
*/
YT_PUBLIC int SUFFIX(Yt_face_tracker_track)(yt_handle handle, const yt_image image, SUFFIX(Yt_tracked_face) **tracked_faces, int *tracked_faces_count);
/**
* @brief 重置追踪接口,当对新的视频进行追踪时调用,用于清空追踪内部状态
*
* @param[in] handle 实例句柄
* @return YT_SUCCESS成功其他失败
*/
YT_PUBLIC int SUFFIX(Yt_face_tracker_reset)(yt_handle handle);
/**
* @brief 释放人脸追踪结果
*
* @param[in] tracked_faces 人脸追踪结果
*/
YT_PUBLIC void SUFFIX(Yt_face_tracker_release_tracked_faces)(SUFFIX(Yt_tracked_face) *tracked_faces);
#endif // _YT_FACE_TRACKER_H_

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>YTFaceTracker</string>
<key>CFBundleIdentifier</key>
<string>com.tencent.youtu.tracker</string>
<key>CFBundleExecutable</key>
<string>YTFaceTrackerLiveness</string>
<key>CFBundleVersion</key>
<string>v3.0.5-mini.16</string>
<key>CFBundleShortVersionString</key>
<string>v3.0.5-mini.16</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
</dict>
</plist>

View File

@@ -0,0 +1,97 @@
//
// Created by sunnydu on 2024/5/10.
//
#ifndef VERIFICATION_DETECTFACEINFO_H
#define VERIFICATION_DETECTFACEINFO_H
/// opencv
#ifdef __ANDROID__
#include <core.hpp>
#include <resize.hpp>
#include "cvtColor.hpp"
#else
#include <YTCv/core.hpp>
#include <YTCv/cvtColor.hpp>
#include <YTCv/resize.hpp>
#endif // __ANDROID__
/// opencv end
#include <vector>
/// 动作类型
typedef enum :int{
/// 眨眨眼动作
POSETYPE_BLINK_EYE = 1,
/// 张张嘴动作
POSETYPE_OPEN_MOUSE = 2,
//不建议使用的动作检测方式,安全性不如眨眼和张嘴高
/// 点点头动作
POSETYPE_NOD_HEAD = 3,
/// 摇摇头
POSETYPE_SHAKE_HEAD = 4,
/// 静默动作
POSETYPE_SILENCE = 5,
//缓慢向左转头
POSETYPE_TURN_LEFT = 6,
//缓慢向右转头
POSETYPE_TURN_RIGHT = 7,
//由近及远
POSETYPE_CLOSER_FAR = 8,
//由远及近
POSETYPE_FAR_CLOSER = 9,
POSETYPE_COUNT = POSETYPE_SILENCE+1
}POSETYPE;
/// 动作检测返回码
typedef enum :int{
/// 动作检测通过
POSE_RET_POSE_COMMIT = 1,
/// 动作检测中
POSE_RET_POSE_DETECTING = 0,
/// 姿态不正确
POSE_RET_POSE_NOT_RIGHT = -1,
/// 无人脸
POSE_RET_NO_FACE = -2,
/// 半边人脸
POSE_RET_HALF_FACE = -3,
/// 光线不合适
POSE_RET_LIGHT_NOT_RIGHT = -4,
/// 晃动
POSE_RET_SHAKING = -5,
///点位信息不对
POSE_SHAPE_ERROR = -6,
/// 授权不通过
POSE_RET_AUTH_FAILED = -1024,
/// 人脸质量最佳帧不通过 (ppl层 根据归因转换tips)
FACE_QUALITY_DELETE_FAILED = -1025,
/// 人脸质量最佳帧获取中 (ppl tips 请保持姿态)
FACE_QUALITY_KEEP = -1026,
/// 人脸姿态不合格
FACE_QUALITY_STATUS_FAILED = -1029,
/// 人脸质量阶段 角度不符合预期
FACE_QUALITY_STATUS_ANGLE_FAILED = -1030,
/// 闭眼
FACE_QUALITY_EYE_CLOSE = -1031,
/// 张嘴
FACE_QUALITY_MOUTH_OPEN = -1032,
FACE_QUALITY_SHAKING = -1033,
}YT_POSE_RET_TYPE;
struct DetectFaceInfo{
std::vector<float> shape;
std::vector<float> visVec;
POSETYPE postType;
yt_tinycv::Mat3BGR rgbPtr;
float pitch;
float yaw;
float roll;
int faceDetectStatus;
int faceQualityStatus;
yt_tinycv::Rect2i faceRect;
int frameW;
int frameH;
bool isFaceShaking;
};
#endif //VERIFICATION_DETECTFACEINFO_H

View File

@@ -0,0 +1,28 @@
//
// Created by sunnydu on 2023/3/3.
//
#ifndef VERIFICATION_FAR2NEARDATA_H
#define VERIFICATION_FAR2NEARDATA_H
#include <vector>
#ifdef __ANDROID__
#include <core.hpp>
#include <resize.hpp>
#include "cvtColor.hpp"
#else
#include <YTCv/core.hpp>
#include <YTCv/cvtColor.hpp>
#include <YTCv/resize.hpp>
#endif // __ANDROID__
struct FrameData {
float iou;
float area_ratio;
std::vector<float> align;
yt_tinycv::Mat3BGR rgb;
int x;
int y;
long frame_timestamp = 0;
yt_tinycv::Rect2i face_rect;
};
using FaceFrameList = std::vector<FrameData>;
#endif //VERIFICATION_FAR2NEARDATA_H

View File

@@ -0,0 +1,50 @@
#ifndef PoseUtils_h
#define PoseUtils_h
#include <stdint.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <sstream>
#include <math.h>
typedef struct _CAPTCHA_V2_ {
int fixedInterval; // 4 or 1
int unit; // ios: 70, andorid 120
std::vector<int> intervals; // 3 - 6
int rand_shift; // 0 - 3
int rand_inv; // -1 1
int version_flag; // 471418
int section_num; // section_num / intervals_num
int action; // -1
int unit_v2;
int live_mode; // 0 is close, 1 only open reflective, 2 only open action, 3. both open.
int64_t time_stamp_tv_sec;
int64_t time_stamp_tv_usec;
std::vector<int> colors; // total
std::vector<int> intervals2; // 2 - ?
std::vector<int> reserved_int; // size is 16, default is 5
std::string reserved;
} CAPTCHA_V2;
class PoseUtils{
public:
PoseUtils();
/**
* @brief 生成一串数字 用于checksum计算
*
* @param CP_string
* @return uint64_t
*/
uint64_t yt_parseCP(const std::string CP_string);
void setColorData(std::string cpStr, std::string clientVersionStr, std::string actStr);
std::string checksum(const std::string data);
std::string getSelectDataChecksum(std::string selectDataStr, std::string actVideochecksum,std::string checksumBest,std::string checksumMouth,std::string checksumEye);
private:
std::string clientVersionStr;
std::string actStr;
uint64_t timestamp;
};
#endif /* PoseUtils_h */

View File

@@ -0,0 +1,13 @@
//
// Version.h
// YTPoseDetector
//
// Created by sunnydu on 2022/10/13.
// Copyright © 2022 PanCheng. All rights reserved.
//
#define P_FRAMEWORK_VERSION "1.1.15.175.1";
#ifndef Version_h
#define Version_h
#endif /* Version_h */

View File

@@ -0,0 +1,234 @@
//
// YTFaceCheckLivePose.hpp
// YTPoseDetector
//
// Created by Cheng Pan on 3/27/18.
// Copyright © 2018 PanCheng. All rights reserved.
//
#ifndef YTFaceCheckLivePose_hpp
#define YTFaceCheckLivePose_hpp
#include <stdint.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <sstream>
#include <math.h>
#include "Far2NearData.h"
#include "YTFaceQualityDetect.h"
#include "DetectFaceInfo.h"
#include "PoseUtils.h"
#ifdef __ANDROID__
#include <core.hpp>
#include <resize.hpp>
#include "cvtColor.hpp"
#else
#include <YTCv/core.hpp>
#include <YTCv/cvtColor.hpp>
#include <YTCv/resize.hpp>
#endif // __ANDROID__
#ifdef YTFACETRACK_NAMESPACE
#endif
#ifdef __ANDROID__
#define FACEDETECT_EXPORT
#else
#define FACEDETECT_EXPORT __attribute__((visibility("default")))
#endif
#define YT_FACEPOSE_VERSION "3.7.5"
#define P_FRAMEWORK_VERSION "@FRAMEWORK_VERSION"
namespace youtu {
typedef int (*YtFacePoseSDKLogCallback)(void *caller, int level, std::string message);
typedef void (*PlatformJpegEncoderCallback)(void *context, unsigned char *rgb, int rows, int cols, std::string &jpegData);
class YTPoseLiveDetector;
/// 最佳照片检测时的返回码
typedef enum :int{
/// 当前帧光照质量较差
LIGHT_ERROR = -2,
/// 当前帧的人脸所占屏幕区域较小
FACE_TOO_SMALL = -3,
/// 当前帧的人脸姿态角度过大
POSE_ANGLE_ERROR = -4,
/// 当前帧的人脸嘴部姿态异常
POSE_MOUTH_ERROR = -5,
/// 当前帧其他异常情况
OHTER_ERROR = 0,
/// 检测正常
SUCCESS = 1
}BestImgCode;
/// 动作算法类型
typedef enum :int {
/// 推荐安全类型,光流算法
YTPOSE_SAFETY_RECOMMAND = 0,
/// (点位计算)灵敏度高,但是对遮挡攻击的效果不够理想
YTPOSE_SAFETY_LOW = 1,
/// (光流算法)相对安全,但是灵敏度会略微下降,让面部距离屏幕更近,可以有效提高通过率
YTPOSE_SAFETY_HIGH = 2,
/// 动作类型算法数量
YTPOSE_SAFETY_COUNT = 3
}YTPOSE_SAFETY_LEVEL;
struct YTPoseRect
{
int x;
int y;
int width;
int height;
YTPoseRect() :x(0), y(0), width(0), height(0){}
YTPoseRect(int x_, int y_, int width_, int height_) :x(x_), y(y_), width(width_), height(height_){}
};
struct YTSize
{
int width;
int height;
YTSize() :width(0), height(0){}
YTSize(int width_, int height_) :width(width_), height(height_){}
};
struct YTPosePoint2f
{
float x;
float y;
YTPosePoint2f() :x(0), y(0){}
YTPosePoint2f(int x_, int y_) :x(x_), y(y_){}
YTPosePoint2f operator -(const YTPosePoint2f& rp){
return YTPosePoint2f(x - rp.x, y - rp.y);
}
};
inline float Norm(YTPosePoint2f p)
{
double x = p.x;
double y = p.y;
return sqrt(x * x + y * y);
}
/// 动作检测对象类
class FACEDETECT_EXPORT FaceCheckLivePose
{
public:
/// 动作检测构造接口
/// @param _frameNum 缓存视频帧数推荐20帧
FaceCheckLivePose(int _frameNum=20);
/// 动作检测析构接口
~FaceCheckLivePose();
/// 获取版本信息
/// @note 返回当前版本信息
static std::string getVersion();
/// 重置接口
///@note 每次开始检测动作的时候请调用reset检测不到人脸的时候也应该调用reset以保障动作过程中没有发生人脸切换
/// 获取完最优图和视频帧数据后也请调用reset接口
void reset();
/// 动作安全等级设置接口
/// @param level 参考YTPOSE_SAFETY_LEVEL 目标安全等级
void setSafetyLevel(YTPOSE_SAFETY_LEVEL level);
/// 动作安全等级获取接口
/// @return 返回当前动作安全等级
YTPOSE_SAFETY_LEVEL getSafetyLevel();
/// 动作检测接口
/// @param shapeInput 输入人脸框
/// @param visVec 输入关键点置信度
/// @param poseType 输入目标动作
/// @param rgb 输入帧信息rgb
/// @param yuv 输入帧信息yuv仅android使用其他情况请填充空mat
/// @param pitch 输入人脸俯仰角度
/// @param yaw 输入人脸左右角度
/// @param roll 输入人脸旋转角度
/// @return 返回YT_POSE_RET_TYPE 对应的错误码信息
/**
return -1 姿态不正确
-2 当前没有人脸
-3 当前只有半张脸
-4 光线不合适
-5 当前晃动较大
-1024 授权检测不过
**/
int detect_liveness(DetectFaceInfo& detectFaceInfo);
void registerSDKLogger(int level, YtFacePoseSDKLogCallback listener);
//最优图相关接口
/// 获取最优图
/// @return 返回对应最优图
yt_tinycv::Mat3BGR get_BestImgMat();
/// 获取最优图
/// @param shape 人脸信息
/// @return 返回对应最优图
yt_tinycv::Mat3BGR get_BestImgMat(std::vector<float> & shape);
/// 检测记录完成通知
/// @return 返回是否可以获取序列帧视频和最优图
bool get_RecordingDone();
/// 获取当前已经存储的视频流
/// @return 返回序列帧 yuv格式
std::vector<yt_tinycv::Mat3BGR> get_bgrFrameList();
// 动作+反光合并协议相关接口
/// 获取动作幅度最大图
/// @param bestImg 输出动作最大的图
/// @param bestShape 输出动作最大的点位信息
/// @param eyeImg 输出动作最大的eye部图
/// @param eyeShape 输出动作最大的eye部点位信息
/// @param mouthImg 输出动作最大的mouth部图
/// @param mouthImg 输出动作最大的mouth部点位信息
void get_PoseImgMat(yt_tinycv::Mat3BGR &bestImg, std::vector<float> &bestShape,
yt_tinycv::Mat3BGR &eyeImg, std::vector<float> &eyeShape,
yt_tinycv::Mat3BGR &mouthImg, std::vector<float> &mouthShape
);
int get_actionVideoShortenStrategy();
//主要动作执行完成,可以启动下一个步骤(目前主要用于动作+反光方案)
/// 检测是否可以进入反光
/// @return 返回是否可以进入反光状态
bool get_CanReflect();
/// 更新内部检测参数
/// @param key 参数key
/// @param value 参数值
int updateParam(const std::string &key, const std::string &value);
std::string checksum(const std::string data);
void setColorData(std::string cp, std::string clientVersion, std::string actStr);
void setChecksumJpg(std::string best, std::string eye, std::string mouth);
std::string getSelectDataChecksum(std::string selectDataStr, std::string actionVideo);
yt_tinycv::Mat3BGR get_MaxActionEyeImgMat(std::vector<float> & shape);
yt_tinycv::Mat3BGR get_MaxActionMouthImgMat(std::vector<float> & shape);
bool isFrameListNull();
void initFar2NearParam(int width,int height,int count,float min_r,float max_r);
FaceFrameList GetFaceDistanceDetectData();
std::vector<yt_tinycv::Rect2i> GetFaceDistanceProcessRect();
std::string getFaceDetectDistanceRectParam();
std::vector<int> GetLargeFace();
std::vector<int> GetSmallFace();
float GetFar2NearRectChangeScore();
private:
YTPoseLiveDetector* livenessdetector;
YTFaceQualityDetect* faceQualityDetect;
PoseUtils* poseUtils;
std::string anchorWidths;
std::string checksumBest;
std::string checksumEye;
std::string checksumMouth;
std::string checksumActionVideo;
};
/// 推荐对外使用类型
class FACEDETECT_EXPORT YTFaceCheckLivePose:public FaceCheckLivePose{};
}
#endif /* YTFaceCheckLivePose_hpp */

View File

@@ -0,0 +1,83 @@
//
// YTFaceCheckLivePoseErrorCode.h
//
// Created by tidetzhang 2020/08/06.
// Copyright © 2018 PanCheng. All rights reserved.
//
#ifndef _YTFACECHECKLIVEPOSEERRORCODE_H_
#define _YTFACECHECKLIVEPOSEERRORCODE_H_
namespace youtu
{
/// 动作类型
typedef enum : int {
/// 眨眨眼动作
POSETYPE_BLINK_EYE = 1,
/// 张张嘴动作
POSETYPE_OPEN_MOUSE = 2,
//不建议使用的动作检测方式,安全性不如眨眼和张嘴高
/// 点点头动作
POSETYPE_NOD_HEAD = 3,
/// 摇摇头
POSETYPE_SHAKE_HEAD = 4,
/// 静默动作
POSETYPE_SILENCE = 5,
POSETYPE_COUNT = POSETYPE_SILENCE + 1
} POSETYPE;
/// 动作检测返回码
typedef enum : int {
/// 动作检测通过
POSE_RET_POSE_COMMIT = 1,
/// 动作检测中
POSE_RET_POSE_DETECTING = 0,
/// 姿态不正确
POSE_RET_POSE_NOT_RIGHT = -1,
/// 无人脸
POSE_RET_NO_FACE = -2,
/// 半边人脸
POSE_RET_HALF_FACE = -3,
/// 光线不合适
POSE_RET_LIGHT_NOT_RIGHT = -4,
/// 晃动
POSE_RET_SHAKING = -5,
///点位信息不对
POSE_SHAPE_ERROR = -6,
/// 授权不通过
POSE_RET_AUTH_FAILED = -1024
} YT_POSE_RET_TYPE;
/// 最佳照片检测时的返回码
typedef enum : int {
/// 当前帧光照质量较差
LIGHT_ERROR = -2,
/// 当前帧的人脸所占屏幕区域较小
FACE_TOO_SMALL = -3,
/// 当前帧的人脸姿态角度过大
POSE_ANGLE_ERROR = -4,
/// 当前帧的人脸嘴部姿态异常
POSE_MOUTH_ERROR = -5,
/// 当前帧其他异常情况
OHTER_ERROR = 0,
/// 检测正常
SUCCESS = 1
} BestImgCode;
/// 动作算法类型
typedef enum : int {
/// 推荐安全类型,光流算法
YTPOSE_SAFETY_RECOMMAND = 0,
/// (点位计算)灵敏度高,但是对遮挡攻击的效果不够理想
YTPOSE_SAFETY_LOW = 1,
/// (光流算法)相对安全,但是灵敏度会略微下降,让面部距离屏幕更近,可以有效提高通过率
YTPOSE_SAFETY_HIGH = 2,
/// 动作类型算法数量
YTPOSE_SAFETY_COUNT = 3
} YTPOSE_SAFETY_LEVEL;
} // namespace youtu
#endif /* YTFaceCheckLivePose_hpp */

View File

@@ -0,0 +1,99 @@
//
// Created by sunnydu on 2024/5/9.
//
#ifndef VERIFICATION_YTFACEQUALITYDETECT_H
#define VERIFICATION_YTFACEQUALITYDETECT_H
#include "DetectFaceInfo.h"
#ifdef __ANDROID__
#include <core.hpp>
#include <resize.hpp>
#include "cvtColor.hpp"
#else
#include <YTCv/core.hpp>
#include <YTCv/cvtColor.hpp>
#include <YTCv/resize.hpp>
#endif // __ANDROID__
#include <vector>
class YTFaceQualityDetect {
public:
int needFaceQualityImage = false;
float stableRoiThreshold = 0.98f;//模糊判断
float continuousShelterNumThreshold = 5;
int continuousQualityNumThreshold = 10;
// float faceMaxHeightThreshold = 0.95f;
// float faceRealMinHeightThreshold = 0.4f;
float secondaryYawThreshold = 18;
float secondaryPitchThreshold = 18;
float secondaryRollThreshold = 18;
float closeMouthThreshold = 0.4f;
float closeEyeLeftThreshold = 0.25f;//左睁眼阈值
float closeEyeRightThreshold = 0.25f;//右睁眼阈值
//人脸质量最佳帧
bool isGetImageMat = false;
yt_tinycv::Mat3BGR qualityImageMat;
std::vector<float> qualityShape;
int continuousCount = 0;
int continuousShelterCount = 0;
/**
* 清空连续帧计数
*/
void resetContinuousCount();
/**
* 遮挡累计检测
*/
void shelterDetect();
/**
* 计数器+1然后判断是否满足条件
*/
int faceQualityIsPass(DetectFaceInfo& detectFaceInfo);
private:
yt_tinycv::Rect2i previousFaceRect = yt_tinycv::Rect2i(0,0,0,0);
/**
* 内置二级角度检测
*/
bool faceAngleForceCheck(DetectFaceInfo& detectFaceInfo);
/**
* 检测脸部长度占比,脸部长度占比在图像长度的预设百分比(faceHeightThreshold) 视为通过,否则不通过
* faceHeightThreshold 默认为0不对人脸大小做限制
*
* @return 1 太远
* 2 太近
* 0 合适
*/
int isFaceHeightStandard(DetectFaceInfo& detectFaceInfo);
/**
* 闭眼判断
* @param shape
* @return
*/
bool isEyeOpen(DetectFaceInfo& detectFaceInfo);
/**
* 张嘴检测
* @param detectFaceInfo
* @return
*/
bool isMouthClose(DetectFaceInfo& detectFaceInfo);
/**
* 计算人脸框差值
* @param rect1
* @param outRect
*/
void getIntersectionRect(const yt_tinycv::Rect2i& rect1,yt_tinycv::Rect2i& outRect);
/**
* 遮挡判断
* @param rect
* @return
*/
bool detectScreenShaking(const yt_tinycv::Rect2i& rect);
};
#endif //VERIFICATION_YTFACEQUALITYDETECT_H

View File

@@ -0,0 +1,52 @@
//
// YtSDKKitFrameworkTool.h
// YtSDKKitFrameworkTool
//
// Created by sunnydu on 2022/10/12.
// Copyright © 2022 Tecnet.Youtu. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface YtSDKTool : NSObject
#define T_FRAMEWORK_VERSION "1.1.15.175.1";
/**
获取YtSDKKitFrameworkTool*/
+(NSString*) getFrameworkVersion;
/**
慧眼版本
*/
+(void) setHuiYanVersion:(NSString*)huiyanVersion;
/**
远程下发模型场景对算法模型做MD5校验
*/
+(int) md5ValidityByDir:(NSString*) path;
/**
开启bugly
*/
+(void) openBuglyShared;
typedef enum {
//验证完成。
VALIDITY_OK=11000,
//模型文件夹目录为空 或者找不到路径
NOT_FOUND_MODEL_DIR=11001,
//找不到md5效验文件
NOT_FOUND_MODEL_MD5=11002,
//读取md5文件异常
READ_MD5_ERROR=11003,
//效验失败
VALIDITY_ERROR=11004,
//目标MD5值没有找到
TARGET_MD5_NOT_FOUND=11005,
//生成md5 失败
CREATE_MD5_ERROR=11006,
//模型文件存在个别缺失
MODEL_FILE_MISS=11007
}ModelValidityCode;
@end
NS_ASSUME_NONNULL_END

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,41 @@
{
"name": "custom",
"statusBarStyle": "dark",
"navbarTintColor": "0x333333",
"baseNavBarColor": "0x0",
"authNavBarColor": "0x22252A",
"imageBgColor": "0xffffff",
"faceNormalColor": "0x33FFFFFF",
"faceSatisfyColor": "0x5065FF",
"faceErrorColor": "0xFF6034",
"guideLabelColor": "0x363C62",
"guideLabelErrorColor" : "0xFF6034",
"customTipsColor": "0x545874",
"bottomTipsBgColor": "0xFAFAFA",
"bottomTipsTextColor": "0x8E92AE",
"backButtonImage": "backbutton@light",
"authBackButtonImage": "backbutton@dark",
"authBodyImage_651": "wbcf_auth_face_651",
"authCheckboxUnSelectImage_651": "wbcf_checkbox_unselect_651",
"authCheckboxSelectImage_651": "wbcf_checkbox_select_651",
"authCheckboxTipsColor": "0x8E92AE",
"authCheckboxLinkColor": "0x5065FF",
"authAgreeButtonNormalColor": "0xB7C0FF",
"authAgreeButtonHighlightColor": "0x5065FF",
"authAgreeTextNormalColor":"0xFFFFFF",
"authAgreeTextHighlightColor":"0xFFFFFF",
"authTipBackgroundColor_651":"0xF9FAFF",
"authTipTitileTextColor_651":"0x363C62",
"authTipDetailTextColor_651":"0x545874",
"alertTitleColor":"0x000000",
"alertMessageColor":"0x000000",
"alertLeftBtnColor":"0x5065FF",
"alertRightBtnColor":"0x5065FF",
"alertBackgroundColor":"0xFFFFFF"
}

View File

@@ -0,0 +1,41 @@
{
"name": "dark",
"statusBarStyle" : "light",
"navbarTintColor": "0xffffff",
"baseNavBarColor" : "0x0",
"authNavBarColor" : "0x22252A",
"imageBgColor" : "0x22252A",
"faceNormalColor": "0x33FFFFFF",
"faceSatisfyColor": "0x5065FF",
"faceErrorColor": "0xEB4140",
"guideLabelColor" : "0xffffff",
"guideLabelErrorColor" : "0xEB4140",
"customTipsColor": "0xFFFFFF",
"bottomTipsBgColor": "0x0DFFFFFF",
"bottomTipsTextColor": "0x80FFFFFF",
"backButtonImage":"backbutton@dark",
"authBackButtonImage":"backbutton@dark",
"authBodyImage_651": "wbcf_auth_face_651",
"authCheckboxUnSelectImage_651": "wbcf_checkbox_unselect_651",
"authCheckboxSelectImage_651": "wbcf_checkbox_select_651",
"authCheckboxTipsColor": "0xFFFFFF",
"authCheckboxLinkColor": "0x6F80FF",
"authAgreeButtonNormalColor": "0xB7C0FF",
"authAgreeButtonHighlightColor": "0x5065FF",
"authAgreeTextNormalColor":"0xFFFFFF",
"authAgreeTextHighlightColor":"0xFFFFFF",
"authTipBackgroundColor_651":"0x292C31",
"authTipTitileTextColor_651":"0xADB1C6",
"authTipDetailTextColor_651":"0x80FFFFFF",
"alertTitleColor":"0x000000",
"alertMessageColor":"0x000000",
"alertLeftBtnColor":"0x5065FF",
"alertRightBtnColor":"0x5065FF",
"alertBackgroundColor":"0xFFFFFF"
}

View File

@@ -0,0 +1,42 @@
{
"name" : "light",
"statusBarStyle": "dark",
"navbarTintColor": "0x333333",
"baseNavBarColor": "0x0",
"authNavBarColor": "0x22252A",
"imageBgColor": "0xffffff",
"faceNormalColor": "0x33FFFFFF",
"faceSatisfyColor": "0x5065FF",
"faceErrorColor": "0xFF6034",
"guideLabelColor": "0x363C62",
"guideLabelErrorColor" : "0xFF6034",
"customTipsColor": "0x545874",
"bottomTipsBgColor": "0xFAFAFA",
"bottomTipsTextColor": "0x8E92AE",
"backButtonImage": "backbutton@light",
"authBackButtonImage": "backbutton@dark",
"authBodyImage_651": "wbcf_auth_face_651",
"authCheckboxUnSelectImage_651": "wbcf_checkbox_unselect_651",
"authCheckboxSelectImage_651": "wbcf_checkbox_select_651",
"authCheckboxTipsColor": "0x999999",
"authCheckboxLinkColor": "0x5065FF",
"authAgreeButtonNormalColor": "0xB7C0FF",
"authAgreeButtonHighlightColor": "0x5065FF",
"authAgreeTextNormalColor":"0xFFFFFF",
"authAgreeTextHighlightColor":"0xFFFFFF",
"authTipBackgroundColor_651":"0xF9FAFF",
"authTipTitileTextColor_651":"0x363C62",
"authTipDetailTextColor_651":"0x545874",
"alertTitleColor":"0x000000",
"alertMessageColor":"0x000000",
"alertLeftBtnColor":"0x5065FF",
"alertRightBtnColor":"0x5065FF",
"alertBackgroundColor":"0xFFFFFF"
}

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>version</key>
<string>8.7.0</string>
</dict>
</plist>

View File

@@ -0,0 +1,6 @@
detect_path=face-detector-v535-i8
detect_cfg=config_detector.ini
align_path=face-alignment-v331-i8
align_cfg=config_sparse.ini
output_point_num=130

View File

@@ -0,0 +1,14 @@
version=v331
compute=cpu
type=sparse
sparse_model=1102_mbv2_p1_eye.opt.tnnmodel
sparse_proto=1102_mbv2_p1_eye.opt_bin.tnnproto
sparse_scale=1.1
eye_model=1105_mbv2_eye_ch3.opt.tnnmodel
eye_proto=1105_mbv2_eye_ch3.opt_bin.tnnproto
eye_scale=1.5
dense_model=null
dense_proto=null
dense_scale=1.5

Some files were not shown because too many files have changed in this diff Show More