├── src ├── assets │ ├── .gitkeep │ └── sample1.jpg ├── app │ ├── app.component.scss │ ├── app.component.html │ ├── app.component.ts │ ├── app.component.spec.ts │ └── app.module.ts ├── favicon.ico ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── styles.scss ├── tsconfig.app.json ├── tslint.json ├── tsconfig.spec.json ├── index.html ├── main.ts ├── browserslist ├── test.ts ├── karma.conf.js └── polyfills.ts ├── .prettierignore ├── .bettercodehub.yml ├── docs ├── fonts │ ├── ionicons.eot │ ├── ionicons.ttf │ ├── ionicons.woff │ ├── ionicons.woff2 │ ├── roboto-v15-latin-300.eot │ ├── roboto-v15-latin-300.ttf │ ├── roboto-v15-latin-300.woff │ ├── roboto-v15-latin-700.eot │ ├── roboto-v15-latin-700.ttf │ ├── roboto-v15-latin-700.woff │ ├── roboto-v15-latin-300.woff2 │ ├── roboto-v15-latin-700.woff2 │ ├── roboto-v15-latin-regular.eot │ ├── roboto-v15-latin-regular.ttf │ ├── roboto-v15-latin-regular.woff │ └── roboto-v15-latin-regular.woff2 ├── images │ ├── favicon.ico │ ├── compodoc-vectorise.png │ ├── compodoc-vectorise-inverted.png │ └── coverage-badge-documentation.svg ├── styles │ ├── style.css │ ├── tablesort.css │ ├── original.css │ ├── reset.css │ ├── stripe.css │ ├── laravel.css │ ├── vagrant.css │ ├── readthedocs.css │ ├── material.css │ ├── postmark.css │ ├── bootstrap-card.css │ └── prism.css ├── js │ ├── compodoc.js │ ├── libs │ │ ├── tablesort.number.min.js │ │ ├── EventDispatcher.js │ │ ├── custom-elements-es5-adapter.js │ │ ├── innersvg.js │ │ ├── promise.min.js │ │ ├── tablesort.min.js │ │ └── bootstrap-native.js │ ├── tabs.js │ ├── lazy-load-graphs.js │ ├── search │ │ └── search-lunr.js │ ├── svg-pan-zoom.controls.js │ ├── sourceCode.js │ └── tree.js ├── modules.html ├── dependencies.html ├── license.html ├── interfaces │ └── Schema.html ├── miscellaneous │ └── typealiases.html ├── graph │ └── dependencies.svg ├── modules │ └── NgxFaceApiJsModule │ │ └── dependencies.svg └── index.html ├── media ├── how-it-works.png ├── ngx-face-api-js-demo-detect-faces.png └── ngx-face-api-js-demo-with-expressions-and-landmarks.png ├── projects └── ngx-face-api-js │ ├── src │ ├── lib │ │ ├── tokens │ │ │ ├── TaskTypeToken.ts │ │ │ ├── ModelsUrl.ts │ │ │ ├── FaceDetectionOptions.ts │ │ │ ├── FeatureToken.ts │ │ │ └── ModelToken.ts │ │ ├── components │ │ │ └── detection-result │ │ │ │ ├── detection-result.component.html │ │ │ │ ├── detection-result.component.scss │ │ │ │ ├── detection-result.component.spec.ts │ │ │ │ └── detection-result.component.ts │ │ ├── services │ │ │ ├── model-loader.service.spec.ts │ │ │ ├── face-detector.service.spec.ts │ │ │ ├── face-detector.service.ts │ │ │ └── model-loader.service.ts │ │ ├── directives │ │ │ ├── detect-all-faces-img.directive.ts │ │ │ ├── detect-all-faces-video.directive.ts │ │ │ ├── detect-all-faces-img.directive.spec.ts │ │ │ ├── detect-all-faces-video.directive.spec.ts │ │ │ ├── detect-dingle-face-img.directive.ts │ │ │ └── abbstract-detect.directive.ts │ │ ├── ngx-face-api-js.module.ts │ │ └── classes │ │ │ └── DetectTask.ts │ ├── public-api.ts │ └── test.ts │ ├── schematics │ ├── ng-add │ │ ├── Schema.ts │ │ ├── schema.json │ │ ├── addBrowserIgnorePackageSetting.ts │ │ ├── index.ts │ │ ├── addNgxFaceApiJsModule.ts │ │ ├── addCdkOverlayPrebuiltCssToAppStyles.ts │ │ └── index.spec.ts │ ├── .npmignore │ ├── migrations │ │ ├── migration.json │ │ └── update-0-1-0 │ │ │ ├── index.ts │ │ │ └── index.spec.ts │ ├── .gitignore │ ├── collection.json │ ├── util │ │ ├── installDependencies.ts │ │ ├── npmjs.ts │ │ └── addDependencies.ts │ └── README.md │ ├── tslint.json │ ├── tsconfig.spec.json │ ├── ng-package.json │ ├── tsconfig.schematics.json │ ├── tsconfig.lib.json │ ├── .gitignore │ ├── karma.conf.js │ └── package.json ├── .vscode └── settings.json ├── e2e ├── tsconfig.e2e.json ├── src │ ├── app.po.ts │ └── app.e2e-spec.ts └── protractor.conf.js ├── .editorconfig ├── prettier.config.js ├── tsconfig.json ├── .travis.yml ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── FUNDING.yml └── CODE_OF_CONDUCT.md ├── .gitignore ├── LICENSE ├── tslint.json ├── package.json ├── README.md └── angular.json /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package.json 2 | dist 3 | coverage 4 | docs 5 | -------------------------------------------------------------------------------- /.bettercodehub.yml: -------------------------------------------------------------------------------- 1 | component_depth: 1 2 | languages: 3 | - typescript 4 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /docs/fonts/ionicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/fonts/ionicons.eot -------------------------------------------------------------------------------- /docs/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/fonts/ionicons.ttf -------------------------------------------------------------------------------- /docs/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/fonts/ionicons.woff -------------------------------------------------------------------------------- /docs/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/images/favicon.ico -------------------------------------------------------------------------------- /media/how-it-works.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/media/how-it-works.png -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/tokens/TaskTypeToken.ts: -------------------------------------------------------------------------------- 1 | export type TaskTypeToken = 'all' | 'single'; 2 | -------------------------------------------------------------------------------- /src/assets/sample1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/src/assets/sample1.jpg -------------------------------------------------------------------------------- /docs/fonts/ionicons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/fonts/ionicons.woff2 -------------------------------------------------------------------------------- /projects/ngx-face-api-js/schematics/ng-add/Schema.ts: -------------------------------------------------------------------------------- 1 | export interface Schema { 2 | project: string; 3 | } 4 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/schematics/.npmignore: -------------------------------------------------------------------------------- 1 | # Ignores TypeScript files, but keeps definitions. 2 | *.ts 3 | !*.d.ts 4 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/components/detection-result/detection-result.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/images/compodoc-vectorise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/images/compodoc-vectorise.png -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-300.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/fonts/roboto-v15-latin-300.eot -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-300.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/fonts/roboto-v15-latin-300.ttf -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-300.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/fonts/roboto-v15-latin-300.woff -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-700.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/fonts/roboto-v15-latin-700.eot -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-700.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/fonts/roboto-v15-latin-700.ttf -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-700.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/fonts/roboto-v15-latin-700.woff -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-300.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/fonts/roboto-v15-latin-300.woff2 -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/fonts/roboto-v15-latin-700.woff2 -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/fonts/roboto-v15-latin-regular.eot -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/fonts/roboto-v15-latin-regular.ttf -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/fonts/roboto-v15-latin-regular.woff -------------------------------------------------------------------------------- /docs/fonts/roboto-v15-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/fonts/roboto-v15-latin-regular.woff2 -------------------------------------------------------------------------------- /docs/images/compodoc-vectorise-inverted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/docs/images/compodoc-vectorise-inverted.png -------------------------------------------------------------------------------- /media/ngx-face-api-js-demo-detect-faces.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/media/ngx-face-api-js-demo-detect-faces.png -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/components/detection-result/detection-result.component.scss: -------------------------------------------------------------------------------- 1 | canvas { 2 | width: 100%; 3 | height: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | @import '~@angular/cdk/overlay-prebuilt.css'; -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "tslint.exclude": ["**/dist/**", "**/node_modules/**"], 3 | "markdownlint.config": { 4 | "default": true, 5 | "MD026": false 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /media/ngx-face-api-js-demo-with-expressions-and-landmarks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamiazya/ngx-face-api-js/HEAD/media/ngx-face-api-js-demo-with-expressions-and-landmarks.png -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/tokens/ModelsUrl.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from '@angular/core'; 2 | export const ModelsUrl = new InjectionToken( 3 | 'ngx-face-api-js.models-url', 4 | ); 5 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": [] 6 | }, 7 | "exclude": ["test.ts", "**/*.spec.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [true, "attribute", "app", "camelCase"], 5 | "component-selector": [true, "element", "app", "kebab-case"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /docs/styles/style.css: -------------------------------------------------------------------------------- 1 | @import "./reset.css"; 2 | @import "./bootstrap.min.css"; 3 | @import "./bootstrap-card.css"; 4 | @import "./prism.css"; 5 | @import "./ionicons.min.css"; 6 | @import "./compodoc.css"; 7 | @import "./tablesort.css"; 8 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tslint.json", 3 | "rules": { 4 | "directive-selector": [true, "attribute", "", "camelCase"], 5 | "component-selector": [true, "element", "", "kebab-case"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": ["jasmine", "jasminewd2", "node"] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/schematics/migrations/migration.json: -------------------------------------------------------------------------------- 1 | { 2 | "schematics": { 3 | "update-0-1-0": { 4 | "version": "0.1", 5 | "factory": "./update-0-1-0/index", 6 | "description": "updates to v0.1" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "types": ["jasmine", "node"] 6 | }, 7 | "files": ["test.ts", "polyfills.ts"], 8 | "include": ["**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/tokens/FaceDetectionOptions.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from '@angular/core'; 2 | import * as faceapi from 'face-api.js'; 3 | 4 | export const FaceDetectionOptions = new InjectionToken< 5 | faceapi.FaceDetectionOptions 6 | >('ngx-face-api-js.face-detection-options'); 7 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/schematics/.gitignore: -------------------------------------------------------------------------------- 1 | # Outputs 2 | **/*.js 3 | **/*.js.map 4 | **/*.d.ts 5 | 6 | # IDEs 7 | .idea/ 8 | jsconfig.json 9 | .vscode/ 10 | 11 | # Misc 12 | node_modules/ 13 | npm-debug.log* 14 | yarn-error.log* 15 | 16 | # Mac OSX Finder files. 17 | **/.DS_Store 18 | .DS_Store 19 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": ["jasmine", "node"], 6 | "skipLibCheck": true 7 | }, 8 | "files": ["src/test.ts"], 9 | "include": ["**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/schematics/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json", 3 | "schematics": { 4 | "ng-add": { 5 | "description": "Add ngx-face-api-js Module to project.", 6 | "factory": "./ng-add/index#ngAdd", 7 | "schema": "./ng-add/schema.json" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/ngx-face-api-js", 4 | "lib": { 5 | "entryFile": "src/public-api.ts", 6 | "umdModuleIds": { 7 | "face-api.js": "face-api.js" 8 | } 9 | }, 10 | "whitelistedNonPeerDependencies": ["angular", "face-api.js"] 11 | } 12 | -------------------------------------------------------------------------------- /docs/js/compodoc.js: -------------------------------------------------------------------------------- 1 | var compodoc = { 2 | EVENTS: { 3 | READY: 'compodoc.ready', 4 | SEARCH_READY: 'compodoc.search.ready' 5 | } 6 | }; 7 | 8 | Object.assign( compodoc, EventDispatcher.prototype ); 9 | 10 | document.addEventListener('DOMContentLoaded', function() { 11 | compodoc.dispatchEvent({ 12 | type: compodoc.EVENTS.READY 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NgxFaceApiJs 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 80, 3 | tabWidth: 2, 4 | useTabs: false, 5 | semi: true, 6 | singleQuote: true, 7 | trailingComma: 'all', 8 | bracketSpacing: true, 9 | jsxBracketSameLine: false, 10 | arrowParens: 'avoid', 11 | rangeStart: 0, 12 | rangeEnd: Infinity, 13 | requirePragma: false, 14 | insertPragma: false, 15 | proseWrap: 'preserve', 16 | }; 17 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic() 12 | .bootstrapModule(AppModule) 13 | .catch(err => console.error(err)); 14 | -------------------------------------------------------------------------------- /src/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # 5 | # For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed 6 | 7 | > 0.5% 8 | last 2 versions 9 | Firefox ESR 10 | not dead 11 | not IE 9-11 -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/tokens/FeatureToken.ts: -------------------------------------------------------------------------------- 1 | export type FeatureToken = 2 | | 'expressions' 3 | | 'landmarks' 4 | | 'descriptors' 5 | | 'ageAndGender'; 6 | 7 | export const ExpressionsFeatureToken: FeatureToken = 'expressions'; 8 | export const LandmarksFeatureToken: FeatureToken = 'landmarks'; 9 | export const DescriptorsFeatureToken: FeatureToken = 'descriptors'; 10 | export const AgeAndGenderToken: FeatureToken = 'ageAndGender'; 11 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/schematics/util/installDependencies.ts: -------------------------------------------------------------------------------- 1 | import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics'; 2 | import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks'; 3 | export function installDependencies(): Rule { 4 | return (host: Tree, context: SchematicContext) => { 5 | context.addTask(new NodePackageInstallTask()); 6 | context.logger.info('✅️ Dependencies installed'); 7 | return host; 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 |

ngx-face-api-js

2 | 3 |

Detect Face

4 |
5 | 6 |
7 |

With Expressions and Landmarks

8 |
9 | 15 |
16 |

Select File

17 |
18 | 19 |
20 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/schematics/migrations/update-0-1-0/index.ts: -------------------------------------------------------------------------------- 1 | import { Rule, chain } from '@angular-devkit/schematics'; 2 | import { addDependencies } from '../../util/addDependencies'; 3 | import { installDependencies } from '../../util/installDependencies'; 4 | 5 | export default function(): Rule { 6 | return chain([ 7 | addDependencies({ 8 | packageName: 'face-api.js', 9 | version: '~0.20.0', 10 | overwrite: true, 11 | }), 12 | installDependencies(), 13 | ]); 14 | } 15 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/schematics/ng-add/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "id": "angular-firebase-schematic-ng-add", 4 | "title": "ngx-face-api-js-schematics ng-add schematic", 5 | "type": "object", 6 | "properties": { 7 | "project": { 8 | "type": "string", 9 | "description": "The name of the project.", 10 | "$default": { 11 | "$source": "projectName" 12 | } 13 | } 14 | }, 15 | "required": [], 16 | "additionalProperties": false 17 | } 18 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.scss'], 7 | }) 8 | export class AppComponent { 9 | imageSrc = '/assets/sample1.jpg'; 10 | 11 | selectFile(event: any) { 12 | const file = event.target.files.item(0); 13 | const reader = new FileReader(); 14 | reader.onload = (e: any) => (this.imageSrc = e.target.result); 15 | reader.readAsDataURL(file); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/public-api.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Public API Surface of ngx-face-api-js 3 | */ 4 | 5 | export * from './lib/classes/DetectTask'; 6 | export * from './lib/tokens/FaceDetectionOptions'; 7 | export * from './lib/tokens/FeatureToken'; 8 | export * from './lib/tokens/ModelToken'; 9 | export * from './lib/tokens/ModelsUrl'; 10 | export * from './lib/tokens/TaskTypeToken'; 11 | export * from './lib/services/face-detector.service'; 12 | export * from './lib/services/model-loader.service'; 13 | export * from './lib/ngx-face-api-js.module'; 14 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async(() => { 6 | TestBed.configureTestingModule({ 7 | declarations: [AppComponent], 8 | }).compileComponents(); 9 | })); 10 | 11 | it('should create the app', () => { 12 | const fixture = TestBed.createComponent(AppComponent); 13 | const app = fixture.debugElement.componentInstance; 14 | expect(app).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /docs/js/libs/tablesort.number.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * tablesort v5.1.0 (2018-09-14) 3 | * http://tristen.ca/tablesort/demo/ 4 | * Copyright (c) 2018 ; Licensed MIT 5 | */ 6 | !function(){var a=function(a){return a.replace(/[^\-?0-9.]/g,"")},b=function(a,b){return a=parseFloat(a),b=parseFloat(b),a=isNaN(a)?0:a,b=isNaN(b)?0:b,a-b};Tablesort.extend("number",function(a){return a.match(/^[-+]?[£\x24Û¢´€]?\d+\s*([,\.]\d{0,2})/)||a.match(/^[-+]?\d+\s*([,\.]\d{0,2})?[£\x24Û¢´€]/)||a.match(/^[-+]?(\d)*-?([,\.]){0,1}-?(\d)+([E,e][\-+][\d]+)?%?$/)},function(c,d){return c=a(c),d=a(d),b(d,c)})}(); -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | 4 | import { AppComponent } from './app.component'; 5 | import { NgxFaceApiJsModule } from 'ngx-face-api-js'; 6 | 7 | @NgModule({ 8 | declarations: [AppComponent], 9 | imports: [ 10 | BrowserModule, 11 | NgxFaceApiJsModule.forRoot({ 12 | modelsUrl: 13 | 'https://raw.githubusercontent.com/justadudewhohacks/face-api.js/master/weights', 14 | }), 15 | ], 16 | providers: [], 17 | bootstrap: [AppComponent], 18 | }) 19 | export class AppModule {} 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "module": "es2015", 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "importHelpers": true, 13 | "target": "es5", 14 | "typeRoots": ["node_modules/@types"], 15 | "lib": ["es2018", "dom"], 16 | "paths": { 17 | "ngx-face-api-js": ["dist/ngx-face-api-js"], 18 | "ngx-face-api-js/*": ["dist/ngx-face-api-js/*"] 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/services/model-loader.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ModelLoaderService } from './model-loader.service'; 4 | import { NgxFaceApiJsModule } from '../ngx-face-api-js.module'; 5 | 6 | describe('ModelLoaderService', () => { 7 | beforeEach(() => 8 | TestBed.configureTestingModule({ 9 | imports: [NgxFaceApiJsModule.forRoot({ modelsUrl: '/' })], 10 | }), 11 | ); 12 | 13 | it('should be created', () => { 14 | const service: ModelLoaderService = TestBed.get(ModelLoaderService); 15 | expect(service).toBeTruthy(); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/services/face-detector.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { FaceDetectorService } from './face-detector.service'; 4 | import { NgxFaceApiJsModule } from '../ngx-face-api-js.module'; 5 | 6 | describe('FaceDetectorService', () => { 7 | beforeEach(() => 8 | TestBed.configureTestingModule({ 9 | imports: [NgxFaceApiJsModule.forRoot({ modelsUrl: '/' })], 10 | }), 11 | ); 12 | 13 | it('should be created', () => { 14 | const service: FaceDetectorService = TestBed.get(FaceDetectorService); 15 | expect(service).toBeTruthy(); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | - "10" 5 | 6 | # safelist 7 | branches: 8 | only: 9 | - master 10 | 11 | before_install: 12 | # yarn 13 | - curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.13.0 14 | - export PATH="$HOME/.yarn/bin:$PATH" 15 | 16 | script: 17 | - yarn 18 | - yarn lint 19 | - yarn test:all 20 | - yarn build:lib 21 | - yarn build:lib:schematics 22 | 23 | after_success: yarn report-coverage 24 | 25 | addons: 26 | apt: 27 | sources: 28 | - google-chrome 29 | packages: 30 | - google-chrome-stable 31 | 32 | dist: trusty 33 | cache: 34 | yarn: true 35 | directories: 36 | - node_modules 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/schematics/ng-add/addBrowserIgnorePackageSetting.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Rule, 3 | SchematicContext, 4 | Tree, 5 | SchematicsException, 6 | } from '@angular-devkit/schematics'; 7 | export function addBrowserIgnorePackageSetting(): Rule { 8 | return (host: Tree, _: SchematicContext) => { 9 | const buf = host.read('package.json'); 10 | if (!buf) { 11 | throw new SchematicsException('cannot find package.json'); 12 | } 13 | const content = JSON.parse(buf.toString('utf-8')); 14 | content.browser = { 15 | ...content.browser, 16 | fs: false, 17 | crypto: false, 18 | }; 19 | host.overwrite('package.json', JSON.stringify(content, null, 2)); 20 | return host; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/tsconfig.schematics.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "tsconfig", 4 | "lib": ["es2018", "dom"], 5 | "declaration": true, 6 | "module": "commonjs", 7 | "moduleResolution": "node", 8 | "noEmitOnError": true, 9 | "noFallthroughCasesInSwitch": true, 10 | "noImplicitAny": true, 11 | "noImplicitThis": true, 12 | "noUnusedParameters": true, 13 | "noUnusedLocals": true, 14 | "rootDir": "schematics", 15 | "skipDefaultLibCheck": true, 16 | "skipLibCheck": true, 17 | "sourceMap": true, 18 | "strictNullChecks": true, 19 | "target": "es6", 20 | "types": ["jasmine", "node"] 21 | }, 22 | "include": ["schematics/**/*"], 23 | "exclude": [] 24 | } 25 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false, 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/tokens/ModelToken.ts: -------------------------------------------------------------------------------- 1 | export type ModelToken = 2 | | 'SsdMobilenetv1Model' 3 | | 'MtcnnModel' 4 | | 'FaceExpressionModel' 5 | | 'FaceLandmarkModel' 6 | | 'FaceRecognitionModel' 7 | | 'TinyFaceDetectorModel' 8 | | 'AgeAndGenderModel'; 9 | 10 | export const SsdMobilenetv1Model: ModelToken = 'SsdMobilenetv1Model'; 11 | export const MtcnnModel: ModelToken = 'MtcnnModel'; 12 | export const FaceExpressionModel: ModelToken = 'FaceExpressionModel'; 13 | export const FaceLandmarkModel: ModelToken = 'FaceLandmarkModel'; 14 | export const FaceRecognitionModel: ModelToken = 'FaceRecognitionModel'; 15 | export const TinyFaceDetectorModel: ModelToken = 'TinyFaceDetectorModel'; 16 | export const AgeAndGenderModel: ModelToken = 'AgeAndGenderModel'; 17 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: kamiazya # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: kamiazya # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /docs/js/libs/EventDispatcher.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | var EventDispatcher=function(){};Object.assign(EventDispatcher.prototype,{addEventListener:function(i,t){void 0===this._listeners&&(this._listeners={});var e=this._listeners;void 0===e[i]&&(e[i]=[]),-1===e[i].indexOf(t)&&e[i].push(t)},hasEventListener:function(i,t){if(void 0===this._listeners)return!1;var e=this._listeners;return void 0!==e[i]&&-1!==e[i].indexOf(t)},removeEventListener:function(i,t){if(void 0!==this._listeners){var e=this._listeners[i];if(void 0!==e){var s=e.indexOf(t);-1!==s&&e.splice(s,1)}}},dispatchEvent:function(i){if(void 0!==this._listeners){var t=this._listeners[i.type];if(void 0!==t){i.target=this;var e=[],s=0,n=t.length;for(s=0;s { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to ngx-face-api-demo-app!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser 19 | .manage() 20 | .logs() 21 | .get(logging.Type.BROWSER); 22 | expect(logs).not.toContain( 23 | jasmine.objectContaining({ 24 | level: logging.Level.SEVERE, 25 | } as logging.Entry), 26 | ); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'core-js/es7/reflect'; 4 | import 'zone.js/dist/zone'; 5 | import 'zone.js/dist/zone-testing'; 6 | import { getTestBed } from '@angular/core/testing'; 7 | import { 8 | BrowserDynamicTestingModule, 9 | platformBrowserDynamicTesting, 10 | } from '@angular/platform-browser-dynamic/testing'; 11 | 12 | declare const require: any; 13 | 14 | // First, initialize the Angular testing environment. 15 | getTestBed().initTestEnvironment( 16 | BrowserDynamicTestingModule, 17 | platformBrowserDynamicTesting(), 18 | ); 19 | // Then we find all the tests. 20 | const context = require.context('./', true, /\.spec\.ts$/); 21 | // And load the modules. 22 | context.keys().map(context); 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events.json 15 | speed-measure-plugin.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/lib", 5 | "target": "es2015", 6 | "module": "es2015", 7 | "moduleResolution": "node", 8 | "declaration": true, 9 | "sourceMap": true, 10 | "inlineSources": true, 11 | "emitDecoratorMetadata": true, 12 | "experimentalDecorators": true, 13 | "importHelpers": true, 14 | "types": [], 15 | "lib": ["dom", "es2018"] 16 | }, 17 | "angularCompilerOptions": { 18 | "annotateForClosureCompiler": true, 19 | "skipTemplateCodegen": true, 20 | "strictMetadataEmit": true, 21 | "fullTemplateTypeCheck": true, 22 | "strictInjectionParameters": true, 23 | "enableResourceInlining": true 24 | }, 25 | "exclude": ["src/test.ts", "**/*.spec.ts"] 26 | } 27 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/directives/detect-all-faces-img.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, Input, ElementRef, Injector } from '@angular/core'; 2 | import { Overlay } from '@angular/cdk/overlay'; 3 | import { TaskTypeToken } from '../tokens/TaskTypeToken'; 4 | import { FeatureToken } from '../tokens/FeatureToken'; 5 | import { AbstractDetectDirective } from './abbstract-detect.directive'; 6 | @Directive({ 7 | selector: 'img[allFaces]', 8 | exportAs: 'faces', 9 | }) 10 | export class DetectAllFacesImgDirective extends AbstractDetectDirective { 11 | @Input() 12 | public with: FeatureToken[] = []; 13 | constructor( 14 | el: ElementRef, 15 | overlay: Overlay, 16 | injector: Injector, 17 | ) { 18 | super(el, overlay, injector); 19 | } 20 | protected type: TaskTypeToken = 'all'; 21 | protected stream = false; 22 | } 23 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events.json 15 | speed-measure-plugin.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/directives/detect-all-faces-video.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, Input, ElementRef, Injector } from '@angular/core'; 2 | import { Overlay } from '@angular/cdk/overlay'; 3 | import { TaskTypeToken } from '../tokens/TaskTypeToken'; 4 | import { FeatureToken } from '../tokens/FeatureToken'; 5 | import { AbstractDetectDirective } from './abbstract-detect.directive'; 6 | @Directive({ 7 | selector: 'video[allFaces]', 8 | exportAs: 'faces', 9 | }) 10 | export class DetectAllFacesVideoDirective extends AbstractDetectDirective { 11 | @Input() 12 | public with: FeatureToken[] = []; 13 | constructor( 14 | el: ElementRef, 15 | overlay: Overlay, 16 | injector: Injector, 17 | ) { 18 | super(el, overlay, injector); 19 | } 20 | protected type: TaskTypeToken = 'all'; 21 | protected stream = true; 22 | } 23 | -------------------------------------------------------------------------------- /docs/js/tabs.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | var tabs = document.getElementsByClassName('nav-tabs'), 3 | updateAddress = function(e) { 4 | if(history.pushState && e.target.dataset.link) { 5 | history.pushState(null, null, '#' + e.target.dataset.link); 6 | } 7 | }; 8 | if (tabs.length > 0) { 9 | tabs = tabs[0].querySelectorAll('li'); 10 | for (var i = 0; i < tabs.length; i++) { 11 | tabs[i].addEventListener('click', updateAddress); 12 | var linkTag = tabs[i].querySelector('a'); 13 | if (location.hash !== '') { 14 | var currentHash = location.hash.substr(1); 15 | if (currentHash === linkTag.dataset.link) { 16 | linkTag.click(); 17 | } 18 | } 19 | } 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /docs/images/coverage-badge-documentation.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | documentation 7 | 0% 8 | 9 | 10 | -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: ['./src/**/*.e2e-spec.ts'], 9 | capabilities: { 10 | browserName: 'chrome', 11 | }, 12 | chromeOptions: { 13 | args: ['--headless'], 14 | }, 15 | directConnect: true, 16 | baseUrl: 'http://localhost:4200/', 17 | framework: 'jasmine', 18 | jasmineNodeOpts: { 19 | showColors: true, 20 | defaultTimeoutInterval: 30000, 21 | print: function() {}, 22 | }, 23 | onPrepare() { 24 | require('ts-node').register({ 25 | project: require('path').join(__dirname, './tsconfig.e2e.json'), 26 | }); 27 | jasmine 28 | .getEnv() 29 | .addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/directives/detect-all-faces-img.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, ComponentFixture } from '@angular/core/testing'; 2 | import { Component } from '@angular/core'; 3 | import { NgxFaceApiJsModule } from '../ngx-face-api-js.module'; 4 | 5 | // Simple test component that will not in the actual app 6 | @Component({ 7 | template: '', 8 | }) 9 | class TestComponent {} 10 | 11 | describe('DetectAllFacesDirective', () => { 12 | let component: TestComponent; 13 | let fixture: ComponentFixture; 14 | 15 | beforeEach(() => { 16 | TestBed.configureTestingModule({ 17 | imports: [NgxFaceApiJsModule.forRoot({ modelsUrl: '/' })], 18 | declarations: [TestComponent], 19 | }); 20 | 21 | fixture = TestBed.createComponent(TestComponent); 22 | component = fixture.componentInstance; 23 | }); 24 | 25 | it('should create an instance', () => { 26 | expect(component).toBeDefined(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/directives/detect-all-faces-video.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, ComponentFixture } from '@angular/core/testing'; 2 | import { Component } from '@angular/core'; 3 | import { NgxFaceApiJsModule } from '../ngx-face-api-js.module'; 4 | 5 | // Simple test component that will not in the actual app 6 | @Component({ 7 | template: '', 8 | }) 9 | class TestComponent {} 10 | 11 | describe('DetectAllFacesDirective', () => { 12 | let component: TestComponent; 13 | let fixture: ComponentFixture; 14 | 15 | beforeEach(() => { 16 | TestBed.configureTestingModule({ 17 | imports: [NgxFaceApiJsModule.forRoot({ modelsUrl: '/' })], 18 | declarations: [TestComponent], 19 | }); 20 | 21 | fixture = TestBed.createComponent(TestComponent); 22 | component = fixture.componentInstance; 23 | }); 24 | 25 | it('should create an instance', () => { 26 | expect(component).toBeDefined(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /docs/js/libs/custom-elements-es5-adapter.js: -------------------------------------------------------------------------------- 1 | /** 2 | @license @nocompile 3 | Copyright (c) 2018 The Polymer Project Authors. All rights reserved. 4 | This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt 5 | The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt 6 | The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt 7 | Code distributed by Google as part of the polymer project is also 8 | subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt 9 | */ 10 | (function () { 11 | 'use strict'; 12 | 13 | (function(){if(void 0===window.Reflect||void 0===window.customElements||window.customElements.hasOwnProperty('polyfillWrapFlushCallback'))return;const a=HTMLElement;window.HTMLElement=function(){return Reflect.construct(a,[],this.constructor)},HTMLElement.prototype=a.prototype,HTMLElement.prototype.constructor=HTMLElement,Object.setPrototypeOf(HTMLElement,a);})(); 14 | 15 | }()); 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | 28 | - OS: [e.g. iOS] 29 | - Browser [e.g. chrome, safari] 30 | - Version [e.g. 22] 31 | 32 | **Smartphone (please complete the following information):** 33 | 34 | - Device: [e.g. iPhone6] 35 | - OS: [e.g. iOS8.1] 36 | - Browser [e.g. stock browser, safari] 37 | - Version [e.g. 22] 38 | 39 | **Additional context** 40 | Add any other context about the problem here. 41 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting, 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | import { NgxFaceApiJsModule } from 'ngx-face-api-js'; 10 | 11 | declare const require: any; 12 | 13 | // First, initialize the Angular testing environment. 14 | getTestBed().initTestEnvironment( 15 | BrowserDynamicTestingModule, 16 | platformBrowserDynamicTesting(), 17 | ); 18 | 19 | beforeEach(() => { 20 | getTestBed().configureTestingModule({ 21 | imports: [ 22 | NgxFaceApiJsModule.forRoot({ 23 | modelsUrl: 24 | 'https://raw.githubusercontent.com/justadudewhohacks/face-api.js/master/weights', 25 | }), 26 | ], 27 | }); 28 | }); 29 | 30 | // Then we find all the tests. 31 | const context = require.context('./', true, /\.spec\.ts$/); 32 | // And load the modules. 33 | context.keys().map(context); 34 | -------------------------------------------------------------------------------- /docs/styles/original.css: -------------------------------------------------------------------------------- 1 | .navbar-default .navbar-brand, .menu ul.list li.title { 2 | font-weight: bold; 3 | color: #3c3c3c; 4 | padding-bottom: 5px; 5 | } 6 | 7 | .menu ul.list li a[data-type="chapter-link"], .menu ul.list li.chapter .simple { 8 | font-weight: bold; 9 | border-top: 1px solid #ddd; 10 | border-bottom: 1px solid #ddd; 11 | font-size: 14px; 12 | } 13 | 14 | .menu ul.list li a[href="./routes.html"] { 15 | border-bottom: none; 16 | } 17 | 18 | .menu ul.list > li:nth-child(2) { 19 | display: none; 20 | } 21 | 22 | .menu ul.list li.chapter ul.links { 23 | background: #fff; 24 | padding-left: 0; 25 | } 26 | 27 | .menu ul.list li.chapter ul.links li { 28 | border-bottom: 1px solid #ddd; 29 | padding-left: 20px; 30 | } 31 | 32 | .menu ul.list li.chapter ul.links li:last-child { 33 | border-bottom: none; 34 | } 35 | 36 | .menu ul.list li a.active { 37 | color: inherit; 38 | font-weight: bold; 39 | } 40 | 41 | #book-search-input { 42 | margin-bottom: 0; 43 | border-bottom: none; 44 | } 45 | .menu ul.list li.divider { 46 | margin: 0; 47 | } 48 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/directives/detect-dingle-face-img.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, Input, ElementRef, Injector, OnInit } from '@angular/core'; 2 | import { Overlay } from '@angular/cdk/overlay'; 3 | import { TaskTypeToken } from '../tokens/TaskTypeToken'; 4 | import { FeatureToken } from '../tokens/FeatureToken'; 5 | import { DetectTask } from '../classes/DetectTask'; 6 | import { AbstractDetectDirective } from './abbstract-detect.directive'; 7 | @Directive({ 8 | selector: 'img[singleFace]', 9 | exportAs: 'face', 10 | }) 11 | export class DetectSingleFaceImgDirective extends AbstractDetectDirective 12 | implements OnInit { 13 | @Input() 14 | public with: FeatureToken[] = []; 15 | constructor( 16 | el: ElementRef, 17 | overlay: Overlay, 18 | injector: Injector, 19 | ) { 20 | super(el, overlay, injector); 21 | } 22 | protected type: TaskTypeToken = 'single'; 23 | protected stream = false; 24 | ngOnInit() { 25 | this.task = new DetectTask({ 26 | type: this.type, 27 | tokens: this.with, 28 | realtime: this.stream, 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2019 Yuki Yamazaki 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma'), 14 | ], 15 | client: { 16 | clearContext: false, // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../../coverage/ngx-face-api-js'), 20 | reports: ['html', 'lcovonly'], 21 | fixWebpackSourcePaths: true, 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true, 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma'), 14 | ], 15 | client: { 16 | clearContext: false, // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage/ngx-face-api-demo-app'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true, 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true, 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/schematics/ng-add/index.ts: -------------------------------------------------------------------------------- 1 | import { Rule, chain } from '@angular-devkit/schematics'; 2 | import { Schema } from './Schema'; 3 | import { NodeDependencyType } from '@schematics/angular/utility/dependencies'; 4 | import { addDependencies } from '../util/addDependencies'; 5 | import { installDependencies } from '../util/installDependencies'; 6 | import { addBrowserIgnorePackageSetting } from './addBrowserIgnorePackageSetting'; 7 | import { addNgxFaceApiJsModule } from './addNgxFaceApiJsModule'; 8 | import { addCdkOverlayPrebuiltCssToAppStyles } from './addCdkOverlayPrebuiltCssToAppStyles'; 9 | 10 | // You don't have to export the function as default. You can also have more than one rule factory 11 | // per file. 12 | export function ngAdd(options: Schema): Rule { 13 | return chain([ 14 | addDependencies({ 15 | packageName: 'face-api.js', 16 | version: '~0.20.0', 17 | }), 18 | addDependencies({ 19 | packageName: '@angular/cdk', 20 | type: NodeDependencyType.Dev, 21 | }), 22 | installDependencies(), 23 | addBrowserIgnorePackageSetting(), 24 | addCdkOverlayPrebuiltCssToAppStyles(options), 25 | addNgxFaceApiJsModule(options), 26 | ]); 27 | } 28 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/schematics/util/npmjs.ts: -------------------------------------------------------------------------------- 1 | import { get } from 'http'; 2 | 3 | export interface NpmRegistryPackage { 4 | name: string; 5 | version: string; 6 | } 7 | 8 | export function getLatestNodeVersion( 9 | packageName: string, 10 | ): Promise { 11 | const DEFAULT_VERSION = 'latest'; 12 | 13 | return new Promise(resolve => { 14 | return get(`http://registry.npmjs.org/${packageName}`, res => { 15 | let rawData = ''; 16 | res.on('data', chunk => (rawData += chunk)); 17 | res.on('end', () => { 18 | try { 19 | const response = JSON.parse(rawData); 20 | const latestVersion = 21 | (response && 22 | response['dist-tags'] && 23 | response['dist-tags'].latest) || 24 | {}; 25 | 26 | resolve(buildPackage(response.name || packageName, latestVersion)); 27 | } catch (e) { 28 | resolve(buildPackage(packageName)); 29 | } 30 | }); 31 | }).on('error', () => resolve(buildPackage(packageName))); 32 | }); 33 | 34 | function buildPackage( 35 | name: string, 36 | version: string = DEFAULT_VERSION, 37 | ): NpmRegistryPackage { 38 | return { name, version }; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /docs/styles/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | /* HTML5 display-role reset for older browsers */ 27 | article, aside, details, figcaption, figure, 28 | footer, header, hgroup, menu, nav, section { 29 | display: block; 30 | } 31 | body { 32 | line-height: 1; 33 | } 34 | ol, ul { 35 | list-style: none; 36 | } 37 | blockquote, q { 38 | quotes: none; 39 | } 40 | blockquote:before, blockquote:after, 41 | q:before, q:after { 42 | content: ''; 43 | content: none; 44 | } 45 | table { 46 | border-collapse: collapse; 47 | border-spacing: 0; 48 | } -------------------------------------------------------------------------------- /docs/js/libs/innersvg.js: -------------------------------------------------------------------------------- 1 | /** 2 | * innerHTML property for SVGElement 3 | * Copyright(c) 2010, Jeff Schiller 4 | * 5 | * Licensed under the Apache License, Version 2 6 | * 7 | * Minor modifications by Chris Price to only polyfill when required. 8 | */ 9 | !function(e){if(e&&!("innerHTML"in e.prototype)){var t=function(e,r){var i=e.nodeType;if(3==i)r.push(e.textContent.replace(/&/,"&").replace(/",">"));else if(1==i){if(r.push("<",e.tagName),e.hasAttributes())for(var n=e.attributes,s=0,o=n.length;s");for(var h=e.childNodes,s=0,o=h.length;s")}else r.push("/>")}else{if(8!=i)throw"Error serializing XML. Unhandled node of type: "+i;r.push("\x3c!--",e.nodeValue,"--\x3e")}};Object.defineProperty(e.prototype,"innerHTML",{get:function(){for(var e=[],r=this.firstChild;r;)t(r,e),r=r.nextSibling;return e.join("")},set:function(e){for(;this.firstChild;)this.removeChild(this.firstChild);try{var t=new DOMParser;t.async=!1,sXML=""+e+"";for(var r=t.parseFromString(sXML,"text/xml").documentElement.firstChild;r;)this.appendChild(this.ownerDocument.importNode(r,!0)),r=r.nextSibling}catch(e){throw new Error("Error parsing XML string")}}})}}((0,eval)("this").SVGElement); -------------------------------------------------------------------------------- /docs/styles/stripe.css: -------------------------------------------------------------------------------- 1 | .navbar-default .navbar-brand { 2 | color: #0099e5; 3 | } 4 | 5 | .menu ul.list li a[data-type="chapter-link"], .menu ul.list li.chapter .simple { 6 | color: #939da3; 7 | text-transform: uppercase; 8 | } 9 | 10 | .content h1, .content h2, .content h3, .content h4, .content h5 { 11 | color: #292e31; 12 | font-weight: normal; 13 | } 14 | 15 | .content { 16 | color: #4c555a; 17 | } 18 | 19 | .menu ul.list li.title { 20 | padding: 5px 0; 21 | } 22 | 23 | a { 24 | color: #0099e5; 25 | text-decoration: none; 26 | } 27 | a:hover { 28 | color: #292e31; 29 | text-decoration: none; 30 | } 31 | 32 | .menu ul.list li:nth-child(2) { 33 | margin-top: 0; 34 | } 35 | 36 | .menu ul.list li.title a, .navbar a { 37 | color: #0099e5; 38 | text-decoration: none; 39 | font-size: 16px; 40 | } 41 | 42 | .menu ul.list li a.active { 43 | color: #0099e5; 44 | } 45 | 46 | code { 47 | box-sizing: border-box; 48 | display: inline-block; 49 | padding: 0 5px; 50 | background: #fafcfc; 51 | border-radius: 4px; 52 | color: #b93d6a; 53 | font-size: 13px; 54 | line-height: 20px 55 | } 56 | 57 | pre { 58 | margin: 0; 59 | padding: 12px 12px; 60 | background: #272b2d; 61 | border-radius: 5px; 62 | font-size: 13px; 63 | line-height: 1.5em; 64 | font-weight: 500 65 | } 66 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/components/detection-result/detection-result.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DetectionResultComponent } from './detection-result.component'; 4 | import { FaceDetectorService } from '../../services/face-detector.service'; 5 | import { ModelLoaderService } from '../../services/model-loader.service'; 6 | import { DetectTask } from '../../classes/DetectTask'; 7 | import { ModelsUrl } from '../../tokens/ModelsUrl'; 8 | 9 | describe('DetectionResultComponent', () => { 10 | let component: DetectionResultComponent; 11 | let fixture: ComponentFixture; 12 | 13 | beforeEach(async(() => { 14 | TestBed.configureTestingModule({ 15 | providers: [ 16 | { 17 | provide: ModelsUrl, 18 | useValue: '/', 19 | }, 20 | FaceDetectorService, 21 | ModelLoaderService, 22 | { 23 | provide: DetectTask, 24 | useValue: new DetectTask({ 25 | type: 'all', 26 | tokens: [], 27 | }), 28 | }, 29 | ], 30 | declarations: [DetectionResultComponent], 31 | }).compileComponents(); 32 | })); 33 | 34 | beforeEach(() => { 35 | fixture = TestBed.createComponent(DetectionResultComponent); 36 | component = fixture.componentInstance; 37 | fixture.detectChanges(); 38 | }); 39 | 40 | it('should create', () => { 41 | expect(component).toBeTruthy(); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/services/face-detector.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Optional, Inject } from '@angular/core'; 2 | import * as faceapi from 'face-api.js'; 3 | import { Observable, of, fromEvent, interval } from 'rxjs'; 4 | import { switchMap, shareReplay } from 'rxjs/operators'; 5 | 6 | import { ModelLoaderService } from './model-loader.service'; 7 | import { DetectTask } from '../classes/DetectTask'; 8 | import { FaceDetectionOptions } from '../tokens/FaceDetectionOptions'; 9 | 10 | @Injectable() 11 | export class FaceDetectorService { 12 | constructor( 13 | private modelLoader: ModelLoaderService, 14 | @Optional() 15 | @Inject(FaceDetectionOptions) 16 | private option?: faceapi.FaceDetectionOptions, 17 | ) {} 18 | 19 | public detect(task: DetectTask): Observable { 20 | if (task.realtime === true) { 21 | return of(task).pipe( 22 | switchMap(async t => await t.target), 23 | switchMap(video => fromEvent(video, 'loadeddata')), 24 | switchMap(() => this.modelLoader.loadForFeature(task.tokens)), 25 | switchMap(() => interval(300)), 26 | switchMap(() => task.detect(this.option)), 27 | shareReplay(1), 28 | ); 29 | } 30 | return of(task).pipe( 31 | switchMap(async t => await t.target), 32 | switchMap(image => fromEvent(image, 'load')), 33 | switchMap(async () => await this.modelLoader.loadForFeature(task.tokens)), 34 | switchMap(() => task.detect(this.option)), 35 | shareReplay(1), 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/schematics/ng-add/addNgxFaceApiJsModule.ts: -------------------------------------------------------------------------------- 1 | import { Tree } from '@angular-devkit/schematics'; 2 | import { getWorkspace } from '@schematics/angular/utility/config'; 3 | import { 4 | getProjectFromWorkspace, 5 | hasNgModuleImport, 6 | addModuleImportToRootModule, 7 | getProjectMainFile, 8 | } from '@angular/cdk/schematics'; 9 | import { Schema } from './Schema'; 10 | import { red, bold } from '@angular-devkit/core/src/terminal'; 11 | import { getAppModulePath } from '@schematics/angular/utility/ng-ast-utils'; 12 | 13 | export function addNgxFaceApiJsModule(options: Schema) { 14 | return (host: Tree) => { 15 | const workspace = getWorkspace(host); 16 | const project = getProjectFromWorkspace(workspace, options.project); 17 | const appModulePath = getAppModulePath(host, getProjectMainFile(project)); 18 | const ngxFaceApiJsModuleName = 'NgxFaceApiJsModule'; 19 | if (hasNgModuleImport(host, appModulePath, ngxFaceApiJsModuleName)) { 20 | return console.warn( 21 | red( 22 | `Could not set up "${bold(ngxFaceApiJsModuleName)}" ` + 23 | `because "${bold(ngxFaceApiJsModuleName)}" is already imported.`, 24 | ), 25 | ); 26 | } 27 | const modelsUrl = 28 | 'https://raw.githubusercontent.com/justadudewhohacks/face-api.js/master/weights'; 29 | addModuleImportToRootModule( 30 | host, 31 | `NgxFaceApiJsModule.forRoot({ modelsUrl: '${modelsUrl}' })`, 32 | 'ngx-face-api-js', 33 | project, 34 | ); 35 | return host; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /docs/styles/laravel.css: -------------------------------------------------------------------------------- 1 | .navbar-default .navbar-brand { 2 | color: #f4645f; 3 | text-decoration: none; 4 | font-size: 16px; 5 | } 6 | 7 | .menu ul.list li a[data-type="chapter-link"], .menu ul.list li.chapter .simple { 8 | color: #525252; 9 | border-bottom: 1px dashed rgba(0,0,0,.1); 10 | } 11 | 12 | .content h1, .content h2, .content h3, .content h4, .content h5 { 13 | color: #292e31; 14 | font-weight: normal; 15 | } 16 | 17 | .content { 18 | color: #4c555a; 19 | } 20 | 21 | a { 22 | color: #f4645f; 23 | text-decoration: underline; 24 | } 25 | a:hover { 26 | color: #f1362f; 27 | } 28 | 29 | .menu ul.list li:nth-child(2) { 30 | margin-top: 0; 31 | } 32 | 33 | .menu ul.list li.title a { 34 | color: #f4645f; 35 | text-decoration: none; 36 | font-size: 16px; 37 | } 38 | 39 | .menu ul.list li a { 40 | color: #f4645f; 41 | text-decoration: none; 42 | } 43 | .menu ul.list li a.active { 44 | color: #f4645f; 45 | font-weight: bold; 46 | } 47 | 48 | code { 49 | box-sizing: border-box; 50 | display: inline-block; 51 | padding: 0 5px; 52 | background: #f0f2f1; 53 | border-radius: 3px; 54 | color: #b93d6a; 55 | font-size: 13px; 56 | line-height: 20px; 57 | box-shadow: 0 1px 1px rgba(0,0,0,.125); 58 | } 59 | 60 | pre { 61 | margin: 0; 62 | padding: 12px 12px; 63 | background: rgba(238,238,238,.35); 64 | border-radius: 3px; 65 | font-size: 13px; 66 | line-height: 1.5em; 67 | font-weight: 500; 68 | box-shadow: 0 1px 1px rgba(0,0,0,.125); 69 | } 70 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngx-face-api-js", 3 | "version": "0.1.1", 4 | "description": "Angular directives for face detection and face recognition in the browser. It is a wrapper for face-api.js, so it is not dependent on the browser implementation.", 5 | "author": "kamiazya ", 6 | "license": "MIT", 7 | "keywords": [ 8 | "angular", 9 | "directive", 10 | "face-recognition", 11 | "emotion-recognition", 12 | "face-detection", 13 | "tesorflow" 14 | ], 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/kamiazya/ngx-face-api-js.git" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/kamiazya/ngx-face-api-js/issues" 21 | }, 22 | "homepage": "https://github.com/kamiazya/ngx-face-api-js", 23 | "peerDependencies": { 24 | "@angular/common": "^7.2.0", 25 | "@angular/core": "^7.2.0" 26 | }, 27 | "scripts": { 28 | "build:schematics": "tsc -p tsconfig.schematics.json", 29 | "test:schematics": "npm run build:schematics && jasmine schematics/**/*.spec.js schematics/**/**/*.spec.js" 30 | }, 31 | "dependencies": { 32 | "@angular/cdk": "^7.3.7", 33 | "face-api.js": "~0.20.0" 34 | }, 35 | "devDependencies": { 36 | "@angular-devkit/core": "^7.3.8", 37 | "@angular-devkit/schematics": "^7.3.8", 38 | "@types/jasmine": "^3.0.0", 39 | "@types/node": "^8.0.31", 40 | "jasmine": "^3.0.0", 41 | "typescript": "~3.2.2" 42 | }, 43 | "schematics": "./schematics/collection.json", 44 | "ng-update": { 45 | "migrations": "./schematics/migrations/migration.json" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-config-prettier"], 3 | "rulesDirectory": ["codelyzer"], 4 | "rules": { 5 | "array-type": false, 6 | "arrow-parens": false, 7 | "deprecation": { 8 | "severity": "warn" 9 | }, 10 | "import-blacklist": [true, "rxjs/Rx"], 11 | "interface-name": false, 12 | "max-classes-per-file": false, 13 | "max-line-length": [true, 140], 14 | "member-access": false, 15 | "member-ordering": [ 16 | true, 17 | { 18 | "order": [ 19 | "static-field", 20 | "instance-field", 21 | "static-method", 22 | "instance-method" 23 | ] 24 | } 25 | ], 26 | "no-consecutive-blank-lines": false, 27 | "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], 28 | "no-empty": false, 29 | "no-inferrable-types": [true, "ignore-params"], 30 | "no-non-null-assertion": true, 31 | "no-redundant-jsdoc": true, 32 | "no-switch-case-fall-through": true, 33 | "no-use-before-declare": true, 34 | "no-var-requires": false, 35 | "object-literal-key-quotes": [true, "as-needed"], 36 | "object-literal-sort-keys": false, 37 | "ordered-imports": false, 38 | "quotemark": [true, "single"], 39 | "trailing-comma": false, 40 | "no-output-on-prefix": true, 41 | "use-input-property-decorator": true, 42 | "use-output-property-decorator": true, 43 | "use-host-property-decorator": true, 44 | "no-input-rename": true, 45 | "no-output-rename": true, 46 | "use-life-cycle-interface": true, 47 | "use-pipe-transform-interface": true, 48 | "component-class-suffix": true, 49 | "directive-class-suffix": true 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /docs/js/lazy-load-graphs.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | var lazyGraphs = [].slice.call(document.querySelectorAll('[lazy]')); 3 | var active = false; 4 | 5 | var lazyLoad = function() { 6 | if (active === false) { 7 | active = true; 8 | 9 | setTimeout(function() { 10 | lazyGraphs.forEach(function(lazyGraph) { 11 | if ( 12 | lazyGraph.getBoundingClientRect().top <= window.innerHeight && 13 | lazyGraph.getBoundingClientRect().bottom >= 0 && 14 | getComputedStyle(lazyGraph).display !== 'none' 15 | ) { 16 | lazyGraph.data = lazyGraph.getAttribute('lazy'); 17 | lazyGraph.removeAttribute('lazy'); 18 | 19 | lazyGraphs = lazyGraphs.filter(function(image) { return image !== lazyGraph}); 20 | 21 | if (lazyGraphs.length === 0) { 22 | document.removeEventListener('scroll', lazyLoad); 23 | window.removeEventListener('resize', lazyLoad); 24 | window.removeEventListener('orientationchange', lazyLoad); 25 | } 26 | } 27 | }); 28 | 29 | active = false; 30 | }, 200); 31 | } 32 | }; 33 | 34 | // initial load 35 | lazyLoad(); 36 | 37 | var container = document.querySelector('.container-fluid.modules'); 38 | if (container) { 39 | container.addEventListener('scroll', lazyLoad); 40 | window.addEventListener('resize', lazyLoad); 41 | window.addEventListener('orientationchange', lazyLoad); 42 | } 43 | 44 | }); 45 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/schematics/ng-add/addCdkOverlayPrebuiltCssToAppStyles.ts: -------------------------------------------------------------------------------- 1 | import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics'; 2 | import { getWorkspace } from '@schematics/angular/utility/config'; 3 | import { 4 | getProjectFromWorkspace, 5 | getProjectStyleFile, 6 | } from '@angular/cdk/schematics'; 7 | import { Schema } from './Schema'; 8 | import { red, italic } from '@angular-devkit/core/src/terminal'; 9 | export function addCdkOverlayPrebuiltCssToAppStyles(options: Schema): Rule { 10 | return (host: Tree, _: SchematicContext) => { 11 | const workspace = getWorkspace(host); 12 | const project = getProjectFromWorkspace(workspace, options.project); 13 | const styleFilePath = getProjectStyleFile(project); 14 | if (!styleFilePath) { 15 | console.warn( 16 | red(`Could not find the default style file for this project.`), 17 | ); 18 | console.warn( 19 | red(`Please consider manually setting up the Roboto font in your CSS.`), 20 | ); 21 | return; 22 | } 23 | const buffer = host.read(styleFilePath); 24 | if (!buffer) { 25 | console.warn( 26 | red( 27 | `Could not read the default style file within the project ` + 28 | `(${italic(styleFilePath)})`, 29 | ), 30 | ); 31 | console.warn(red(`Please consider manually setting up the Robot font.`)); 32 | return; 33 | } 34 | const content = buffer.toString(); 35 | const insertion = `\n@import '~@angular/cdk/overlay-prebuilt.css';`; 36 | if (content.includes(insertion)) { 37 | return; 38 | } 39 | const recorder = host.beginUpdate(styleFilePath); 40 | recorder.insertLeft(content.length, insertion); 41 | host.commitUpdate(recorder); 42 | return host; 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/schematics/util/addDependencies.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Rule, 3 | SchematicContext, 4 | Tree, 5 | SchematicsException, 6 | } from '@angular-devkit/schematics'; 7 | import { 8 | addPackageJsonDependency, 9 | NodeDependency, 10 | NodeDependencyType, 11 | } from '@schematics/angular/utility/dependencies'; 12 | import { Observable, of } from 'rxjs'; 13 | import { concatMap, map } from 'rxjs/operators'; 14 | import { getLatestNodeVersion, NpmRegistryPackage } from './npmjs'; 15 | export function addDependencies({ 16 | packageName, 17 | version = 'latest', 18 | type = NodeDependencyType.Default, 19 | overwrite = false, 20 | }: { 21 | packageName: string; 22 | version?: string; 23 | type?: NodeDependencyType; 24 | overwrite?: boolean; 25 | }): Rule { 26 | return (host: Tree, context: SchematicContext): Observable => { 27 | const buf = host.read('package.json'); 28 | if (!buf) { 29 | throw new SchematicsException('cannot find package.json'); 30 | } 31 | return of(packageName).pipe( 32 | concatMap(async name => { 33 | if (version === 'latest') { 34 | return getLatestNodeVersion(name); 35 | } 36 | return { name, version }; 37 | }), 38 | map((npmRegistryPackage: NpmRegistryPackage) => { 39 | const nodeDependency: NodeDependency = { 40 | type, 41 | overwrite, 42 | name: npmRegistryPackage.name, 43 | version: npmRegistryPackage.version, 44 | }; 45 | addPackageJsonDependency(host, nodeDependency); 46 | context.logger.info( 47 | `✅️ Added dependency: ${npmRegistryPackage.name}@${ 48 | npmRegistryPackage.version 49 | }`, 50 | ); 51 | return host; 52 | }), 53 | ); 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/schematics/migrations/update-0-1-0/index.spec.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import { 3 | UnitTestTree, 4 | SchematicTestRunner, 5 | } from '@angular-devkit/schematics/testing'; 6 | import { 7 | addPackageJsonDependency, 8 | NodeDependencyType, 9 | } from '@schematics/angular/utility/dependencies'; 10 | import { getFileContent } from '@schematics/angular/utility/test'; 11 | 12 | const migrationPath = path.join(__dirname, '../migration.json'); 13 | 14 | function createTestApp(appOptions: any = {}): UnitTestTree { 15 | const baseRunner = new SchematicTestRunner('schematics', migrationPath); 16 | 17 | const workspaceTree = baseRunner.runExternalSchematic( 18 | '@schematics/angular', 19 | 'workspace', 20 | { 21 | name: 'workspace', 22 | version: '7.1.2', 23 | newProjectRoot: 'projects', 24 | }, 25 | ); 26 | addPackageJsonDependency(workspaceTree, { 27 | name: 'face-api.js', 28 | version: '^0.19.0', 29 | type: NodeDependencyType.Default, 30 | }); 31 | 32 | return baseRunner.runExternalSchematic( 33 | '@schematics/angular', 34 | 'application', 35 | { 36 | ...appOptions, 37 | name: 'example-app', 38 | }, 39 | workspaceTree, 40 | ); 41 | } 42 | 43 | describe('ngx-face-api-js-schematics migrations update-0-1-0', () => { 44 | it('update addDependencies works face-api.js', async () => { 45 | const runner = new SchematicTestRunner('schematics', migrationPath); 46 | const tree = await runner 47 | .runSchematicAsync('update-0-1-0', {}, createTestApp()) 48 | .toPromise(); 49 | 50 | expect(tree.files).toContain('/package.json'); 51 | 52 | const packageJson = JSON.parse(getFileContent(tree, '/package.json')); 53 | expect(packageJson.dependencies['face-api.js']).toBe('~0.20.0'); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /docs/styles/vagrant.css: -------------------------------------------------------------------------------- 1 | .navbar-default .navbar-brand { 2 | background: white; 3 | color: #8d9ba8; 4 | } 5 | 6 | .menu .list { 7 | background: #0c5593; 8 | } 9 | 10 | .menu .chapter { 11 | padding: 0 20px; 12 | } 13 | 14 | .menu ul.list li a[data-type="chapter-link"], .menu ul.list li.chapter .simple { 15 | color: white; 16 | text-transform: uppercase; 17 | border-bottom: 1px solid rgba(255,255,255,0.4); 18 | } 19 | 20 | .content h1, .content h2, .content h3, .content h4, .content h5 { 21 | color: #292e31; 22 | font-weight: normal; 23 | } 24 | 25 | .content { 26 | color: #4c555a; 27 | } 28 | 29 | a { 30 | color: #0094bf; 31 | text-decoration: underline; 32 | } 33 | a:hover { 34 | color: #f1362f; 35 | } 36 | 37 | .menu ul.list li.title { 38 | background: white; 39 | padding-bottom: 5px; 40 | } 41 | 42 | .menu ul.list li:nth-child(2) { 43 | margin-top: 0; 44 | } 45 | 46 | .menu ul.list li:nth-last-child(2) { 47 | background: none; 48 | } 49 | 50 | .menu ul.list li.title a { 51 | padding: 10px 15px; 52 | } 53 | 54 | .menu ul.list li.title a, .navbar a { 55 | color: #8d9ba8; 56 | text-decoration: none; 57 | font-size: 16px; 58 | font-weight: 300; 59 | } 60 | 61 | .menu ul.list li a { 62 | color: white; 63 | padding: 10px; 64 | font-weight: 300; 65 | text-decoration: none; 66 | } 67 | .menu ul.list li a.active { 68 | color: white; 69 | font-weight: bold; 70 | } 71 | 72 | .copyright { 73 | color: white; 74 | background: #000; 75 | } 76 | 77 | code { 78 | box-sizing: border-box; 79 | display: inline-block; 80 | padding: 0 5px; 81 | background: rgba(0,148,191,0.1); 82 | border-radius: 3px; 83 | color: #0094bf; 84 | font-size: 13px; 85 | line-height: 20px; 86 | } 87 | 88 | pre { 89 | margin: 0; 90 | padding: 12px 12px; 91 | background: rgba(238,238,238,.35); 92 | border-radius: 3px; 93 | font-size: 13px; 94 | line-height: 1.5em; 95 | font-weight: 500; 96 | } 97 | -------------------------------------------------------------------------------- /docs/js/search/search-lunr.js: -------------------------------------------------------------------------------- 1 | (function(compodoc) { 2 | 3 | function LunrSearchEngine() { 4 | this.index = undefined; 5 | this.store = {}; 6 | this.name = 'LunrSearchEngine'; 7 | } 8 | 9 | LunrSearchEngine.prototype.init = function() { 10 | var that = this, 11 | d = new promise.Promise(); 12 | 13 | that.index = lunr.Index.load(COMPODOC_SEARCH_INDEX.index); 14 | that.store = COMPODOC_SEARCH_INDEX.store; 15 | d.done(); 16 | 17 | return d; 18 | }; 19 | 20 | LunrSearchEngine.prototype.search = function(q, offset, length) { 21 | var that = this, 22 | results = [], 23 | d = new promise.Promise(); 24 | 25 | if (this.index) { 26 | results = $.map(this.index.search('*' + q + '*'), function(result) { 27 | var doc = that.store[result.ref]; 28 | 29 | return { 30 | title: doc.title, 31 | url: doc.url, 32 | body: doc.summary || doc.body 33 | }; 34 | }); 35 | } 36 | 37 | d.done({ 38 | query: q, 39 | results: results.slice(0, length), 40 | count: results.length 41 | }); 42 | 43 | return d; 44 | }; 45 | 46 | compodoc.addEventListener(compodoc.EVENTS.READY, function(event) { 47 | var engine = new LunrSearchEngine(), 48 | initialized = false; 49 | 50 | function query(q, offset, length) { 51 | if (!initialized) throw new Error('Search has not been initialized'); 52 | return engine.search(q, offset, length); 53 | } 54 | 55 | compodoc.search = { 56 | query: query 57 | }; 58 | 59 | engine.init() 60 | .then(function() { 61 | initialized = true; 62 | compodoc.dispatchEvent({ 63 | type: compodoc.EVENTS.SEARCH_READY 64 | }); 65 | }); 66 | }); 67 | })(compodoc); 68 | -------------------------------------------------------------------------------- /docs/styles/readthedocs.css: -------------------------------------------------------------------------------- 1 | .navbar-default { 2 | background: #2980B9; 3 | border: none; 4 | } 5 | .navbar-default .navbar-brand { 6 | color: #fcfcfc; 7 | } 8 | .menu { 9 | background: #343131; 10 | color: #fcfcfc; 11 | } 12 | .menu ul.list li a { 13 | color: #fcfcfc; 14 | } 15 | 16 | .menu ul.list li a.active { 17 | color: #0099e5; 18 | } 19 | 20 | .menu ul.list li.title { 21 | background: #2980B9; 22 | padding-bottom: 5px; 23 | } 24 | 25 | .menu ul.list li:nth-child(2) { 26 | margin-top: 0; 27 | } 28 | 29 | .menu ul.list li.chapter a, .menu ul.list li.chapter .simple { 30 | color: #555; 31 | text-transform: uppercase; 32 | text-decoration: none; 33 | } 34 | 35 | .menu ul.list li.chapter ul.links a { 36 | color: #b3b3b3; 37 | text-transform: none; 38 | padding-left: 35px; 39 | } 40 | .menu ul.list li.chapter ul.links a:hover { 41 | background: #4E4A4A; 42 | } 43 | 44 | .menu ul.list li.chapter ul.links { 45 | padding-left: 0; 46 | } 47 | 48 | .menu ul.list li.divider { 49 | background: rgba(255, 255, 255, 0.07); 50 | } 51 | 52 | #book-search-input input, #book-search-input input:focus, #book-search-input input:hover { 53 | color: #949494; 54 | } 55 | 56 | .copyright { 57 | color: #b3b3b3; 58 | } 59 | 60 | .content { 61 | background: #fcfcfc; 62 | } 63 | 64 | .content a { 65 | color: #2980B9; 66 | } 67 | .content a:hover { 68 | color: #3091d1; 69 | } 70 | .content a:visited { 71 | color: #9B59B6; 72 | } 73 | .copyright { 74 | background: #272525; 75 | } 76 | .menu ul.list li:nth-last-child(2) { 77 | background: none; 78 | } 79 | code { 80 | white-space: nowrap; 81 | max-width: 100%; 82 | background: #fff; 83 | padding: 2px 5px; 84 | color: #E74C3C; 85 | overflow-x: auto; 86 | border-radius: 0; 87 | } 88 | pre { 89 | white-space: pre; 90 | margin: 0; 91 | padding: 12px 12px; 92 | font-size: 12px; 93 | line-height: 1.5; 94 | display: block; 95 | overflow: auto; 96 | color: #404040; 97 | background: rgba(238,238,238,.35); 98 | } 99 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/ngx-face-api-js.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { ModuleWithProviders } from '@angular/core'; 3 | import { BrowserModule } from '@angular/platform-browser'; 4 | import { OverlayModule } from '@angular/cdk/overlay'; 5 | import { PortalModule } from '@angular/cdk/portal'; 6 | import * as faceapi from 'face-api.js'; 7 | import { ModelsUrl } from './tokens/ModelsUrl'; 8 | import { FaceDetectionOptions } from './tokens/FaceDetectionOptions'; 9 | import { FaceDetectorService } from './services/face-detector.service'; 10 | import { ModelLoaderService } from './services/model-loader.service'; 11 | import { DetectionResultComponent } from './components/detection-result/detection-result.component'; 12 | import { DetectAllFacesImgDirective } from './directives/detect-all-faces-img.directive'; 13 | import { DetectSingleFaceImgDirective } from './directives/detect-dingle-face-img.directive'; 14 | import { DetectAllFacesVideoDirective } from './directives/detect-all-faces-video.directive'; 15 | 16 | export interface NgxFaceApiJsModuleOption { 17 | modelsUrl: string; 18 | faceDetectionOptions?: faceapi.FaceDetectionOptions; 19 | } 20 | 21 | @NgModule({ 22 | declarations: [ 23 | DetectionResultComponent, 24 | DetectAllFacesImgDirective, 25 | DetectSingleFaceImgDirective, 26 | DetectAllFacesVideoDirective, 27 | ], 28 | imports: [BrowserModule, OverlayModule, PortalModule], 29 | exports: [ 30 | DetectAllFacesImgDirective, 31 | DetectSingleFaceImgDirective, 32 | DetectAllFacesVideoDirective, 33 | ], 34 | entryComponents: [DetectionResultComponent], 35 | }) 36 | export class NgxFaceApiJsModule { 37 | static forRoot(options: NgxFaceApiJsModuleOption): ModuleWithProviders { 38 | return { 39 | ngModule: NgxFaceApiJsModule, 40 | providers: [ 41 | { 42 | provide: ModelsUrl, 43 | useValue: options.modelsUrl, 44 | }, 45 | ModelLoaderService, 46 | FaceDetectorService, 47 | ...[ 48 | options.faceDetectionOptions 49 | ? { 50 | provide: FaceDetectionOptions, 51 | useValue: options.faceDetectionOptions, 52 | } 53 | : [], 54 | ], 55 | ], 56 | }; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /docs/js/libs/promise.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2013 (c) Pierre Duquesne 3 | * Licensed under the New BSD License. 4 | * https://github.com/stackp/promisejs 5 | */ 6 | (function(a){function b(){this._callbacks=[];}b.prototype.then=function(a,c){var d;if(this._isdone)d=a.apply(c,this.result);else{d=new b();this._callbacks.push(function(){var b=a.apply(c,arguments);if(b&&typeof b.then==='function')b.then(d.done,d);});}return d;};b.prototype.done=function(){this.result=arguments;this._isdone=true;for(var a=0;a=300)&&j.status!==304);h.done(a,j.responseText,j);}};j.send(k);return h;}function h(a){return function(b,c,d){return g(a,b,c,d);};}var i={Promise:b,join:c,chain:d,ajax:g,get:h('GET'),post:h('POST'),put:h('PUT'),del:h('DELETE'),ENOXHR:1,ETIMEOUT:2,ajaxTimeout:0};if(typeof define==='function'&&define.amd)define(function(){return i;});else a.promise=i;})(this); -------------------------------------------------------------------------------- /docs/js/svg-pan-zoom.controls.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | if (document.getElementById('module-graph-svg')) { 3 | panZoom = svgPanZoom(document.getElementById('module-graph-svg').querySelector('svg'), { 4 | zoomEnabled: true, 5 | minZoom: 1, 6 | maxZoom: 5 7 | }); 8 | 9 | document.getElementById('zoom-in').addEventListener('click', function(ev) { 10 | ev.preventDefault(); 11 | panZoom.zoomIn(); 12 | }); 13 | 14 | document.getElementById('zoom-out').addEventListener('click', function(ev) { 15 | ev.preventDefault(); 16 | panZoom.zoomOut(); 17 | }); 18 | 19 | document.getElementById('reset').addEventListener('click', function(ev) { 20 | ev.preventDefault(); 21 | panZoom.resetZoom(); 22 | panZoom.resetPan(); 23 | }); 24 | 25 | var overviewFullscreen = false, 26 | originalOverviewHeight; 27 | 28 | document.getElementById('fullscreen').addEventListener('click', function(ev) { 29 | if (overviewFullscreen) { 30 | document.getElementById('module-graph-svg').style.height = originalOverviewHeight; 31 | overviewFullscreen = false; 32 | if (ev.target) { 33 | ev.target.classList.remove('ion-md-close'); 34 | ev.target.classList.add('ion-ios-resize'); 35 | } 36 | } else { 37 | originalOverviewHeight = document.getElementById('module-graph-svg').style.height; 38 | document.getElementById('module-graph-svg').style.height = '85vh'; 39 | overviewFullscreen = true; 40 | if (ev.target) { 41 | ev.target.classList.remove('ion-ios-resize'); 42 | ev.target.classList.add('ion-md-close'); 43 | } 44 | } 45 | document.getElementById('module-graph-svg').querySelector('svg').style.height = document.getElementById('module-graph-svg').clientHeight; 46 | setTimeout(function() { 47 | panZoom.resize(); 48 | panZoom.fit(); 49 | panZoom.center(); 50 | }, 0) 51 | }); 52 | } 53 | }); 54 | -------------------------------------------------------------------------------- /docs/js/sourceCode.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | var $tabSource = document.querySelector('#source-tab'), 3 | $tabInfo = document.querySelector('#info-tab'), 4 | $tabReadme = document.querySelector('#readme-tab'), 5 | $tabTemplate = document.querySelector('#templateData-tab'), 6 | $tabTree = document.querySelector('#tree-tab'), 7 | $tabExample = document.querySelector('#example-tab'), 8 | $prismPre = document.querySelector('pre.compodoc-sourcecode'); 9 | if ($tabSource && $prismPre) { 10 | $prismCode = $prismPre.querySelector('code'), 11 | $content = document.querySelector('.content'), 12 | prismLinks = document.querySelectorAll('.link-to-prism') 13 | 14 | for (var i = 0; i < prismLinks.length; i++) { 15 | prismLinks[i].addEventListener('click', linkToPrism, false); 16 | } 17 | 18 | function linkToPrism(event) { 19 | var targetLine = event.target.getAttribute('data-line'); 20 | event.preventDefault(); 21 | 22 | $prismPre.setAttribute('data-line', targetLine); 23 | Prism.highlightElement($prismCode, function() {}); 24 | 25 | $tabSource.click(); 26 | 27 | setTimeout(function() { 28 | var $prismHighlightLine = document.querySelector('.line-highlight'), 29 | top = parseInt(getComputedStyle($prismHighlightLine)['top']); 30 | $content.scrollTop = top; 31 | }, 500); 32 | }; 33 | 34 | window.onhashchange = function(event) { 35 | switch (window.location.hash) { 36 | case '': 37 | case '#info': 38 | $tabInfo.click(); 39 | break; 40 | case '#readme': 41 | $tabReadme.click(); 42 | break; 43 | case '#source': 44 | $tabSource.click(); 45 | break; 46 | case '#template': 47 | $tabTemplate.click(); 48 | break; 49 | case '#dom-tree': 50 | $tabTree.click(); 51 | break; 52 | case '#example': 53 | $tabExample.click(); 54 | break; 55 | } 56 | } 57 | } 58 | }); 59 | -------------------------------------------------------------------------------- /docs/styles/material.css: -------------------------------------------------------------------------------- 1 | .menu { 2 | background: none; 3 | } 4 | 5 | a:hover { 6 | text-decoration: none; 7 | } 8 | 9 | /** LINK **/ 10 | 11 | .menu ul.list li a { 12 | text-decoration: none; 13 | } 14 | 15 | .menu ul.list li a:hover, .menu ul.list li.chapter .simple:hover { 16 | background-color: #f8f9fa; 17 | text-decoration: none; 18 | } 19 | 20 | #book-search-input { 21 | margin-bottom: 0; 22 | } 23 | 24 | .menu ul.list li.divider { 25 | margin-top: 0; 26 | background: #e9ecef; 27 | } 28 | 29 | .menu .title:hover { 30 | background-color: #f8f9fa; 31 | } 32 | 33 | /** CARD **/ 34 | 35 | .card { 36 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); 37 | border-radius: 0.125rem; 38 | border: 0; 39 | margin-top: 1px; 40 | } 41 | 42 | .card-header { 43 | background: none; 44 | } 45 | 46 | /** BUTTON **/ 47 | 48 | .btn { 49 | border-radius: 0.125rem; 50 | } 51 | 52 | /** NAV BAR **/ 53 | 54 | .nav { 55 | border: 0; 56 | } 57 | .nav-tabs > li > a { 58 | border: 0; 59 | border-bottom: 0.214rem solid transparent; 60 | color: rgba(0, 0, 0, 0.54); 61 | margin-right: 0; 62 | } 63 | .nav-tabs>li.active>a, .nav-tabs>li.active>a:focus, .nav-tabs>li.active>a:hover { 64 | color: rgba(0, 0, 0, 0.87); 65 | border-top: 0; 66 | border-left: 0; 67 | border-right: 0; 68 | border-bottom: 0.214rem solid transparent; 69 | border-color: #008cff; 70 | font-weight: bold; 71 | } 72 | .nav>li>a:focus, .nav>li>a:hover { 73 | background: none; 74 | } 75 | 76 | /** LIST **/ 77 | 78 | .list-group-item:first-child { 79 | border-top-left-radius: 0.125rem; 80 | border-top-right-radius: 0.125rem; 81 | } 82 | .list-group-item:last-child { 83 | border-bottom-left-radius: 0.125rem; 84 | border-bottom-right-radius: 0.125rem; 85 | } 86 | 87 | /** MISC **/ 88 | 89 | .modifier { 90 | border-radius: 0.125rem; 91 | } 92 | 93 | pre[class*="language-"] { 94 | border-radius: 0.125rem; 95 | } 96 | 97 | /** TABLE **/ 98 | 99 | .table-hover>tbody>tr:hover { 100 | background: rgba(0, 0, 0, 0.075); 101 | } 102 | 103 | table.params thead { 104 | background: none; 105 | } 106 | table.params thead td { 107 | color: rgba(0, 0, 0, 0.54); 108 | font-weight: bold; 109 | } -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/directives/abbstract-detect.directive.ts: -------------------------------------------------------------------------------- 1 | import { ElementRef, Injector, OnInit, AfterViewInit } from '@angular/core'; 2 | import { Overlay, OverlayConfig } from '@angular/cdk/overlay'; 3 | import { ComponentPortal } from '@angular/cdk/portal'; 4 | import { TaskTypeToken } from '../tokens/TaskTypeToken'; 5 | import { FeatureToken } from '../tokens/FeatureToken'; 6 | import { DetectTask } from '../classes/DetectTask'; 7 | import { DetectionResultComponent } from '../components/detection-result/detection-result.component'; 8 | 9 | export abstract class AbstractDetectDirective implements OnInit, AfterViewInit { 10 | protected abstract with: FeatureToken[] = []; 11 | protected abstract type: TaskTypeToken; 12 | protected abstract stream: boolean; 13 | constructor( 14 | protected el: ElementRef, 15 | protected overlay: Overlay, 16 | protected injector: Injector, 17 | ) {} 18 | public task: DetectTask; 19 | ngOnInit() { 20 | this.task = new DetectTask({ 21 | type: this.type, 22 | tokens: this.with, 23 | realtime: this.stream, 24 | }); 25 | } 26 | 27 | private get orverlayPositionStrategy() { 28 | return this.overlay 29 | .position() 30 | .flexibleConnectedTo(this.el) 31 | .withPositions([ 32 | { 33 | overlayX: 'start', 34 | overlayY: 'top', 35 | originX: 'start', 36 | originY: 'top', 37 | }, 38 | ]) 39 | .withFlexibleDimensions(false) 40 | .withLockedPosition(true); 41 | } 42 | 43 | private createOverlay() { 44 | const scrollStrategy = this.overlay.scrollStrategies.reposition(); 45 | const config = new OverlayConfig({ 46 | positionStrategy: this.orverlayPositionStrategy, 47 | scrollStrategy, 48 | hasBackdrop: false, 49 | }); 50 | return this.overlay.create(config); 51 | } 52 | 53 | private createInjector(): Injector { 54 | return Injector.create({ 55 | parent: this.injector, 56 | providers: [ 57 | { 58 | provide: DetectTask, 59 | useValue: this.task, 60 | }, 61 | ], 62 | }); 63 | } 64 | 65 | ngAfterViewInit() { 66 | this.task.resolveTarget(this.el.nativeElement); 67 | const overlayRef = this.createOverlay(); 68 | const injector = this.createInjector(); 69 | const portal = new ComponentPortal( 70 | DetectionResultComponent, 71 | undefined, 72 | injector, 73 | ); 74 | overlayRef.attach(portal); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /docs/js/libs/tablesort.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * tablesort v5.1.0 (2018-09-14) 3 | * http://tristen.ca/tablesort/demo/ 4 | * Copyright (c) 2018 ; Licensed MIT 5 | */ 6 | !function(){function a(b,c){if(!(this instanceof a))return new a(b,c);if(!b||"TABLE"!==b.tagName)throw new Error("Element must be a table");this.init(b,c||{})}var b=[],c=function(a){var b;return window.CustomEvent&&"function"==typeof window.CustomEvent?b=new CustomEvent(a):(b=document.createEvent("CustomEvent"),b.initCustomEvent(a,!1,!1,void 0)),b},d=function(a){return a.getAttribute("data-sort")||a.textContent||a.innerText||""},e=function(a,b){return a=a.trim().toLowerCase(),b=b.trim().toLowerCase(),a===b?0:a0)if(a.tHead&&a.tHead.rows.length>0){for(e=0;e0&&l.push(k),m++;if(!l)return}for(m=0;m= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags.ts'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | /*************************************************************************************************** 61 | * APPLICATION IMPORTS 62 | */ 63 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/services/model-loader.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject } from '@angular/core'; 2 | // tslint:disable-next-line:max-line-length 3 | import { 4 | loadMtcnnModel, 5 | loadSsdMobilenetv1Model, 6 | loadFaceExpressionModel, 7 | loadFaceLandmarkModel, 8 | loadTinyFaceDetectorModel, 9 | loadFaceRecognitionModel, 10 | loadAgeGenderModel, 11 | } from 'face-api.js'; 12 | // tslint:disable-next-line:max-line-length 13 | import { ModelsUrl } from '../tokens/ModelsUrl'; 14 | import { 15 | FeatureToken, 16 | ExpressionsFeatureToken, 17 | LandmarksFeatureToken, 18 | DescriptorsFeatureToken, 19 | AgeAndGenderToken, 20 | } from '../tokens/FeatureToken'; 21 | import { 22 | ModelToken, 23 | SsdMobilenetv1Model, 24 | FaceExpressionModel, 25 | FaceLandmarkModel, 26 | FaceRecognitionModel, 27 | AgeAndGenderModel, 28 | MtcnnModel, 29 | TinyFaceDetectorModel, 30 | } from '../tokens/ModelToken'; 31 | 32 | @Injectable() 33 | export class ModelLoaderService { 34 | private loadedModels: ModelToken[] = []; 35 | 36 | constructor( 37 | @Inject(ModelsUrl) 38 | private modelUrl: string, 39 | ) {} 40 | 41 | private getReqiredModels(tokens: FeatureToken[]): ModelToken[] { 42 | return [SsdMobilenetv1Model].concat( 43 | Object.entries({ 44 | [ExpressionsFeatureToken]: [FaceExpressionModel, SsdMobilenetv1Model], 45 | [LandmarksFeatureToken]: [FaceLandmarkModel, SsdMobilenetv1Model], 46 | [DescriptorsFeatureToken]: [FaceRecognitionModel], 47 | [AgeAndGenderToken]: [AgeAndGenderModel], 48 | }) 49 | .map(([key, models]) => 50 | tokens.includes(key as FeatureToken) ? models : [], 51 | ) 52 | .reduce((a, b) => a.concat(b)) 53 | .filter((v, i, arr) => arr.indexOf(v) === i), 54 | ); 55 | } 56 | 57 | private mapLoadFunction(model: ModelToken) { 58 | switch (model) { 59 | case SsdMobilenetv1Model: 60 | return loadSsdMobilenetv1Model; 61 | case MtcnnModel: 62 | return loadMtcnnModel; 63 | case FaceExpressionModel: 64 | return loadFaceExpressionModel; 65 | case FaceLandmarkModel: 66 | return loadFaceLandmarkModel; 67 | case FaceRecognitionModel: 68 | return loadFaceRecognitionModel; 69 | case TinyFaceDetectorModel: 70 | return loadTinyFaceDetectorModel; 71 | case AgeAndGenderModel: 72 | return loadAgeGenderModel; 73 | } 74 | } 75 | 76 | public isLoaded(model: ModelToken): boolean { 77 | return this.loadedModels.includes(model); 78 | } 79 | 80 | async load(...models: ModelToken[]): Promise { 81 | const loadTargetModels = models.filter(m => this.isLoaded(m) === false); 82 | 83 | await Promise.all( 84 | loadTargetModels 85 | .map(m => this.mapLoadFunction(m)) 86 | .map(load => load(this.modelUrl)), 87 | ); 88 | 89 | if (loadTargetModels.length >= 0) { 90 | this.loadedModels = loadTargetModels.concat(this.loadedModels); 91 | } 92 | } 93 | 94 | async loadForFeature(tokens: FeatureToken[]): Promise { 95 | const reqiredModels = this.getReqiredModels(tokens); 96 | console.log({ reqiredModels }); 97 | await this.load(...reqiredModels); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at yuki@kamiazya.tech. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/components/detection-result/detection-result.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Component, 3 | OnInit, 4 | ViewChild, 5 | ElementRef, 6 | Renderer2, 7 | OnDestroy, 8 | HostListener, 9 | } from '@angular/core'; 10 | import { Subscription, Subject, combineLatest } from 'rxjs'; 11 | 12 | import * as faceapi from 'face-api.js'; 13 | import { map, startWith } from 'rxjs/operators'; 14 | import { DetectTask } from '../../classes/DetectTask'; 15 | import { FaceDetectorService } from '../../services/face-detector.service'; 16 | 17 | @Component({ 18 | templateUrl: './detection-result.component.html', 19 | styleUrls: ['./detection-result.component.scss'], 20 | }) 21 | export class DetectionResultComponent implements OnInit, OnDestroy { 22 | subscription = new Subscription(); 23 | 24 | @ViewChild('canvas') 25 | private canvasEl: ElementRef; 26 | 27 | private get canvas(): HTMLCanvasElement { 28 | return this.canvasEl.nativeElement; 29 | } 30 | 31 | private resize$ = new Subject(); 32 | 33 | @HostListener('window:resize') 34 | public onResize() { 35 | this.resize$.next('onResize'); 36 | } 37 | 38 | constructor( 39 | private task: DetectTask, 40 | private el: ElementRef, 41 | private renderer: Renderer2, 42 | private faceDetector: FaceDetectorService, 43 | ) {} 44 | 45 | private convertResultToArray(result: any): any[] { 46 | if (Array.isArray(result)) { 47 | return result; 48 | } 49 | return [result]; 50 | } 51 | 52 | ngOnInit() { 53 | this.subscription.add( 54 | combineLatest( 55 | this.faceDetector.detect(this.task), 56 | this.resize$.pipe(startWith('init')), 57 | ) 58 | .pipe(map(([result]) => this.convertResultToArray(result))) 59 | .subscribe(result => this.draw(result)), 60 | ); 61 | } 62 | 63 | ngOnDestroy() { 64 | this.subscription.unsubscribe(); 65 | } 66 | private async draw(results: any[]) { 67 | const target = await this.task.target; 68 | let { width, height } = target; 69 | if (target instanceof HTMLVideoElement) { 70 | height = target.videoHeight; 71 | width = target.videoWidth; 72 | } 73 | 74 | const detectionsForSize = faceapi.resizeResults( 75 | results.map(result => 76 | result instanceof faceapi.FaceDetection ? result : result.detection, 77 | ), 78 | { width, height }, 79 | ); 80 | 81 | this.canvas.width = width; 82 | this.canvas.height = height; 83 | this.renderer.setStyle(this.canvas, 'width', `${width}px`); 84 | this.renderer.setStyle(this.canvas, 'height', `${height}px`); 85 | if (this.task.tokens.length >= 1) { 86 | faceapi.draw.drawDetections(this.canvas, detectionsForSize); 87 | 88 | const resizeResults = faceapi.resizeResults(results, { width, height }); 89 | if (this.task.tokens.includes('expressions')) { 90 | faceapi.draw.drawFaceExpressions( 91 | this.canvas, 92 | resizeResults.map(({ detection, expressions }) => ({ 93 | position: detection.box, 94 | expressions, 95 | })), 96 | ); 97 | } 98 | 99 | if (this.task.tokens.includes('landmarks')) { 100 | faceapi.draw.drawFaceLandmarks( 101 | this.canvas, 102 | resizeResults.map(({ landmarks }) => landmarks), 103 | ); 104 | } 105 | 106 | if (this.task.tokens.includes('ageAndGender')) { 107 | resizeResults.forEach(result => { 108 | const { age, gender, genderProbability } = result; 109 | const text = new faceapi.draw.DrawTextField( 110 | [ 111 | `${faceapi.round(age, 0)} years`, 112 | `${gender} (${faceapi.round(genderProbability)})`, 113 | ], 114 | result.detection.box.bottomLeft, 115 | ); 116 | text.draw(this.canvas); 117 | }); 118 | } 119 | } else { 120 | faceapi.draw.drawDetections(this.canvas, detectionsForSize); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/schematics/ng-add/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { 2 | SchematicTestRunner, 3 | UnitTestTree, 4 | } from '@angular-devkit/schematics/testing'; 5 | import { getFileContent } from '@schematics/angular/utility/test'; 6 | import * as path from 'path'; 7 | import { getWorkspace } from '@schematics/angular/utility/config'; 8 | import { 9 | getProjectFromWorkspace, 10 | getProjectStyleFile, 11 | getProjectMainFile, 12 | } from '@angular/cdk/schematics'; 13 | import { getAppModulePath } from '@schematics/angular/utility/ng-ast-utils'; 14 | 15 | const collectionPath = path.join(__dirname, '../collection.json'); 16 | 17 | function createTestApp(appOptions: any = {}): UnitTestTree { 18 | const baseRunner = new SchematicTestRunner('schematics', collectionPath); 19 | 20 | const workspaceTree = baseRunner.runExternalSchematic( 21 | '@schematics/angular', 22 | 'workspace', 23 | { 24 | name: 'workspace', 25 | version: '7.1.2', 26 | newProjectRoot: 'projects', 27 | }, 28 | ); 29 | 30 | return baseRunner.runExternalSchematic( 31 | '@schematics/angular', 32 | 'application', 33 | { 34 | ...appOptions, 35 | name: 'example-app', 36 | }, 37 | workspaceTree, 38 | ); 39 | } 40 | 41 | describe('ngx-face-api-js-schematics ng-add', () => { 42 | it('addDependencies works face-api.js', async () => { 43 | const runner = new SchematicTestRunner('schematics', collectionPath); 44 | const tree = await runner 45 | .runSchematicAsync('ng-add', {}, createTestApp()) 46 | .toPromise(); 47 | 48 | expect(tree.files).toContain('/package.json'); 49 | 50 | const packageJson = JSON.parse(getFileContent(tree, '/package.json')); 51 | expect(packageJson.dependencies['face-api.js']).toBe('~0.20.0'); 52 | }); 53 | 54 | it('addDependencies works @angular/cdk', async () => { 55 | const runner = new SchematicTestRunner('schematics', collectionPath); 56 | const tree = await runner 57 | .runSchematicAsync('ng-add', {}, createTestApp()) 58 | .toPromise(); 59 | 60 | expect(tree.files).toContain('/package.json'); 61 | 62 | const packageJson = JSON.parse(getFileContent(tree, '/package.json')); 63 | expect(Object.keys(packageJson.devDependencies)).toContain('@angular/cdk'); 64 | }); 65 | 66 | it('addBrowserIgnorePackageSetting works', async () => { 67 | const runner = new SchematicTestRunner('schematics', collectionPath); 68 | const tree = await runner 69 | .runSchematicAsync('ng-add', {}, createTestApp()) 70 | .toPromise(); 71 | 72 | expect(tree.files).toContain('/package.json'); 73 | 74 | const packageJson = JSON.parse(getFileContent(tree, '/package.json')); 75 | 76 | expect(packageJson.browser.fs).toBe(false); 77 | expect(packageJson.browser.crypto).toBe(false); 78 | }); 79 | 80 | it('addCdkOverlayPrebuiltCssToAppStyles works', async () => { 81 | const runner = new SchematicTestRunner('schematics', collectionPath); 82 | const tree = await runner 83 | .runSchematicAsync('ng-add', {}, createTestApp()) 84 | .toPromise(); 85 | 86 | const workspace = getWorkspace(tree); 87 | const project = getProjectFromWorkspace(workspace); 88 | const styleFilePath = getProjectStyleFile(project); 89 | if (styleFilePath) { 90 | const stylesScss = getFileContent(tree, styleFilePath); 91 | expect(stylesScss).toMatch( 92 | `@import '~@angular/cdk/overlay-prebuilt.css'`, 93 | ); 94 | } 95 | }); 96 | 97 | it('addNgxFaceApiJsModule works', async () => { 98 | const runner = new SchematicTestRunner('schematics', collectionPath); 99 | const tree = await runner 100 | .runSchematicAsync('ng-add', {}, createTestApp()) 101 | .toPromise(); 102 | 103 | const workspace = getWorkspace(tree); 104 | const project = getProjectFromWorkspace(workspace); 105 | const appModulePath = getAppModulePath(tree, getProjectMainFile(project)); 106 | 107 | if (appModulePath) { 108 | const appModuleContent = getFileContent(tree, appModulePath); 109 | expect(appModuleContent).toMatch('NgxFaceApiJsModule.forRoot'); 110 | } 111 | }); 112 | }); 113 | -------------------------------------------------------------------------------- /projects/ngx-face-api-js/src/lib/classes/DetectTask.ts: -------------------------------------------------------------------------------- 1 | import * as faceapi from 'face-api.js'; 2 | import { TaskTypeToken } from '../tokens/TaskTypeToken'; 3 | import { FeatureToken } from '../tokens/FeatureToken'; 4 | 5 | export class DetectTask { 6 | public get resolveTarget(): ( 7 | el: HTMLImageElement | HTMLVideoElement, 8 | ) => void { 9 | return this.targetResolver; 10 | } 11 | 12 | public readonly type: TaskTypeToken; 13 | public readonly tokens: FeatureToken[]; 14 | public readonly realtime: boolean; 15 | 16 | constructor(option: { 17 | type: TaskTypeToken; 18 | tokens: FeatureToken[]; 19 | realtime?: boolean; 20 | }) { 21 | this.type = option.type; 22 | this.tokens = option.tokens; 23 | this.realtime = option.realtime || false; 24 | this.target = new Promise( 25 | resolver => (this.targetResolver = resolver), 26 | ); 27 | } 28 | 29 | public target: Promise; 30 | 31 | private targetResolver: (el: HTMLImageElement | HTMLVideoElement) => void; 32 | 33 | private isMatchPattern(patten: string[], target: string[]): boolean { 34 | return patten.every(item => target.includes(item)); 35 | } 36 | 37 | public with(...tokens: FeatureToken[]): this { 38 | this.tokens.push(...tokens); 39 | return this; 40 | } 41 | 42 | public async detect(option?: faceapi.FaceDetectionOptions): Promise { 43 | let t: faceapi.DetectAllFacesTask | faceapi.DetectSingleFaceTask; 44 | if (this.type === 'all') { 45 | t = faceapi.detectAllFaces(await this.target, option || undefined); 46 | } else { 47 | t = faceapi.detectSingleFace(await this.target, option || undefined); 48 | } 49 | 50 | if ( 51 | this.isMatchPattern( 52 | ['expressions', 'landmarks', 'ageAndGender', 'descriptors'], 53 | this.tokens, 54 | ) 55 | ) { 56 | if (t instanceof faceapi.DetectSingleFaceTask) { 57 | return t 58 | .withFaceLandmarks() 59 | .withFaceExpressions() 60 | .withAgeAndGender() 61 | .withFaceDescriptor() 62 | .run(); 63 | } else if (t instanceof faceapi.DetectAllFacesTask) { 64 | return t 65 | .withFaceLandmarks() 66 | .withFaceExpressions() 67 | .withAgeAndGender() 68 | .withFaceDescriptors() 69 | .run(); 70 | } 71 | } else if ( 72 | this.isMatchPattern( 73 | ['expressions', 'landmarks', 'descriptors'], 74 | this.tokens, 75 | ) 76 | ) { 77 | if (t instanceof faceapi.DetectSingleFaceTask) { 78 | return t 79 | .withFaceLandmarks() 80 | .withFaceExpressions() 81 | .withFaceDescriptor() 82 | .run(); 83 | } else if (t instanceof faceapi.DetectAllFacesTask) { 84 | return t 85 | .withFaceLandmarks() 86 | .withFaceExpressions() 87 | .withFaceDescriptors() 88 | .run(); 89 | } 90 | } else if ( 91 | this.isMatchPattern( 92 | ['expressions', 'landmarks', 'ageAndGender'], 93 | this.tokens, 94 | ) 95 | ) { 96 | return t 97 | .withFaceLandmarks() 98 | .withFaceExpressions() 99 | .withAgeAndGender() 100 | .run(); 101 | } else if (this.isMatchPattern(['expressions', 'landmarks'], this.tokens)) { 102 | return t 103 | .withFaceLandmarks() 104 | .withFaceExpressions() 105 | .run(); 106 | } else if ( 107 | this.isMatchPattern(['expressions', 'ageAndGender'], this.tokens) 108 | ) { 109 | return t 110 | .withFaceExpressions() 111 | .withAgeAndGender() 112 | .run(); 113 | } else if (this.isMatchPattern(['expressions'], this.tokens)) { 114 | return t.withFaceExpressions().run(); 115 | } else if ( 116 | this.isMatchPattern(['landmarks', 'ageAndGender'], this.tokens) 117 | ) { 118 | return t 119 | .withFaceLandmarks() 120 | .withAgeAndGender() 121 | .run(); 122 | } else if (this.isMatchPattern(['landmarks'], this.tokens)) { 123 | return t.withFaceLandmarks().run(); 124 | } 125 | return t.run(); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /docs/styles/postmark.css: -------------------------------------------------------------------------------- 1 | .navbar-default { 2 | background: #FFDE00; 3 | border: none; 4 | } 5 | .navbar-default .navbar-brand { 6 | color: #333; 7 | font-weight: bold; 8 | } 9 | .menu { 10 | background: #333; 11 | color: #fcfcfc; 12 | } 13 | .menu ul.list li a { 14 | color: #333; 15 | } 16 | 17 | .menu ul.list li.title { 18 | background: #FFDE00; 19 | color: #333; 20 | padding-bottom: 5px; 21 | } 22 | 23 | .menu ul.list li:nth-child(2) { 24 | margin-top: 0; 25 | } 26 | 27 | .menu ul.list li.chapter a, .menu ul.list li.chapter .simple { 28 | color: white; 29 | text-decoration: none; 30 | } 31 | 32 | .menu ul.list li.chapter ul.links a { 33 | color: #949494; 34 | text-transform: none; 35 | padding-left: 35px; 36 | } 37 | .menu ul.list li.chapter ul.links a:hover, .menu ul.list li.chapter ul.links a.active { 38 | color: #FFDE00; 39 | } 40 | 41 | .menu ul.list li.chapter ul.links { 42 | padding-left: 0; 43 | } 44 | 45 | .menu ul.list li.divider { 46 | background: rgba(255, 255, 255, 0.07); 47 | } 48 | 49 | #book-search-input input, #book-search-input input:focus, #book-search-input input:hover { 50 | color: #949494; 51 | } 52 | 53 | .copyright { 54 | color: #b3b3b3; 55 | } 56 | 57 | .content { 58 | background: #fcfcfc; 59 | } 60 | 61 | .content a { 62 | color: #007DCC; 63 | } 64 | .content a:visited { 65 | color: #0165a5; 66 | } 67 | .copyright { 68 | background: #272525; 69 | } 70 | .menu ul.list li:nth-last-child(2) { 71 | background: none; 72 | } 73 | .list-group-item:first-child, .list-group-item:last-child { 74 | border-radius: 0; 75 | } 76 | 77 | .menu ul.list li.title a { 78 | text-decoration: none; 79 | font-weight: bold; 80 | } 81 | .menu ul.list li.title a:hover { 82 | background: rgba(255,255,255,0.1); 83 | } 84 | 85 | .breadcrumb>li+li:before { 86 | content: "»\00a0" 87 | } 88 | 89 | .breadcrumb { 90 | padding-bottom: 15px; 91 | border-bottom: 1px solid #e1e4e5; 92 | } 93 | code { 94 | white-space: nowrap; 95 | max-width: 100%; 96 | background: #F5F5F5; 97 | padding: 2px 5px; 98 | color: #666666; 99 | overflow-x: auto; 100 | border-radius: 0; 101 | } 102 | pre { 103 | white-space: pre; 104 | margin: 0; 105 | padding: 12px 12px; 106 | font-size: 12px; 107 | line-height: 1.5; 108 | display: block; 109 | overflow: auto; 110 | color: #404040; 111 | background: #f3f3f3; 112 | } 113 | pre code.hljs { 114 | border: none; 115 | background: inherit; 116 | } 117 | 118 | /* 119 | Atom One Light by Daniel Gamage 120 | Original One Light Syntax theme from https://github.com/atom/one-light-syntax 121 | base: #fafafa 122 | mono-1: #383a42 123 | mono-2: #686b77 124 | mono-3: #a0a1a7 125 | hue-1: #0184bb 126 | hue-2: #4078f2 127 | hue-3: #a626a4 128 | hue-4: #50a14f 129 | hue-5: #e45649 130 | hue-5-2: #c91243 131 | hue-6: #986801 132 | hue-6-2: #c18401 133 | */ 134 | 135 | .hljs { 136 | display: block; 137 | overflow-x: auto; 138 | padding: 0.5em; 139 | color: #383a42; 140 | background: #fafafa; 141 | } 142 | 143 | .hljs-comment, 144 | .hljs-quote { 145 | color: #a0a1a7; 146 | font-style: italic; 147 | } 148 | 149 | .hljs-doctag, 150 | .hljs-keyword, 151 | .hljs-formula { 152 | color: #a626a4; 153 | } 154 | 155 | .hljs-section, 156 | .hljs-name, 157 | .hljs-selector-tag, 158 | .hljs-deletion, 159 | .hljs-subst { 160 | color: #e45649; 161 | } 162 | 163 | .hljs-literal { 164 | color: #0184bb; 165 | } 166 | 167 | .hljs-string, 168 | .hljs-regexp, 169 | .hljs-addition, 170 | .hljs-attribute, 171 | .hljs-meta-string { 172 | color: #50a14f; 173 | } 174 | 175 | .hljs-built_in, 176 | .hljs-class .hljs-title { 177 | color: #c18401; 178 | } 179 | 180 | .hljs-attr, 181 | .hljs-variable, 182 | .hljs-template-variable, 183 | .hljs-type, 184 | .hljs-selector-class, 185 | .hljs-selector-attr, 186 | .hljs-selector-pseudo, 187 | .hljs-number { 188 | color: #986801; 189 | } 190 | 191 | .hljs-symbol, 192 | .hljs-bullet, 193 | .hljs-link, 194 | .hljs-meta, 195 | .hljs-selector-id, 196 | .hljs-title { 197 | color: #4078f2; 198 | } 199 | 200 | .hljs-emphasis { 201 | font-style: italic; 202 | } 203 | 204 | .hljs-strong { 205 | font-weight: bold; 206 | } 207 | 208 | .hljs-link { 209 | text-decoration: underline; 210 | } 211 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngx-face-api-js", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "author": "kamiazya ", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/kamiazya/ngx-face-api-js.git" 10 | }, 11 | "bugs": { 12 | "url": "https://github.com/kamiazya/ngx-face-api-js/issues" 13 | }, 14 | "homepage": "https://github.com/kamiazya/ngx-face-api-js", 15 | "scripts": { 16 | "ng": "ng", 17 | "prettier": "prettier --write \"**/*.{js,json,css,md,ts,html,component.html}\"", 18 | "start": "run-s build:lib schematics:link start:demo-app", 19 | "start:demo-app": "ng serve", 20 | "build": "ng build", 21 | "build:demo-app": "ng build", 22 | "build:lib": "ng build ngx-face-api-js", 23 | "build:lib:prod": "run-s install:lib build:lib:schematics build:lib schematics:copy", 24 | "build:lib:w": "ng build --watch ngx-face-api-js", 25 | "build:lib:schematics": "yarn --cwd projects/ngx-face-api-js build:schematics", 26 | "install:lib": "yarn --cwd projects/ngx-face-api-js install", 27 | "test": "yarn test:demo-app", 28 | "test:all": "npm-run-all build:lib test:demo-app:single-run test:lib:single-run test:lib:schematics", 29 | "test:demo-app": "ng test", 30 | "test:demo-app:single-run": "ng test ngx-face-api-demo-app --watch=false --code-coverage --browsers ChromeHeadless", 31 | "test:lib:single-run": "ng test ngx-face-api-js --watch=false --code-coverage --browsers ChromeHeadless", 32 | "test:lib:schematics": "yarn --cwd projects/ngx-face-api-js test:schematics", 33 | "schematics:link": "yarn --cwd projects/ngx-face-api-js link && yarn link ngx-face-api-js", 34 | "schematics:copy": "cpx \"projects/ngx-face-api-js/schematics/**/*.{json,d.ts,js,js.map}\" dist/ngx-face-api-js/schematics", 35 | "schematics:ng-add": "schematics ngx-face-api-js:ng-add", 36 | "report-coverage": "codecov -f coverage/ngx-face-api-js/lcov.info", 37 | "lint": "ng lint", 38 | "e2e": "ng e2e", 39 | "docs": "compodoc -p projects/ngx-face-api-js/tsconfig.lib.json --theme material -d docs", 40 | "prepare:lib": "run-s build:lib:prod prepare:lib:copy:license prepare:lib:copy:readme prepare:lib:copy:media", 41 | "prepare:lib:copy:license": "cpx LICENSE dist/ngx-face-api-js/", 42 | "prepare:lib:copy:readme": "cpx README.md dist/ngx-face-api-js/", 43 | "prepare:lib:copy:media": "mkdir -p dist/ngx-face-api-js/media/ && cpx \"media/*.png\" dist/ngx-face-api-js/media/" 44 | }, 45 | "dependencies": { 46 | "@angular/animations": "~7.2.0", 47 | "@angular/cdk": "^7.3.7", 48 | "@angular/common": "~7.2.0", 49 | "@angular/compiler": "~7.2.0", 50 | "@angular/core": "~7.2.0", 51 | "@angular/forms": "~7.2.0", 52 | "@angular/platform-browser": "~7.2.0", 53 | "@angular/platform-browser-dynamic": "~7.2.0", 54 | "@angular/router": "~7.2.0", 55 | "core-js": "^2.5.4", 56 | "face-api.js": "~0.20.0", 57 | "rxjs": "~6.3.3", 58 | "tslib": "^1.9.0", 59 | "zone.js": "~0.8.26" 60 | }, 61 | "devDependencies": { 62 | "@angular-devkit/build-angular": "~0.13.0", 63 | "@angular-devkit/build-ng-packagr": "~0.13.0", 64 | "@angular/cli": "~7.3.6", 65 | "@angular/compiler-cli": "~7.2.0", 66 | "@angular/language-service": "~7.2.0", 67 | "@types/jasmine": "~2.8.8", 68 | "@types/jasminewd2": "~2.0.3", 69 | "@types/node": "~8.9.4", 70 | "codecov": "^3.3.0", 71 | "codelyzer": "~4.5.0", 72 | "cpx": "^1.5.0", 73 | "husky": "2.2.0", 74 | "jasmine-core": "~2.99.1", 75 | "jasmine-spec-reporter": "~4.2.1", 76 | "karma": "~4.0.0", 77 | "karma-chrome-launcher": "~2.2.0", 78 | "karma-coverage-istanbul-reporter": "~2.0.1", 79 | "karma-jasmine": "~1.1.2", 80 | "karma-jasmine-html-reporter": "^0.2.2", 81 | "lint-staged": "8.1.6", 82 | "ng-packagr": "^4.2.0", 83 | "npm-run-all": "^4.1.5", 84 | "prettier": "1.17.0", 85 | "protractor": "~5.4.0", 86 | "ts-node": "~7.0.0", 87 | "tsickle": ">=0.34.0", 88 | "tslib": "^1.9.0", 89 | "tslint": "~5.11.0", 90 | "tslint-config-prettier": "1.18.0", 91 | "typescript": "~3.2.2" 92 | }, 93 | "browser": { 94 | "fs": false, 95 | "crypto": false 96 | }, 97 | "husky": { 98 | "hooks": { 99 | "pre-commit": "lint-staged" 100 | } 101 | }, 102 | "lint-staged": { 103 | "*.{js,json,css,md,ts,html,component.html}": [ 104 | "prettier --write", 105 | "git add" 106 | ] 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **This package has not been maintained for a long time.** 2 | 3 | **Please use it by copying the code.** 4 | 5 | --- 6 | 7 | # NgxFaceApiJs 8 | 9 | [![Build Status](https://travis-ci.com/kamiazya/ngx-face-api-js.svg?branch=master)](https://travis-ci.com/kamiazya/ngx-face-api-js) [![codecov](https://codecov.io/gh/kamiazya/ngx-face-api-js/branch/master/graph/badge.svg)](https://codecov.io/gh/kamiazya/ngx-face-api-js) [![CodeFactor](https://www.codefactor.io/repository/github/kamiazya/ngx-face-api-js/badge)](https://www.codefactor.io/repository/github/kamiazya/ngx-face-api-js) [![Maintainability](https://api.codeclimate.com/v1/badges/92a5ffa6ed3f4ab11869/maintainability)](https://codeclimate.com/github/kamiazya/ngx-face-api-js/maintainability) [![BCH compliance](https://bettercodehub.com/edge/badge/kamiazya/ngx-face-api-js?branch=master)](https://bettercodehub.com/) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fkamiazya%2Fngx-face-api-js.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkamiazya%2Fngx-face-api-js?ref=badge_shield) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![npm version](https://badge.fury.io/js/ngx-face-api-js.svg)](https://badge.fury.io/js/ngx-face-api-js) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) 10 | 11 | Angular directives for face detection and face recognition in the browser. 12 | 13 | It is a wrapper for [face-api.js](https://github.com/justadudewhohacks/face-api.js), so it is not dependent on the browser implementation. 14 | 15 | [![NPM](https://nodei.co/npm/ngx-face-api-js.png)](https://nodei.co/npm/ngx-face-api-js/) 16 | 17 | ## Description 18 | 19 | Make face and emotion recognition features easy to use in Angular projects by using [face-api.js](https://github.com/justadudewhohacks/face-api.js). 20 | 21 | - **Recognize faces, emotions** and so on in Angular project. 22 | - **Works in a Mobile**. 23 | - **No Script/Styles reqired**, you only embed attribute to img/video tag. 24 | - **Schematics Support**, you can quickly set up a project using the `ng add` and `ng update` command. 25 | 26 | ### How it works? 27 | 28 | Overlay canvas on img tag with embedded attributes such as singleFace and allFaces by using [Angular CDK Overlay](https://material.angular.io/cdk/overlay/overview). 29 | 30 | ![How it works](./media/how-it-works.png) 31 | 32 | And render the recognition result on canvas according to the content of the with attribute. 33 | 34 | ### Background 35 | 36 | - [face-api.js](https://github.com/justadudewhohacks/face-api.js) 37 | - [TensorFlow.js](https://github.com/tensorflow/tfjs-core) 38 | 39 | ## Demo 40 | 41 | - [Detect Faces by Image -- StackBlitz](https://ngx-face-api-js-demo.stackblitz.io)([Editor](https://stackblitz.com/edit/ngx-face-api-js-demo?embed=1&file=src/app/app.component.html)) 42 | 43 | ## Usage 44 | 45 | ### Detect All Faces 46 | 47 | ```html 48 | 49 | ``` 50 | 51 | ![Detect faces](./media/ngx-face-api-js-demo-detect-faces.png) 52 | 53 | ### Detect Face With Expressions and Landmarks 54 | 55 | ```html 56 | 62 | ``` 63 | 64 | ![Detected Face With Expressions and Landmarks](./media/ngx-face-api-js-demo-with-expressions-and-landmarks.png) 65 | 66 | ## Installation 67 | 68 | ### By `ng-add` Schematics 69 | 70 | ```bash 71 | $ ng add ngx-face-api-js 72 | ... 73 | UPDATE package.json (1457 bytes) 74 | UPDATE src/styles.css (126 bytes) 75 | UPDATE src/app/app.module.ts (497 bytes) 76 | ``` 77 | 78 | ### By Manual 79 | 80 | See [Wiki](https://github.com/kamiazya/ngx-face-api-js/wiki/Manual-Installation). 81 | 82 | ## Update 83 | 84 | ### By `ng-update` Schematics 85 | 86 | ```bash 87 | $ ng update ngx-face-api-js 88 | ✅️ Added dependency: face-api.js@~0.20.0 89 | ✅️ Dependencies installed 90 | UPDATE package.json (1440 bytes) 91 | ``` 92 | 93 | ## Documantation 94 | 95 | - [compodoc](https://kamiazya.github.io/ngx-face-api-js/) 96 | 97 | ## License 98 | 99 | This software is released under the MIT License, see LICENSE. 100 | 101 | [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fkamiazya%2Fngx-face-api-js.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkamiazya%2Fngx-face-api-js?ref=badge_large) 102 | 103 | ## Author 104 | 105 | [kamiazya(Yuki Yamazaki)](https://github.com/kamiazya) 106 | 107 | [![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/W7W5VDNO) 108 | -------------------------------------------------------------------------------- /docs/styles/bootstrap-card.css: -------------------------------------------------------------------------------- 1 | .card { 2 | position: relative; 3 | display: block; 4 | margin-bottom: 20px; 5 | background-color: #fff; 6 | border: 1px solid #ddd; 7 | border-radius: 4px; 8 | } 9 | 10 | .card-block { 11 | padding: 15px; 12 | } 13 | .card-block:before, .card-block:after { 14 | content: " "; 15 | display: table; 16 | } 17 | .card-block:after { 18 | clear: both; 19 | } 20 | 21 | .card-title { 22 | margin: 5px; 23 | margin-bottom: 2px; 24 | text-align: center; 25 | } 26 | 27 | .card-subtitle { 28 | margin-top: -10px; 29 | margin-bottom: 0; 30 | } 31 | 32 | .card-text:last-child { 33 | margin-bottom: 0; 34 | margin-top: 10px; 35 | } 36 | 37 | .card-link:hover { 38 | text-decoration: none; 39 | } 40 | .card-link + .card-link { 41 | margin-left: 15px; 42 | } 43 | 44 | .card > .list-group:first-child .list-group-item:first-child { 45 | border-top-right-radius: 4px; 46 | border-top-left-radius: 4px; 47 | } 48 | .card > .list-group:last-child .list-group-item:last-child { 49 | border-bottom-right-radius: 4px; 50 | border-bottom-left-radius: 4px; 51 | } 52 | 53 | .card-header { 54 | padding: 10px 15px; 55 | background-color: #f5f5f5; 56 | border-bottom: 1px solid #ddd; 57 | } 58 | .card-header:before, .card-header:after { 59 | content: " "; 60 | display: table; 61 | } 62 | .card-header:after { 63 | clear: both; 64 | } 65 | .card-header:first-child { 66 | border-radius: 4px 4px 0 0; 67 | } 68 | 69 | .card-footer { 70 | padding: 10px 15px; 71 | background-color: #f5f5f5; 72 | border-top: 1px solid #ddd; 73 | } 74 | .card-footer:before, .card-footer:after { 75 | content: " "; 76 | display: table; 77 | } 78 | .card-footer:after { 79 | clear: both; 80 | } 81 | .card-footer:last-child { 82 | border-radius: 0 0 4px 4px; 83 | } 84 | 85 | .card-header-tabs { 86 | margin-right: -5px; 87 | margin-bottom: -10px; 88 | margin-left: -5px; 89 | border-bottom: 0; 90 | } 91 | 92 | .card-header-pills { 93 | margin-right: -5px; 94 | margin-left: -5px; 95 | } 96 | 97 | .card-primary { 98 | background-color: #337ab7; 99 | border-color: #337ab7; 100 | } 101 | .card-primary .card-header, 102 | .card-primary .card-footer { 103 | background-color: transparent; 104 | } 105 | 106 | .card-success { 107 | background-color: #5cb85c; 108 | border-color: #5cb85c; 109 | } 110 | .card-success .card-header, 111 | .card-success .card-footer { 112 | background-color: transparent; 113 | } 114 | 115 | .card-info { 116 | background-color: #5bc0de; 117 | border-color: #5bc0de; 118 | } 119 | .card-info .card-header, 120 | .card-info .card-footer { 121 | background-color: transparent; 122 | } 123 | 124 | .card-warning { 125 | background-color: #f0ad4e; 126 | border-color: #f0ad4e; 127 | } 128 | .card-warning .card-header, 129 | .card-warning .card-footer { 130 | background-color: transparent; 131 | } 132 | 133 | .card-danger { 134 | background-color: #d9534f; 135 | border-color: #d9534f; 136 | } 137 | .card-danger .card-header, 138 | .card-danger .card-footer { 139 | background-color: transparent; 140 | } 141 | 142 | .card-outline-primary { 143 | background-color: transparent; 144 | border-color: #337ab7; 145 | } 146 | 147 | .card-outline-secondary { 148 | background-color: transparent; 149 | border-color: #ccc; 150 | } 151 | 152 | .card-outline-info { 153 | background-color: transparent; 154 | border-color: #5bc0de; 155 | } 156 | 157 | .card-outline-success { 158 | background-color: transparent; 159 | border-color: #5cb85c; 160 | } 161 | 162 | .card-outline-warning { 163 | background-color: transparent; 164 | border-color: #f0ad4e; 165 | } 166 | 167 | .card-outline-danger { 168 | background-color: transparent; 169 | border-color: #d9534f; 170 | } 171 | 172 | .card-inverse .card-header, 173 | .card-inverse .card-footer { 174 | border-color: rgba(255, 255, 255, 0.2); 175 | } 176 | .card-inverse .card-header, 177 | .card-inverse .card-footer, 178 | .card-inverse .card-title, 179 | .card-inverse .card-blockquote { 180 | color: #fff; 181 | } 182 | .card-inverse .card-link, 183 | .card-inverse .card-text, 184 | .card-inverse .card-subtitle, 185 | .card-inverse .card-blockquote .blockquote-footer { 186 | color: rgba(255, 255, 255, 0.65); 187 | } 188 | .card-inverse .card-link:hover, .card-inverse .card-link:focus { 189 | color: #fff; 190 | } 191 | 192 | .card-blockquote { 193 | padding: 0; 194 | margin-bottom: 0; 195 | border-left: 0; 196 | } 197 | 198 | .card-img { 199 | border-radius: .25em; 200 | } 201 | 202 | .card-img-overlay { 203 | position: absolute; 204 | top: 0; 205 | right: 0; 206 | bottom: 0; 207 | left: 0; 208 | padding: 15px; 209 | } 210 | 211 | .card-img-top { 212 | border-top-right-radius: 4px; 213 | border-top-left-radius: 4px; 214 | } 215 | 216 | .card-img-bottom { 217 | border-bottom-right-radius: 4px; 218 | border-bottom-left-radius: 4px; 219 | } 220 | -------------------------------------------------------------------------------- /docs/modules.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ngx-face-api-js-demo-app documentation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 24 | 25 |
26 |
27 | 30 | 31 |
32 |
33 | 34 | 35 | 36 | 39 |
40 |
41 |
42 |
43 |
44 |

NgxFaceApiJsModule

45 |
46 |
47 |

48 | 49 | Your browser does not support SVG 50 | 51 |

52 | 55 |
56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
76 |
77 |

result-matching ""

78 |
    79 |
    80 |
    81 |

    No results matching ""

    82 |
    83 |
    84 |
    85 | 86 |
    87 |
    88 | 89 | 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 | -------------------------------------------------------------------------------- /docs/dependencies.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ngx-face-api-js-demo-app documentation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 24 | 25 |
    26 |
    27 | 30 | 31 |
    32 |
    33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 50 |
      51 |
    • 52 | @angular/animations : ~7.2.0
    • 53 |
    • 54 | @angular/cdk : ^7.3.7
    • 55 |
    • 56 | @angular/common : ~7.2.0
    • 57 |
    • 58 | @angular/compiler : ~7.2.0
    • 59 |
    • 60 | @angular/core : ~7.2.0
    • 61 |
    • 62 | @angular/forms : ~7.2.0
    • 63 |
    • 64 | @angular/platform-browser : ~7.2.0
    • 65 |
    • 66 | @angular/platform-browser-dynamic : ~7.2.0
    • 67 |
    • 68 | @angular/router : ~7.2.0
    • 69 |
    • 70 | core-js : ^2.5.4
    • 71 |
    • 72 | face-api.js : ~0.20.0
    • 73 |
    • 74 | rxjs : ~6.3.3
    • 75 |
    • 76 | tslib : ^1.9.0
    • 77 |
    • 78 | zone.js : ~0.8.26
    • 79 |
    80 | 81 | 82 | 83 | 84 | 85 |
    86 |
    87 |

    result-matching ""

    88 |
      89 |
      90 |
      91 |

      No results matching ""

      92 |
      93 |
      94 |
      95 | 96 |
      97 |
      98 | 99 | 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 | -------------------------------------------------------------------------------- /docs/license.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ngx-face-api-js-demo-app documentation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 24 | 25 |
      26 |
      27 | 30 | 31 |
      32 |
      33 | 34 |

      The MIT License (MIT)

      35 |

      Copyright (c) 2019 Yuki Yamazaki

      36 |

      Permission is hereby granted, free of charge, to any person obtaining a copy 37 | of this software and associated documentation files (the "Software"), to deal 38 | in the Software without restriction, including without limitation the rights 39 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 40 | copies of the Software, and to permit persons to whom the Software is 41 | furnished to do so, subject to the following conditions:

      42 |

      The above copyright notice and this permission notice shall be included in all 43 | copies or substantial portions of the Software.

      44 |

      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 45 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 46 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 47 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 48 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 49 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 50 | SOFTWARE.

      51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
      70 |
      71 |

      result-matching ""

      72 |
        73 |
        74 |
        75 |

        No results matching ""

        76 |
        77 |
        78 |
        79 | 80 |
        81 |
        82 | 83 | 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 | -------------------------------------------------------------------------------- /docs/js/libs/bootstrap-native.js: -------------------------------------------------------------------------------- 1 | // Native Javascript for Bootstrap 3 v1.1.0 | © dnp_theme | MIT-License 2 | !function(t,e){if("function"==typeof define&&define.amd)define([],e);else if("object"==typeof module&&module.exports)module.exports=e();else{var o=e();t.Affix=o.Affix,t.Alert=o.Alert,t.Button=o.Button,t.Carousel=o.Carousel,t.Collapse=o.Collapse,t.Dropdown=o.Dropdown,t.Modal=o.Modal,t.Popover=o.Popover,t.ScrollSpy=o.ScrollSpy,t.Tab=o.Tab,t.Tooltip=o.Tooltip}}(this,function(){for(var t=function(t,e){t.classList?t.classList.add(e):(t.className+=" "+e,t.offsetWidth)},e=function(t,e){t.classList?t.classList.remove(e):t.className=t.className.replace(e,"").replace(/^\s+|\s+$/g,"")},o=null!=new RegExp("MSIE ([0-9]{1,}[.0-9]{0,})").exec(navigator.userAgent)&&parseFloat(RegExp.$1),n=function(t,e){for(var o=e.charAt(0);t&&t!==document;t=t.parentNode){if("."===o&&void 0!==document.querySelector(e))return t;if("#"===o&&t.id===e.substr(1))return t}return!1},i=(document,function(i,a){a=a||{},this.btn="object"==typeof i?i:document.querySelector(i),this.accordion=null,this.collapse=null,this.duration=300,this.options={},this.options.duration=o&&o<10?0:a.duration||this.duration;var r=this,s=function(t){var e=t&&(t.currentStyle||window.getComputedStyle(t)),o=/px/.test(e.borderTopWidth)?Math.round(e.borderTopWidth.replace("px","")):0,n=/px/.test(e.marginTop)?Math.round(e.marginTop.replace("px","")):0,i=/px/.test(e.marginBottom)?Math.round(e.marginBottom.replace("px","")):0,a=/em/.test(e.marginTop)?Math.round(e.marginTop.replace("em","")*parseInt(e.fontSize)):0,r=/em/.test(e.marginBottom)?Math.round(e.marginBottom.replace("em","")*parseInt(e.fontSize)):0;return t.clientHeight+parseInt(o)+parseInt(n)+parseInt(i)+parseInt(a)+parseInt(r)};this.toggle=function(t){t.preventDefault(),/\bin/.test(r.collapse.className)?r.close():r.open()},this.close=function(){this._close(this.collapse),t(this.btn,"collapsed")},this.open=function(){if(this._open(this.collapse),e(this.btn,"collapsed"),null!==this.accordion){var t=this.accordion.querySelectorAll(".collapse.in"),o=t.length,n=0;for(n;n1?t[t.length-1]:void 0:t[0]},this.getActiveContent=function(){var t=this.getActiveTab().getElementsByTagName("A")[0].getAttribute("href").replace("#","");return t&&document.getElementById("c-"+t)},this.tab.addEventListener("click",this.handle,!1)},d=document.querySelectorAll("[data-toggle='tab'], [data-toggle='pill']"),u=0,h=d.length;u'; 72 | newNode.color = '#FB7E81'; 73 | newNode.name = COMPONENTS[i].name; 74 | } 75 | } 76 | for(var i = 0; i < DIRECTIVES.length; i++) { 77 | if (value.attributes) { 78 | for(attr in value.attributes) { 79 | if (DIRECTIVES[i].selector.indexOf(attr) !== -1) { 80 | newNode.font = { 81 | multi: 'html' 82 | }; 83 | newNode.label = '' + newNode.label + ''; 84 | newNode.color = '#FF9800'; 85 | newNode.name = DIRECTIVES[i].name; 86 | } 87 | } 88 | } 89 | } 90 | newNodes.push(newNode); 91 | newEdges.push({ 92 | from: parentNode._parent._id, 93 | to: value._id, 94 | arrows: 'to' 95 | }); 96 | } 97 | } 98 | 99 | newNodes.shift(); 100 | 101 | var container = document.getElementById('tree-container'), 102 | data = { 103 | nodes: newNodes, 104 | edges: newEdges 105 | }, 106 | options = { 107 | layout: { 108 | hierarchical: { 109 | sortMethod: 'directed', 110 | enabled: true 111 | } 112 | }, 113 | nodes: { 114 | shape: 'ellipse', 115 | fixed: true 116 | } 117 | }, 118 | 119 | handleClickNode = function(params) { 120 | var clickeNodeId; 121 | if (params.nodes.length > 0) { 122 | clickeNodeId = params.nodes[0]; 123 | for(var i = 0; i < newNodes.length; i++) { 124 | if (newNodes[i].id === clickeNodeId) { 125 | for(var j = 0; j < COMPONENTS.length; j++) { 126 | if (COMPONENTS[j].name === newNodes[i].name) { 127 | document.location.href = currentLocation.origin + currentLocation.pathname.replace(ACTUAL_COMPONENT.name, newNodes[i].name); 128 | } 129 | } 130 | } 131 | } 132 | } 133 | }, 134 | 135 | loadTree = function () { 136 | setTimeout(function() { 137 | container.style.height = document.getElementsByClassName('content')[0].offsetHeight - 140 + 'px'; 138 | var network = new vis.Network(container, data, options); 139 | network.on('click', handleClickNode); 140 | }, 200); // Fade is 0.150 141 | }; 142 | 143 | loadTree(); 144 | treeTab.addEventListener('click', function() { 145 | loadTree(); 146 | }); 147 | }); 148 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "ngx-face-api-demo-app": { 7 | "root": "", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "prefix": "app", 11 | "schematics": { 12 | "@schematics/angular:component": { 13 | "style": "scss" 14 | } 15 | }, 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:browser", 19 | "options": { 20 | "outputPath": "dist/ngx-face-api-demo-app", 21 | "index": "src/index.html", 22 | "main": "src/main.ts", 23 | "polyfills": "src/polyfills.ts", 24 | "tsConfig": "src/tsconfig.app.json", 25 | "assets": ["src/favicon.ico", "src/assets"], 26 | "styles": ["src/styles.scss"], 27 | "scripts": [], 28 | "es5BrowserSupport": true 29 | }, 30 | "configurations": { 31 | "production": { 32 | "fileReplacements": [ 33 | { 34 | "replace": "src/environments/environment.ts", 35 | "with": "src/environments/environment.prod.ts" 36 | } 37 | ], 38 | "optimization": true, 39 | "outputHashing": "all", 40 | "sourceMap": false, 41 | "extractCss": true, 42 | "namedChunks": false, 43 | "aot": true, 44 | "extractLicenses": true, 45 | "vendorChunk": false, 46 | "buildOptimizer": true, 47 | "budgets": [ 48 | { 49 | "type": "initial", 50 | "maximumWarning": "2mb", 51 | "maximumError": "5mb" 52 | } 53 | ] 54 | } 55 | } 56 | }, 57 | "serve": { 58 | "builder": "@angular-devkit/build-angular:dev-server", 59 | "options": { 60 | "browserTarget": "ngx-face-api-demo-app:build" 61 | }, 62 | "configurations": { 63 | "production": { 64 | "browserTarget": "ngx-face-api-demo-app:build:production" 65 | } 66 | } 67 | }, 68 | "extract-i18n": { 69 | "builder": "@angular-devkit/build-angular:extract-i18n", 70 | "options": { 71 | "browserTarget": "ngx-face-api-demo-app:build" 72 | } 73 | }, 74 | "test": { 75 | "builder": "@angular-devkit/build-angular:karma", 76 | "options": { 77 | "main": "src/test.ts", 78 | "polyfills": "src/polyfills.ts", 79 | "tsConfig": "src/tsconfig.spec.json", 80 | "karmaConfig": "src/karma.conf.js", 81 | "styles": ["src/styles.scss"], 82 | "scripts": [], 83 | "assets": ["src/favicon.ico", "src/assets"] 84 | } 85 | }, 86 | "lint": { 87 | "builder": "@angular-devkit/build-angular:tslint", 88 | "options": { 89 | "tsConfig": ["src/tsconfig.app.json", "src/tsconfig.spec.json"], 90 | "exclude": ["**/node_modules/**"] 91 | } 92 | } 93 | } 94 | }, 95 | "ngx-face-api-demo-app-e2e": { 96 | "root": "e2e/", 97 | "projectType": "application", 98 | "prefix": "", 99 | "architect": { 100 | "e2e": { 101 | "builder": "@angular-devkit/build-angular:protractor", 102 | "options": { 103 | "protractorConfig": "e2e/protractor.conf.js", 104 | "devServerTarget": "ngx-face-api-demo-app:serve" 105 | }, 106 | "configurations": { 107 | "production": { 108 | "devServerTarget": "ngx-face-api-demo-app:serve:production" 109 | } 110 | } 111 | }, 112 | "lint": { 113 | "builder": "@angular-devkit/build-angular:tslint", 114 | "options": { 115 | "tsConfig": "e2e/tsconfig.e2e.json", 116 | "exclude": ["**/node_modules/**"] 117 | } 118 | } 119 | } 120 | }, 121 | "ngx-face-api-js": { 122 | "root": "projects/ngx-face-api-js", 123 | "sourceRoot": "projects/ngx-face-api-js/src", 124 | "projectType": "library", 125 | "prefix": "lib", 126 | "architect": { 127 | "build": { 128 | "builder": "@angular-devkit/build-ng-packagr:build", 129 | "options": { 130 | "tsConfig": "projects/ngx-face-api-js/tsconfig.lib.json", 131 | "project": "projects/ngx-face-api-js/ng-package.json" 132 | } 133 | }, 134 | "test": { 135 | "builder": "@angular-devkit/build-angular:karma", 136 | "options": { 137 | "main": "projects/ngx-face-api-js/src/test.ts", 138 | "tsConfig": "projects/ngx-face-api-js/tsconfig.spec.json", 139 | "karmaConfig": "projects/ngx-face-api-js/karma.conf.js" 140 | } 141 | }, 142 | "lint": { 143 | "builder": "@angular-devkit/build-angular:tslint", 144 | "options": { 145 | "tsConfig": [ 146 | "projects/ngx-face-api-js/tsconfig.lib.json", 147 | "projects/ngx-face-api-js/tsconfig.spec.json" 148 | ], 149 | "exclude": ["**/node_modules/**"] 150 | } 151 | } 152 | } 153 | } 154 | }, 155 | "defaultProject": "ngx-face-api-demo-app", 156 | "cli": { 157 | "packageManager": "yarn" 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /docs/styles/prism.css: -------------------------------------------------------------------------------- 1 | /* http://prismjs.com/download.html?themes=prism-okaidia&languages=markup+css+clike+javascript+json+markdown+typescript&plugins=line-highlight+line-numbers+toolbar+copy-to-clipboard */ 2 | /** 3 | * okaidia theme for JavaScript, CSS and HTML 4 | * Loosely based on Monokai textmate theme by http://www.monokai.nl/ 5 | * @author ocodia 6 | */ 7 | 8 | code[class*="language-"], 9 | pre[class*="language-"] { 10 | color: #f8f8f2; 11 | background: none; 12 | text-shadow: 0 1px rgba(0, 0, 0, 0.3); 13 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 14 | text-align: left; 15 | white-space: pre; 16 | word-spacing: normal; 17 | word-break: normal; 18 | word-wrap: normal; 19 | line-height: 1.5; 20 | 21 | -moz-tab-size: 4; 22 | -o-tab-size: 4; 23 | tab-size: 4; 24 | 25 | -webkit-hyphens: none; 26 | -moz-hyphens: none; 27 | -ms-hyphens: none; 28 | hyphens: none; 29 | } 30 | 31 | /* Code blocks */ 32 | pre[class*="language-"] { 33 | padding: 1em; 34 | margin: .5em 0; 35 | overflow: auto; 36 | border-radius: 0.3em; 37 | } 38 | 39 | :not(pre) > code[class*="language-"], 40 | pre[class*="language-"] { 41 | background: #272822; 42 | } 43 | 44 | /* Inline code */ 45 | :not(pre) > code[class*="language-"] { 46 | padding: .1em; 47 | border-radius: .3em; 48 | white-space: normal; 49 | } 50 | 51 | .token.comment, 52 | .token.prolog, 53 | .token.doctype, 54 | .token.cdata { 55 | color: slategray; 56 | } 57 | 58 | .token.punctuation { 59 | color: #f8f8f2; 60 | } 61 | 62 | .namespace { 63 | opacity: .7; 64 | } 65 | 66 | .token.property, 67 | .token.tag, 68 | .token.constant, 69 | .token.symbol, 70 | .token.deleted { 71 | color: #f92672; 72 | } 73 | 74 | .token.boolean, 75 | .token.number { 76 | color: #ae81ff; 77 | } 78 | 79 | .token.selector, 80 | .token.attr-name, 81 | .token.string, 82 | .token.char, 83 | .token.builtin, 84 | .token.inserted { 85 | color: #a6e22e; 86 | } 87 | 88 | .token.operator, 89 | .token.entity, 90 | .token.url, 91 | .language-css .token.string, 92 | .style .token.string, 93 | .token.variable { 94 | color: #f8f8f2; 95 | } 96 | 97 | .token.atrule, 98 | .token.attr-value, 99 | .token.function { 100 | color: #e6db74; 101 | } 102 | 103 | .token.keyword { 104 | color: #66d9ef; 105 | } 106 | 107 | .token.regex, 108 | .token.important { 109 | color: #fd971f; 110 | } 111 | 112 | .token.important, 113 | .token.bold { 114 | font-weight: bold; 115 | } 116 | .token.italic { 117 | font-style: italic; 118 | } 119 | 120 | .token.entity { 121 | cursor: help; 122 | } 123 | 124 | pre[data-line] { 125 | position: relative; 126 | padding: 1em 0 1em 3em; 127 | } 128 | 129 | .line-highlight { 130 | position: absolute; 131 | left: 0; 132 | right: 0; 133 | padding: inherit 0; 134 | margin-top: 1em; /* Same as .prism’s padding-top */ 135 | 136 | background: hsla(24, 20%, 50%,.08); 137 | background: linear-gradient(to right, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0)); 138 | 139 | pointer-events: none; 140 | 141 | line-height: inherit; 142 | white-space: pre; 143 | } 144 | 145 | .line-highlight:before, 146 | .line-highlight[data-end]:after { 147 | content: attr(data-start); 148 | position: absolute; 149 | top: .4em; 150 | left: .6em; 151 | min-width: 1em; 152 | padding: 0 .5em; 153 | background-color: hsla(24, 20%, 50%,.4); 154 | color: hsl(24, 20%, 95%); 155 | font: bold 65%/1.5 sans-serif; 156 | text-align: center; 157 | vertical-align: .3em; 158 | border-radius: 999px; 159 | text-shadow: none; 160 | box-shadow: 0 1px white; 161 | } 162 | 163 | .line-highlight[data-end]:after { 164 | content: attr(data-end); 165 | top: auto; 166 | bottom: .4em; 167 | } 168 | 169 | pre.line-numbers { 170 | position: relative; 171 | padding-left: 3.8em; 172 | counter-reset: linenumber; 173 | } 174 | 175 | pre.line-numbers > code { 176 | position: relative; 177 | white-space: inherit; 178 | } 179 | 180 | .line-numbers .line-numbers-rows { 181 | position: absolute; 182 | pointer-events: none; 183 | top: 0; 184 | font-size: 100%; 185 | left: -3.8em; 186 | width: 3em; /* works for line-numbers below 1000 lines */ 187 | letter-spacing: -1px; 188 | border-right: 1px solid #999; 189 | 190 | -webkit-user-select: none; 191 | -moz-user-select: none; 192 | -ms-user-select: none; 193 | user-select: none; 194 | 195 | } 196 | 197 | .line-numbers-rows > span { 198 | pointer-events: none; 199 | display: block; 200 | counter-increment: linenumber; 201 | } 202 | 203 | .line-numbers-rows > span:before { 204 | content: counter(linenumber); 205 | color: #999; 206 | display: block; 207 | padding-right: 0.8em; 208 | text-align: right; 209 | } 210 | div.code-toolbar { 211 | position: relative; 212 | } 213 | 214 | div.code-toolbar > .toolbar { 215 | position: absolute; 216 | top: .3em; 217 | right: .2em; 218 | transition: opacity 0.3s ease-in-out; 219 | opacity: 0; 220 | } 221 | 222 | div.code-toolbar:hover > .toolbar { 223 | opacity: 1; 224 | } 225 | 226 | div.code-toolbar > .toolbar .toolbar-item { 227 | display: inline-block; 228 | } 229 | 230 | div.code-toolbar > .toolbar a { 231 | cursor: pointer; 232 | } 233 | 234 | div.code-toolbar > .toolbar button { 235 | background: none; 236 | border: 0; 237 | color: inherit; 238 | font: inherit; 239 | line-height: normal; 240 | overflow: visible; 241 | padding: 0; 242 | -webkit-user-select: none; /* for button */ 243 | -moz-user-select: none; 244 | -ms-user-select: none; 245 | } 246 | 247 | div.code-toolbar > .toolbar a, 248 | div.code-toolbar > .toolbar button, 249 | div.code-toolbar > .toolbar span { 250 | color: #bbb; 251 | font-size: .8em; 252 | padding: 0 .5em; 253 | background: #f5f2f0; 254 | background: rgba(224, 224, 224, 0.2); 255 | box-shadow: 0 2px 0 0 rgba(0,0,0,0.2); 256 | border-radius: .5em; 257 | } 258 | 259 | div.code-toolbar > .toolbar a:hover, 260 | div.code-toolbar > .toolbar a:focus, 261 | div.code-toolbar > .toolbar button:hover, 262 | div.code-toolbar > .toolbar button:focus, 263 | div.code-toolbar > .toolbar span:hover, 264 | div.code-toolbar > .toolbar span:focus { 265 | color: inherit; 266 | text-decoration: none; 267 | } -------------------------------------------------------------------------------- /docs/interfaces/Schema.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ngx-face-api-js-demo-app documentation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 24 | 25 |
        26 |
        27 | 30 | 31 |
        32 |
        33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 49 | 50 | 58 | 59 |
        60 |
        61 |

        62 |

        File

        63 |

        64 |

        65 | projects/ngx-face-api-js/schematics/ng-add/Schema.ts 66 |

        67 | 68 | 69 | 70 |
        71 |

        Index

        72 | 73 | 74 | 75 | 78 | 79 | 80 | 87 | 88 | 89 |
        76 |
        Properties
        77 |
        81 | 86 |
        90 |
        91 | 92 | 93 | 94 |
        95 |

        Properties

        96 | 97 | 98 | 99 | 103 | 104 | 105 | 109 | 110 | 111 | 112 | 113 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 |
        100 | 101 | project 102 |
        106 | project: string 107 | 108 |
        114 | Type : string 115 | 116 |
        125 |
        126 |
        127 | 128 | 129 |
        130 |
        export interface Schema {
        131 |   project: string;
        132 | }
        133 | 
        134 |
        135 |
        136 | 137 | 138 | 139 | 140 | 141 | 142 |
        143 |
        144 |

        result-matching ""

        145 |
          146 |
          147 |
          148 |

          No results matching ""

          149 |
          150 |
          151 |
          152 | 153 |
          154 |
          155 | 156 | 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 | -------------------------------------------------------------------------------- /docs/miscellaneous/typealiases.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ngx-face-api-js-demo-app documentation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 24 | 25 |
          26 |
          27 | 30 | 31 |
          32 |
          33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 52 | 53 |
          54 |

          Index

          55 | 56 | 57 | 58 | 71 | 72 | 73 |
          59 | 70 |
          74 |
          75 | 76 |

          projects/ngx-face-api-js/src/lib/tokens/FeatureToken.ts

          77 |
          78 | 79 | 80 | 81 | 85 | 86 | 87 | 91 | 92 | 93 |
          82 | 83 | FeatureToken 84 |
          88 | "expressions" | "landmarks" | "descriptors" | "ageAndGender" 89 | 90 |
          94 |

          projects/ngx-face-api-js/src/lib/tokens/ModelToken.ts

          95 |
          96 | 97 | 98 | 99 | 103 | 104 | 105 | 109 | 110 | 111 |
          100 | 101 | ModelToken 102 |
          106 | "SsdMobilenetv1Model" | "MtcnnModel" | "FaceExpressionModel" | "FaceLandmarkModel" | "FaceRecognitionModel" | "TinyFaceDetectorModel" | "AgeAndGenderModel" 107 | 108 |
          112 |

          projects/ngx-face-api-js/src/lib/tokens/TaskTypeToken.ts

          113 |
          114 | 115 | 116 | 117 | 121 | 122 | 123 | 127 | 128 | 129 |
          118 | 119 | TaskTypeToken 120 |
          124 | "all" | "single" 125 | 126 |
          130 |
          131 | 132 | 133 |
          134 |
          135 |

          result-matching ""

          136 |
            137 |
            138 |
            139 |

            No results matching ""

            140 |
            141 |
            142 |
            143 | 144 |
            145 |
            146 | 147 | 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 | -------------------------------------------------------------------------------- /docs/graph/dependencies.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | dependencies 11 | 12 | Legend 13 | 14 |  Declarations 15 | 16 |  Module 17 | 18 |  Bootstrap 19 | 20 |  Providers 21 | 22 |  Exports 23 | 24 | cluster_NgxFaceApiJsModule 25 | 26 | 27 | 28 | cluster_NgxFaceApiJsModule_declarations 29 | 30 | 31 | 32 | cluster_NgxFaceApiJsModule_exports 33 | 34 | 35 | 36 | 37 | DetectAllFacesImgDirective 38 | 39 | DetectAllFacesImgDirective 40 | 41 | 42 | 43 | NgxFaceApiJsModule 44 | 45 | NgxFaceApiJsModule 46 | 47 | 48 | 49 | DetectAllFacesImgDirective->NgxFaceApiJsModule 50 | 51 | 52 | 53 | 54 | 55 | DetectAllFacesVideoDirective 56 | 57 | DetectAllFacesVideoDirective 58 | 59 | 60 | 61 | DetectAllFacesVideoDirective->NgxFaceApiJsModule 62 | 63 | 64 | 65 | 66 | 67 | DetectSingleFaceImgDirective 68 | 69 | DetectSingleFaceImgDirective 70 | 71 | 72 | 73 | DetectSingleFaceImgDirective->NgxFaceApiJsModule 74 | 75 | 76 | 77 | 78 | 79 | DetectionResultComponent 80 | 81 | DetectionResultComponent 82 | 83 | 84 | 85 | DetectionResultComponent->NgxFaceApiJsModule 86 | 87 | 88 | 89 | 90 | 91 | DetectAllFacesImgDirective 92 | 93 | DetectAllFacesImgDirective 94 | 95 | 96 | 97 | NgxFaceApiJsModule->DetectAllFacesImgDirective 98 | 99 | 100 | 101 | 102 | 103 | DetectAllFacesVideoDirective 104 | 105 | DetectAllFacesVideoDirective 106 | 107 | 108 | 109 | NgxFaceApiJsModule->DetectAllFacesVideoDirective 110 | 111 | 112 | 113 | 114 | 115 | DetectSingleFaceImgDirective 116 | 117 | DetectSingleFaceImgDirective 118 | 119 | 120 | 121 | NgxFaceApiJsModule->DetectSingleFaceImgDirective 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /docs/modules/NgxFaceApiJsModule/dependencies.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | dependencies 11 | 12 | Legend 13 | 14 |  Declarations 15 | 16 |  Module 17 | 18 |  Bootstrap 19 | 20 |  Providers 21 | 22 |  Exports 23 | 24 | cluster_NgxFaceApiJsModule 25 | 26 | 27 | 28 | cluster_NgxFaceApiJsModule_declarations 29 | 30 | 31 | 32 | cluster_NgxFaceApiJsModule_exports 33 | 34 | 35 | 36 | 37 | DetectAllFacesImgDirective 38 | 39 | DetectAllFacesImgDirective 40 | 41 | 42 | 43 | NgxFaceApiJsModule 44 | 45 | NgxFaceApiJsModule 46 | 47 | 48 | 49 | DetectAllFacesImgDirective->NgxFaceApiJsModule 50 | 51 | 52 | 53 | 54 | 55 | DetectAllFacesVideoDirective 56 | 57 | DetectAllFacesVideoDirective 58 | 59 | 60 | 61 | DetectAllFacesVideoDirective->NgxFaceApiJsModule 62 | 63 | 64 | 65 | 66 | 67 | DetectSingleFaceImgDirective 68 | 69 | DetectSingleFaceImgDirective 70 | 71 | 72 | 73 | DetectSingleFaceImgDirective->NgxFaceApiJsModule 74 | 75 | 76 | 77 | 78 | 79 | DetectionResultComponent 80 | 81 | DetectionResultComponent 82 | 83 | 84 | 85 | DetectionResultComponent->NgxFaceApiJsModule 86 | 87 | 88 | 89 | 90 | 91 | DetectAllFacesImgDirective 92 | 93 | DetectAllFacesImgDirective 94 | 95 | 96 | 97 | NgxFaceApiJsModule->DetectAllFacesImgDirective 98 | 99 | 100 | 101 | 102 | 103 | DetectAllFacesVideoDirective 104 | 105 | DetectAllFacesVideoDirective 106 | 107 | 108 | 109 | NgxFaceApiJsModule->DetectAllFacesVideoDirective 110 | 111 | 112 | 113 | 114 | 115 | DetectSingleFaceImgDirective 116 | 117 | DetectSingleFaceImgDirective 118 | 119 | 120 | 121 | NgxFaceApiJsModule->DetectSingleFaceImgDirective 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ngx-face-api-js-demo-app documentation 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 24 | 25 |
            26 |
            27 | 30 | 31 |
            32 |
            33 | 34 |

            NgxFaceApiJs

            35 |

            Build Status codecov CodeFactor Maintainability BCH compliance FOSSA Status License: MIT npm version code style: prettier

            36 |

            Angular directives for face detection and face recognition in the browser.

            37 |

            It is a wrapper for face-api.js, so it is not dependent on the browser implementation.

            38 |

            NPM

            39 |

            Description

            40 |

            Make face and emotion recognition features easy to use in Angular projects by using face-api.js.

            41 |
              42 |
            • Recognize faces, emotions and so on in Angular project.
            • 43 |
            • Works in a Mobile.
            • 44 |
            • No Script/Styles reqired, you only embed attribute to img/video tag.
            • 45 |
            • Schematics Support, you can quickly set up a project using the ng add and ng update command.
            • 46 |
            47 |

            How it works?

            48 |

            Overlay canvas on img tag with embedded attributes such as singleFace and allFaces by using Angular CDK Overlay.

            49 |

            How it works

            50 |

            And render the recognition result on canvas according to the content of the with attribute.

            51 |

            Background

            52 | 56 |

            Demo

            57 | 60 |

            Usage

            61 |

            Detect All Faces

            62 |

            html 63 | <img allFaces [src]="imageSrc" width="300px" />

            64 |

            Detect faces

            65 |

            Detect Face With Expressions and Landmarks

            66 |

            html 67 | <img 68 | singleFace 69 | [with]="['expressions', 'landmarks']" 70 | [src]="imageSrc" 71 | width="300px" 72 | />

            73 |

            Detected Face With Expressions and Landmarks

            74 |

            Installation

            75 |

            By ng-add Schematics

            76 |

            bash 77 | $ ng add ngx-face-api-js 78 | ... 79 | UPDATE package.json (1457 bytes) 80 | UPDATE src/styles.css (126 bytes) 81 | UPDATE src/app/app.module.ts (497 bytes)

            82 |

            By Manual

            83 |

            See Wiki.

            84 |

            Update

            85 |

            By ng-update Schematics

            86 |

            bash 87 | $ ng update ngx-face-api-js 88 | ✅️ Added dependency: face-api.js@~0.20.0 89 | ✅️ Dependencies installed 90 | UPDATE package.json (1440 bytes)

            91 |

            Documantation

            92 | 95 |

            License

            96 |

            This software is released under the MIT License, see LICENSE.

            97 |

            FOSSA Status

            98 |

            Author

            99 |

            kamiazya(Yuki Yamazaki)

            100 |

            ko-fi

            101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 |
            120 |
            121 |

            result-matching ""

            122 |
              123 |
              124 |
              125 |

              No results matching ""

              126 |
              127 |
              128 |
              129 | 130 |
              131 |
              132 | 133 | 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 | --------------------------------------------------------------------------------