Source: tfsdk.js

  1. /**
  2. * This is the node binding of Trueface SDK
  3. */
  4. "use strict";
  5. const FFI = require("ffi-napi");
  6. const Ref = require("ref-napi");
  7. const ArrayType = require("ref-array-di")(Ref);
  8. const StructType = require("ref-struct-di")(Ref);
  9. class TFSDKDataChecker {
  10. constructor() {
  11. this.exception = false;
  12. this.consoleError = false;
  13. }
  14. throw(message) {
  15. if (this.exception) throw new Error(message);
  16. if (this.consoleError) console.error(message);
  17. return 6;
  18. }
  19. isString(value) {
  20. return typeof value === "string" || value instanceof String;
  21. }
  22. isNumber(value) {
  23. return typeof value === "number" && isFinite(value);
  24. }
  25. isArray(value) {
  26. return value && typeof value === "object" && value.constructor === Array;
  27. }
  28. isObject(value) {
  29. return value && typeof value === "object" && value.constructor === Object;
  30. }
  31. isNull(value) {
  32. return value === null;
  33. }
  34. isUndefined(value) {
  35. return typeof value === "undefined";
  36. }
  37. isBoolean(value) {
  38. return typeof value === "boolean";
  39. }
  40. }
  41. /**
  42. * This is the main TFSDK class. In order for SDK to work, please first download the models files, only download the models which is required.
  43. * Download blink detector model
  44. * @example <caption>curl -O -L https://storage.googleapis.com/sdk-models/enc/blink/blink_detector_v1.trueface.enc</caption>
  45. * Download body pose estimator model
  46. * @example <caption>test -e body_pose_estimator_v1.trueface.enc || curl -O -L https://storage.googleapis.com/sdk-models/enc/body_pose_estimator/v1/body_pose_estimator_v1.trueface.enc</caption>
  47. * Download face landmarks v2 model
  48. * @example <caption>curl -O -L https://storage.googleapis.com/sdk-models/enc/landmark_detection/face_landmark_detector_v2.trueface.enc</caption>
  49. * Download face recognition lite v2 model
  50. * @example <caption>curl -O -L https://storage.googleapis.com/sdk-models/enc/face_recognition/cpu/face_recognition_cpu_lite_v2.trueface.enc</caption>
  51. * Download face recognition tfv4 cpu model
  52. * @example <caption>curl -O -L https://storage.googleapis.com/sdk-models/enc/face_recognition/cpu/face_recognition_cpu_v4.trueface.enc</caption>
  53. * Download face recognition tfv5 cpu model
  54. * @example <caption>curl -O -L https://storage.googleapis.com/sdk-models/enc/face_recognition/cpu/face_recognition_cpu_v5.trueface.enc</caption>
  55. * Download face recognition tfv4 gpu model
  56. * @example <caption>curl -O -L https://storage.googleapis.com/sdk-models/enc/face_recognition/gpu/face_recognition_gpu_v4.trueface.enc</caption>
  57. * Download face recognition tfv5 gpu model
  58. * @example <caption>curl -O -L https://storage.googleapis.com/sdk-models/enc/face_recognition/gpu/face_recognition_gpu_v5.trueface.enc</caption>
  59. * Download object detector v1 model
  60. * @example <caption>curl -O -L https://storage.googleapis.com/sdk-models/enc/object_detection/object_detector_v1.trueface.enc</caption>
  61. * Download spoof model
  62. * @example <caption>curl -O -L https://storage.googleapis.com/sdk-models/enc/spoof/v5/spoof_v5.trueface.enc</caption>
  63. * Then in your command line, run sh model_file.sh and place the model files in desired location, be sure to set the correct modelsPath in your sdk initialization.
  64. */
  65. module.exports = class TFSDK {
  66. constructor(options = {}, libPath = "./artifacts/") {
  67. this.dc = new TFSDKDataChecker();
  68. this.int = Ref.types.int;
  69. this.IntArray = ArrayType(this.int);
  70. const libType = "void";
  71. const libPtr = Ref.refType(libType);
  72. this.licensed = false;
  73. this.imageProperties = StructType({
  74. width: Ref.types.uint,
  75. height: Ref.types.uint,
  76. channels: Ref.types.uint,
  77. isGpuImage: Ref.types.bool
  78. });
  79. const ImagePropertiesPtr = Ref.refType(this.imageProperties);
  80. this.lib = FFI.Library(`${libPath}/libtfsdk`, {
  81. TFSDK__create: [libPtr, []],
  82. TFSDK__json_createWithConfigurationOptions: [libPtr, ["string"]],
  83. TFSDK__destory: ["void", [libPtr]],
  84. TFSDK__setLicense: ["bool", [libPtr, "string"]],
  85. TFSDK__isLicensed: ["bool", [libPtr]],
  86. TFSDK__getVersion: ["double", [libPtr]],
  87. TFSDK__setImage: ["int", [libPtr, this.IntArray, "int", "int", "int"]],
  88. TFSDK__setImageFromFile: ["int", [libPtr, "string"]],
  89. TFSDK__estimateFaceImageQuality: [this.IntArray, [libPtr, "double"]],
  90. TFSDK__json_detectObjects: ["string", [libPtr]],
  91. TFSDK__json_detectLargestFace: ["string", [libPtr]],
  92. TFSDK__json_detectFaces: ["string", [libPtr]],
  93. TFSDK__json_getLargestFaceFeatureVector: ["string", [libPtr]],
  94. TFSDK__json_getSimilarity: ["string", [libPtr, "string", "string"]],
  95. TFSDK__json_estimateHeadOrientation: ["string", [libPtr, "string"]],
  96. // TFSDK__json_detectBlink: ["string", [libPtr]],
  97. TFSDK__json_getFaceLandmarks: ["string", [libPtr, "string"]],
  98. TFSDK__createDatabaseConnection: ["int", [libPtr, "string"]],
  99. TFSDK__createLoadCollection: ["int", [libPtr, "string"]],
  100. TFSDK__json_enrollFaceprint: ["string", [libPtr, "string", "string"]],
  101. TFSDK__removeByUUID: ["int", [libPtr, "string"]],
  102. TFSDK__removeByIdentity: ["int", [libPtr, "string"]],
  103. TFSDK__json_identifyTopCandidate: [
  104. "string",
  105. [libPtr, "string", Ref.types.float],
  106. ],
  107. TFSDK__getImageProperties: ["string", [libPtr, ImagePropertiesPtr]],
  108. TFSDK__getFaceLandmarks: ["string", [libPtr, "string"]],
  109. // TFSDK__json_getFaceLandmarks: ["string", [libPtr, "string"]],
  110. TFSDK__json_getFaceFeatureVector: ["string", [libPtr, "string"]],
  111. TFSDK__detectActiveSpoof: ["string", [libPtr, "string", "string"]],
  112. TFSDK__checkSpoofImageFaceSize: ["string", [libPtr, "string", "string"]],
  113. TFSDK__json_detectMask: ["string", [libPtr, "string"]],
  114. TFSDK__json_detectGlasses: ["string", [libPtr, "string"]],
  115. TFSDK__extractAlignedFace: [this.IntArray, [libPtr, "string"]]
  116. });
  117. this.ptr = Ref.alloc(libPtr);
  118. if (options && Object.keys(options).length === 0) {
  119. this.ptr = this.lib.TFSDK__create();
  120. } else {
  121. this.ptr = this.lib.TFSDK__json_createWithConfigurationOptions(JSON.stringify(options));
  122. }
  123. }
  124. getColorSpace(bitmap) {
  125. if (!this.dc.isObject(bitmap) || !this.dc.isBoolean(bitmap._rgba))
  126. return this.dc.throw(`bitmap: must be a object, ${bitmap} was given`);
  127. if (bitmap._rgba === true) {
  128. return 3;
  129. } else {
  130. return 0;
  131. }
  132. }
  133. getError(error) {
  134. if (!this.dc.isNumber(error))
  135. return this.dc.throw(`error: must be a number, ${error} was given`);
  136. const ErrorCode = [
  137. "NO_ERROR",
  138. "INVALID_LICENSE",
  139. "FILE_READ_FAIL",
  140. "UNSUPPORTED_IMAGE_FORMAT",
  141. "UNSUPPORTED_MODEL",
  142. "NO_FACE_IN_FRAME",
  143. "FAILED",
  144. "COLLECTION_CREATION_ERROR",
  145. "DATABASE_CONNECTION_ERROR",
  146. "ENROLLMENT_ERROR",
  147. ];
  148. return ErrorCode[error];
  149. }
  150. /**
  151. * Sets and validates the given license token. Need to call this method
  152. * before being able to use the SDK.
  153. *
  154. * @param {string} token the license token (if you do not have this talk to
  155. * support@trueface.ai).
  156. * @returns {boolean} Whether the given license token is valid.
  157. */
  158. setLicense(license) {
  159. if (!this.dc.isString(license))
  160. return this.dc.throw(`license: must be a string, ${license} was given`);
  161. const res = this.lib.TFSDK__setLicense(this.ptr, license);
  162. this.licensed = res
  163. return res
  164. }
  165. /**
  166. * Checks whether the given license token is valid and you can use
  167. * the SDK.
  168. *
  169. * @returns {boolean} Whether the given license token is valid.
  170. */
  171. isLicensed() {
  172. return this.licensed
  173. }
  174. /**
  175. * Gets the version-build number of the SDK.
  176. *
  177. * @returns {string} Version Number.
  178. */
  179. getVersion() {
  180. return this.lib.TFSDK__getVersion(this.ptr);
  181. }
  182. /**
  183. * Set the image that is processed by the other methods.
  184. *
  185. * @param {Buffer} image an 8-bit decoded image array, in the CPU memory or the GPU memory.
  186. * @param {number} width the image width.
  187. * @param {number} height the image height.
  188. * @param {number} color the image color model, see ColorCode.
  189. *
  190. * @returns {object} error code, see ErrorCode.
  191. * Note, it is highly encouraged to check the return value from setImage before proceeding.
  192. * If the license is invalid, the INVALID_LICENSE error will be returned.
  193. */
  194. setImage(data, width, height, color) {
  195. if (!this.dc.isArray(data))
  196. return this.dc.throw(`data: must be an array, ${data} was given`);
  197. if (!this.dc.isNumber(width))
  198. return this.dc.throw(`width: must be a number, ${width} was given`);
  199. if (!this.dc.isNumber(height))
  200. return this.dc.throw(`height: must be a number, ${height} was given`);
  201. if (!this.dc.isNumber(color))
  202. return this.dc.throw(`color: must be a number, ${color} was given`);
  203. const arr = new this.IntArray(data.length);
  204. for (const [i, v] of data.entries()) arr[i] = v;
  205. return this.lib.TFSDK__setImage(this.ptr, arr, width, height, color);
  206. }
  207. /**
  208. * Set the image from a image file
  209. *
  210. * @param {string} path image's path
  211. * @returns {object} errorCode if there's error from set image
  212. */
  213. setImageFromFile(path) {
  214. if (!this.dc.isString(path))
  215. return this.dc.throw(`path: must be a string, ${path} was given`);
  216. return this.lib.TFSDK__setImageFromFile(this.ptr, path);
  217. }
  218. detectObjects() {
  219. const result = this.lib.TFSDK__json_detectObjects(this.ptr);
  220. return JSON.parse(result);
  221. }
  222. /**
  223. * Detect all the faces in the image. This method has a small false positive rate.
  224. * To reduce the false positive rate to near zero, filter out faces with score lower than 0.90.
  225. * Alternatively, you can use the `Trueface::FaceDetectionFilter`
  226. * configuration option to filter the detected faces.
  227. *
  228. * The face detector has a detection scale range of about 5 octaves. \ref ConfigurationOptions.smallestFaceHeight
  229. * determines the lower of the detection scale range. E.g., setting \ref ConfigurationOptions.smallestFaceHeight to
  230. * 40 pixels yields the detection scale range of ~40 pixels to 1280 (=40x2^5) pixels.
  231. *
  232. * @returns {object} faceBoxAndLandmarks a vector of \ref FaceBoxAndLandmarks representing each of the detected faces.
  233. * If not faces are found, the vector will be empty. The detected faces are sorted in order of descending face score.
  234. *
  235. * @returns {object} error code, see ErrorCode.
  236. */
  237. detectFaces() {
  238. const result = this.lib.TFSDK__json_detectFaces(this.ptr);
  239. return JSON.parse(result);
  240. }
  241. /**
  242. * Detect the largest face in the image.
  243. * This method has a small false positive rate.
  244. * To reduce the false positive rate to near zero, filter out faces with score lower than 0.90.
  245. * Alternatively, you can use the `Trueface::FaceDetectionFilter`
  246. * configuration option to filter the detected faces.
  247. * See detectFaces() for the detection scale range.
  248. *
  249. * @returns {object} faceBoxAndLandmarks the FaceBoxAndLandmarks containing the landmarks and bounding box
  250. * of the largest detected face in the image.
  251. * @returns {boolean} found whether a face was found in the image.
  252. *
  253. * @returns {object} error code, see ErrorCode.
  254. */
  255. detectLargestFace() {
  256. const result = this.lib.TFSDK__json_detectLargestFace(this.ptr);
  257. return JSON.parse(result);
  258. }
  259. /**
  260. * Detect the largest face in the image and return its feature
  261. * vector.
  262. *
  263. * @returns {object} Faceprint object which will contain
  264. * the face feature vector.
  265. * @returns {boolean} foundFace indicates if a face was detected in the image.
  266. * If no face was detected, then the faceprint will be empty.
  267. *
  268. * @returns {object} error code, see ErrorCode.
  269. */
  270. getLargestFaceFeatureVector() {
  271. const result = this.lib.TFSDK__json_getLargestFaceFeatureVector(this.ptr);
  272. return JSON.parse(result);
  273. }
  274. /**
  275. * Compute the similarity between two feature vectors, or how
  276. * similar two faces are.
  277. *
  278. * @param {object} faceprint1 the first Faceprint to be compared.
  279. * @param {object} faceprint2 the second Faceprint to be compared.
  280. * @returns {number} matchProbability the probability the two face feature vectors are a match.
  281. * @returns {number} similarityMeasure the computed similarity measure.
  282. *
  283. * @returns error code, see ErrorCode.
  284. */
  285. getSimilarity(faceprint1, faceprint2) {
  286. if (!this.dc.isObject(faceprint1))
  287. return this.dc.throw(
  288. `faceprint1: must be a object, ${faceprint1} was given`
  289. );
  290. if (!this.dc.isObject(faceprint2))
  291. return this.dc.throw(
  292. `faceprint2: must be a object, ${faceprint2} was given`
  293. );
  294. const result = this.lib.TFSDK__json_getSimilarity(
  295. this.ptr,
  296. JSON.stringify(faceprint1),
  297. JSON.stringify(faceprint2)
  298. );
  299. return JSON.parse(result);
  300. }
  301. /**
  302. * Estimate the head pose.
  303. *
  304. * @param {object} faceBoxAndLandmarks FaceBoxAndLandmarks returned by detectFaces() or detectLargestFace().
  305. *
  306. * @returns {object} <b>yaw</b> the rotation angle around the image's vertical axis, in radians. <b>pitch</b> the rotation angle around the image's transverse axis, in radians. <b>roll<b> the rotation angle around the image's longitudinal axis, in radians.
  307. * @returns {object} error code, see ErrorCode.
  308. */
  309. estimateHeadOrientation(face) {
  310. if (!this.dc.isObject(face))
  311. return this.dc.throw(`face: must be a object, ${face} was given`);
  312. const result = this.lib.TFSDK__json_estimateHeadOrientation(
  313. this.ptr,
  314. JSON.stringify(face)
  315. );
  316. return JSON.parse(result);
  317. }
  318. /*
  319. detectBlink() {
  320. const result = this.lib.TFSDK__json_detectBlink(this.ptr);
  321. return JSON.parse(result);
  322. }
  323. */
  324. /**
  325. *
  326. * Create a connection to a new or existing database.
  327. * If the database does not exist, a new one will be created with the provided name.
  328. * If the `Trueface::DatabaseManagementSystem::NONE` (memory only)
  329. * configuration option is selected, this function does not need to be called (and is a harmless no-op).
  330. *
  331. * @param {string} databaseConnectionString
  332. * If `Trueface::DatabaseManagementSystem::SQLITE` is selected, this should be the filepath to the database.
  333. * ex. "/myPath/myDatabase.db".
  334. * If `Trueface::DatabaseManagementSystem::POSTGRESQL`
  335. * is selected, this should be a database connection string.
  336. * <a href="https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS">Here</a>
  337. * is a list of all supported PostgreSQL connection parameters.
  338. * ex. "hostaddr=192.168.1.0 port=5432 dbname=face_recognition user=postgres password=my_password".
  339. * ex. "host=localhost port=5432 dbname=face_recognition user=postgres password=m_password".
  340. * To enable ssl, add "sslmode=require" to the connection string.
  341. *
  342. * @returns {object} error code, see ErrorCode.
  343. */
  344. createDatabaseConnection(databaseConnectionString) {
  345. if (!this.dc.isString(databaseConnectionString))
  346. return this.dc.throw(
  347. `databaseConnectionString: must be a string, ${databaseConnectionString} was given`
  348. );
  349. return this.lib.TFSDK__createDatabaseConnection(
  350. this.ptr,
  351. databaseConnectionString
  352. );
  353. }
  354. /**
  355. *
  356. * Create a new collection, or load data from an existing collection into memory (RAM) if one with the
  357. * provided name already exists in the database.
  358. * Equivalent to calling createCollection() then loadCollection().
  359. *
  360. * @param {string} collectionName the name of the collection.
  361. *
  362. * @returns {object} error code, see ErrorCode.
  363. */
  364. createLoadCollection(collectionName) {
  365. if (!this.dc.isString(collectionName))
  366. return this.dc.throw(
  367. `collectionName: must be a string, ${collectionName} was given`
  368. );
  369. return this.lib.TFSDK__createLoadCollection(this.ptr, collectionName);
  370. }
  371. /**
  372. * Enroll a Faceprint for a new or existing identity in the collection.
  373. *
  374. * @param {object} faceprint the Faceprint to enroll in the collection.
  375. * @param {string} identity the identity corresponding to the Faceprint.
  376. * @returns {string} UUID universally unique identifier corresponding to the Faceprint.
  377. *
  378. * @returns {object} error code, see ErrorCode.
  379. */
  380. enrollFaceprint(faceprint, identity) {
  381. if (!this.dc.isObject(faceprint))
  382. return this.dc.throw(
  383. `faceprint: must be a object, ${faceprint} was given`
  384. );
  385. if (!this.dc.isString(identity))
  386. return this.dc.throw(`identity: must be a string, ${identity} was given`);
  387. const result = this.lib.TFSDK__json_enrollFaceprint(
  388. this.ptr,
  389. JSON.stringify(faceprint),
  390. identity
  391. );
  392. return JSON.parse(result);
  393. }
  394. /**
  395. * Remove a Faceprint from the collection using the UUID.
  396. *
  397. * @param {string} UUID the universally unique identifier returned by enrollFaceprint().
  398. *
  399. * @returns {object} error code, see ErrorCode.
  400. */
  401. removeByUUID(UUID) {
  402. if (!this.dc.isString(UUID))
  403. return this.dc.throw(`UUID: must be a string, ${UUID} was given`);
  404. return this.lib.TFSDK__removeByUUID(this.ptr, UUID);
  405. }
  406. /**
  407. * Remove all Faceprints in the collection corresponding to the identity.
  408. *
  409. * @param {string} identity the identity to remove from the collection.
  410. * @returns {number} numFaceprintsRemoved the the number of Faceprint which were removed for that identity.
  411. *
  412. * @returns {object} error code, see ErrorCode.
  413. */
  414. removeByIdentity(identity) {
  415. if (!this.dc.isString(UUID))
  416. return this.dc.throw(`identity: must be a string, ${identity} was given`);
  417. return this.lib.TFSDK__removeByIdentity(this.ptr, identity);
  418. }
  419. /**
  420. * Get the top match Candidate in the collection and the corresponding similarity score and match probability.
  421. *
  422. * @param {object} faceprint the Faceprint to be identified.
  423. * @param {number }[in] threshold the similarity score threshold above which it is considered a match.
  424. * Higher thresholds may result in faster queries.
  425. * Refer to our <a href="https://docs.trueface.ai/ROC-Curves-d47d2730cf0a44afacb39aae0ed1b45a">ROC curves</a> when selecting a threshold.
  426. *
  427. * @returns {string} candidate the top match Candidate.
  428. * @returns {boolean} found set to true if a match is found.
  429. *
  430. * @returns {object} error code, see ErrorCode.
  431. */
  432. identifyTopCandidate(faceprint, threshold = 0.3) {
  433. if (!this.dc.isObject(faceprint))
  434. return this.dc.throw(
  435. `faceprint: must be an object, ${faceprint} was given`
  436. );
  437. if (!this.dc.isNumber(threshold))
  438. return this.dc.throw(
  439. `threshold: must be a float, ${threshold} was given`
  440. );
  441. const result = this.lib.TFSDK__json_identifyTopCandidate(
  442. this.ptr,
  443. JSON.stringify(faceprint),
  444. threshold
  445. );
  446. // console.log("result", result);
  447. return JSON.parse(result);
  448. }
  449. /**
  450. * Get properties of the image set by setImage().
  451. *
  452. * @returns {object} imageProperties the image properties
  453. */
  454. getImageProperties() { // need to use json format
  455. /*
  456. struct ImageProperties {
  457. unsigned int width = 0;
  458. unsigned int height = 0;
  459. unsigned int channels = 0;
  460. bool isGpuImage = false;
  461. };
  462. assert(imageProperties.height == 200);
  463. assert(imageProperties.width == 192);
  464. assert(imageProperties.channels == 3);
  465. assert(imageProperties.isGpuImage == false);
  466. */
  467. /* const ImageProperties = StructType({
  468. width: Ref.types.uint,
  469. height: Ref.types.uint,
  470. channels: Ref.types.uint,
  471. isGpuImage: Ref.types.bool
  472. }); */
  473. const ip = new this.imageProperties({
  474. width: 0,
  475. height: 0,
  476. channels: 0,
  477. isGpuImage: false
  478. });
  479. this.lib.TFSDK__getImageProperties(
  480. this.ptr, ip.ref()
  481. );
  482. return ip;
  483. }
  484. /**
  485. * Obtain the 106 face landmarks.
  486. *
  487. * @param {object} faceBoxAndLandmarks FaceBoxAndLandmarks returned by {@link detectFaces()} or {@link detectLargestFace()}.
  488. * @returns {object} landmarks an array of 106 face landmark points.
  489. *
  490. * @returns {object} error code, see ErrorCode.
  491. */
  492. getFaceLandmarks(faceBoxAndLandmarks) {
  493. if (!this.dc.isObject(faceBoxAndLandmarks))
  494. return this.dc.throw(
  495. `faceBoxAndLandmarks: must be an object, ${faceBoxAndLandmarks} was given`
  496. )
  497. const result = this.lib.TFSDK__json_getFaceLandmarks(
  498. this.ptr,
  499. JSON.stringify(faceBoxAndLandmarks)
  500. );
  501. return JSON.parse(result);
  502. }
  503. /**
  504. * Extract the face feature vector from an aligned face image.
  505. *
  506. * @param {object} alignedFaceImage buffer returned by extractAlignedFace().
  507. * Face image must be have size of 112x112 pixels (default extractAlignedFace() margin and scale values).
  508. * @param {object} faceprint a Faceprint object which will contain
  509. * the face feature vector.
  510. *
  511. * @returns {object} error code, see ErrorCode.
  512. */
  513. getFaceFeatureVector(faceBoxAndLandmarks) {
  514. if (!this.dc.isObject(faceBoxAndLandmarks))
  515. return this.dc.throw(
  516. `faceBoxAndLandmarks: must be an object, ${faceBoxAndLandmarks} was given`
  517. )
  518. const result = this.lib.TFSDK__json_getFaceFeatureVector(
  519. this.ptr,
  520. JSON.stringify(faceBoxAndLandmarks)
  521. );
  522. return JSON.parse(result)
  523. }
  524. /**
  525. * Detect the largest face in the image and return its feature
  526. * vector.
  527. *
  528. * @returns {object} faceprint a Faceprint object which will contain
  529. * the face feature vector.
  530. * @returns {object} foundFace indicates if a face was detected in the image.
  531. * If no face was detected, then the faceprint will be empty.
  532. *
  533. * @returns {object} error code, see ErrorCode.
  534. */
  535. getLargestFaceFeatureVector() {
  536. const result = this.lib.TFSDK__json_getLargestFaceFeatureVector(
  537. this.ptr
  538. )
  539. return JSON.parse(result)
  540. }
  541. /**
  542. * Align the the detected face to be optimized for passing to
  543. * feature extraction. If using the face chip with Trueface algorithms (ex face recognition),
  544. * do not change the default margin and scale values.
  545. *
  546. * @param {object} faceBoxAndLandmarks the FaceBoxAndLandmarks returned
  547. * by detectLargestFace() or detectFaces().
  548. * @returns {object} faceImage the pointer to a uint8_t buffer of
  549. * 112x112x3 = 37632 bytes (when using default margins and scale).
  550. * The aligned face image is stored in this buffer.
  551. * The memory must be allocated by the user.
  552. * If using non-default margin and scale
  553. * (again, non-standard face chip sizes will not work with Trueface algorithms),
  554. * the faceImage will be of size:
  555. * width = int((112+marginLeft+marginRight)*scale),
  556. * height = int((112+marginTop+marginBottom)*scale),
  557. * and therefore the buffer size is computed as:
  558. * width * height * 3
  559. *
  560. * @param {number} marginLeft adds a margin to the left side of the face chip.
  561. * @param {number} marginTop adds a margin to the top side of the face chip.
  562. * @param {number} marginRight adds a margin to the right side of the face chip.
  563. * @param {number} marginBottom adds a margin to the bottom side of the face chip.
  564. * @param {number} scale changes the scale of the face chip.
  565. *
  566. * @returns error code, see ErrorCode.
  567. */
  568. extractAlignedFace(faceBoxAndLandmarks) {
  569. if (!this.dc.isObject(faceBoxAndLandmarks))
  570. return this.dc.throw(`faceBoxAndLandmarks: must be an object, ${faceBoxAndLandmarks} was given`)
  571. const result = this.lib.TFSDK__extractAlignedFace(
  572. this.ptr,
  573. JSON.stringify(faceBoxAndLandmarks)
  574. )
  575. return result
  576. }
  577. /**
  578. * Estimate the quality of the face image for recognition.
  579. *
  580. * @param {array} alignedFaceImage The array returned by extractAlignedFace().
  581. * @returns {number} quality a value between 0 to 1, 1 being prefect quality for recognition.
  582. * We suggest using a threshold of 0.999 as a filter for enrollment images.
  583. *
  584. * @returns {object} error code, see ErrorCode.
  585. */
  586. estimateFaceImageQuality(alignedFaceImage) {
  587. if (!this.dc.isArray(alignedFaceImage))
  588. return this.dc.throw(`alignedFaceImage: must be a array, ${alignedFaceImage} was given`);
  589. const arr = new this.IntArray(alignedFaceImage.length);
  590. for (const [i, v] of alignedFaceImage.entries()) arr[i] = v;
  591. return this.lib.TFSDK__estimateFaceImageQuality(
  592. this.ptr,
  593. arr
  594. )
  595. }
  596. /**
  597. *
  598. * Detect if there is a presentation attack attempt.
  599. * Must call checkSpoofImageFaceSize() on both input faces before calling this function.
  600. *
  601. * @param {object} nearFaceLandmarks The face landmarks of the near face, obtained by calling getFaceLandmarks().
  602. * @param {object} farFaceLandmarks The face landmarks of the far face, obtained by calling getFaceLandmarks().
  603. * @returns {number} spoofScore The output spoof score.
  604. * If the spoof score is above the threshold, then it is classified as a real face.
  605. * If the spoof score is below the threshold, then it is classified as a fake face.
  606. * @returns {boolean} spoofPrediction The predicted spoof result, using a spoofScore threshold of 1.05.
  607. *
  608. * @returns {object} error code, see ErrorCode.
  609. */
  610. detectActiveSpoof(nearFaceLandmarks, farFaceLandmarks) {
  611. if (!this.dc.isObject(nearFaceLandmarks))
  612. return this.dc.throw(`nearFaceLandmarks: must be an object, ${nearFaceLandmarks} was given`);
  613. if (!this.dc.isObject(farFaceLandmarks))
  614. return this.dc.throw(`nearFaceLandmarks: must be an object, ${farFaceLandmarks} was given`);
  615. const result = this.lib.TFSDK__json_detectActiveSpoof(
  616. this.ptr,
  617. JSON.stringify(nearFaceLandmarks),
  618. JSON.stringify(farFaceLandmarks)
  619. )
  620. return JSON.parse(result)
  621. }
  622. /**
  623. * Ensures that the face size meets the requirements for active spoof.
  624. * Must check return value of function!
  625. * Active spoof works by analyzing the way a persons face changes as they move closer to a camera.
  626. * The active spoof solution therefore expects the face a certain distance from the camera.
  627. * **In the far image, the face should be about 18 inches from the camera, while in the near image,
  628. * the face should be 7-8 inches from the camera.**
  629. * This function must be called before calling detectActiveSpoof().
  630. *
  631. * @param {object} faceBoxAndLandmarks The face on which to run active spoof detection.
  632. * @param {object} imageProperties The properties of the image, obtained from getImageProperties().
  633. * @param {object} activeSpoofStage The stage of the image, either near stage or far stage.
  634. *
  635. * @returns {object} error code, see ErrorCode.
  636. * If `ErrorCode::NO_ERROR` is returned, then the image is eligible for active spoof detection.
  637. * If `ErrorCode::FACE_TOO_CLOSE` or `ErrorCode::FACE_TOO_FAR` is returned, the image is not eligible for active spoof detection.
  638. *
  639. */
  640. checkSpoofImageFaceSize(faceBoxAndLandmarks, imageProperties) {
  641. if (!this.dc.isObject(faceBoxAndLandmarks))
  642. return this.dc.throw(`faceBoxAndLandmarks: must be an object, ${faceBoxAndLandmarks} was given`);
  643. if (!this.dc.isObject(imageProperties))
  644. return this.dc.throw(`imageProperties: must be an object, ${imageProperties} was given`);
  645. const result = this.lib.TFSDK__json_checkSpoofImageFaceSize(
  646. this.ptr,
  647. JSON.stringify(faceBoxAndLandmarks),
  648. JSON.stringify(imageProperties)
  649. )
  650. return JSON.parse(result)
  651. }
  652. /**
  653. * Detect whether the face in the image is wearing a mask or not
  654. *
  655. * @param {object} faceBoxAndLandmarks FaceBoxAndLandmarks returned by detectFaces() or detectLargestFace().
  656. * @returns {boolean} result The predicted MaskLabel for face image.
  657. *
  658. * @returns {object} error code, see ErrorCode.
  659. */
  660. detectMask(faceBoxAndLandmarks) {
  661. if (!this.dc.isObject(faceBoxAndLandmarks))
  662. return this.dc.throw(`faceBoxAndLandmarks: must be an object, ${faceBoxAndLandmarks} was given`);
  663. const result = this.lib.TFSDK__json_detectMask(
  664. this.ptr,
  665. JSON.stringify(faceBoxAndLandmarks)
  666. )
  667. return JSON.parse(result)
  668. }
  669. /**
  670. * Detect whether the face in the image is wearing any type of eye glasses or not
  671. *
  672. * @param {object} faceBoxAndLandmarks FaceBoxAndLandmarks returned by detectFaces() or detectLargestFace().
  673. * @param {boolean} result The predicted GlassesLabel for face image.
  674. * @param {score} glassesScore The glasses score for this image. This can be used for setting custom thresholds that work
  675. * better for the use case. By default, we use a glasses score greater than 0.0 to determine that glasses were detected.
  676. *
  677. * @returns {object} error code, see ErrorCode.
  678. */
  679. detectGlasses(faceBoxAndLandmarks) {
  680. if (!this.dc.isObject(faceBoxAndLandmarks))
  681. return this.dc.throw(`faceBoxAndLandmarks: must be an object, ${faceBoxAndLandmarks} was given`);
  682. const result = this.lib.TFSDK__json_detectGlasses(
  683. this.ptr,
  684. JSON.stringify(faceBoxAndLandmarks)
  685. )
  686. return JSON.parse(result)
  687. }
  688. };