Source: tfsdk.js

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