@@ -2343,6 +2343,12 @@ | |||||
"resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", | "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", | ||||
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=" | "integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=" | ||||
}, | }, | ||||
"@types/dom-mediacapture-record": { | |||||
"version": "1.0.7", | |||||
"resolved": "https://registry.npmjs.org/@types/dom-mediacapture-record/-/dom-mediacapture-record-1.0.7.tgz", | |||||
"integrity": "sha512-ddDIRTO1ajtbxaNo2o7fPJggpN54PZf1ZUJKOjto2ENMJE/9GKUvaw3ZRuQzlS/p0E+PnIcssxfoqYJ4yiXSBw==", | |||||
"dev": true | |||||
}, | |||||
"@types/glob": { | "@types/glob": { | ||||
"version": "7.1.3", | "version": "7.1.3", | ||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", | "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", | ||||
@@ -4909,6 +4915,21 @@ | |||||
"timsort": "^0.3.0" | "timsort": "^0.3.0" | ||||
} | } | ||||
}, | }, | ||||
"css-line-break": { | |||||
"version": "1.1.1", | |||||
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-1.1.1.tgz", | |||||
"integrity": "sha512-1feNVaM4Fyzdj4mKPIQNL2n70MmuYzAXZ1aytlROFX1JsOo070OsugwGjj7nl6jnDJWHDM8zRZswkmeYVWZJQA==", | |||||
"requires": { | |||||
"base64-arraybuffer": "^0.2.0" | |||||
}, | |||||
"dependencies": { | |||||
"base64-arraybuffer": { | |||||
"version": "0.2.0", | |||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz", | |||||
"integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==" | |||||
} | |||||
} | |||||
}, | |||||
"css-loader": { | "css-loader": { | ||||
"version": "3.5.3", | "version": "3.5.3", | ||||
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.5.3.tgz", | "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.5.3.tgz", | ||||
@@ -5556,6 +5577,11 @@ | |||||
"resolved": "https://registry.npmjs.org/dom-storage/-/dom-storage-2.1.0.tgz", | "resolved": "https://registry.npmjs.org/dom-storage/-/dom-storage-2.1.0.tgz", | ||||
"integrity": "sha512-g6RpyWXzl0RR6OTElHKBl7nwnK87GUyZMYC7JWsB/IA73vpqK2K6LT39x4VepLxlSsWBFrPVLnsSR5Jyty0+2Q==" | "integrity": "sha512-g6RpyWXzl0RR6OTElHKBl7nwnK87GUyZMYC7JWsB/IA73vpqK2K6LT39x4VepLxlSsWBFrPVLnsSR5Jyty0+2Q==" | ||||
}, | }, | ||||
"dom-to-image": { | |||||
"version": "2.6.0", | |||||
"resolved": "https://registry.npmjs.org/dom-to-image/-/dom-to-image-2.6.0.tgz", | |||||
"integrity": "sha1-ilA2CAiMh7HCL5A0rgMuGJiVWGc=" | |||||
}, | |||||
"domain-browser": { | "domain-browser": { | ||||
"version": "1.2.0", | "version": "1.2.0", | ||||
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", | "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", | ||||
@@ -7207,6 +7233,14 @@ | |||||
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", | "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", | ||||
"dev": true | "dev": true | ||||
}, | }, | ||||
"html2canvas": { | |||||
"version": "1.0.0-rc.7", | |||||
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.0.0-rc.7.tgz", | |||||
"integrity": "sha512-yvPNZGejB2KOyKleZspjK/NruXVQuowu8NnV2HYG7gW7ytzl+umffbtUI62v2dCHQLDdsK6HIDtyJZ0W3neerA==", | |||||
"requires": { | |||||
"css-line-break": "1.1.1" | |||||
} | |||||
}, | |||||
"htmlparser2": { | "htmlparser2": { | ||||
"version": "3.10.1", | "version": "3.10.1", | ||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", | ||||
@@ -11,6 +11,11 @@ | |||||
"lint": "ng lint", | "lint": "ng lint", | ||||
"e2e": "ng e2e" | "e2e": "ng e2e" | ||||
}, | }, | ||||
"browser": { | |||||
"fs": false, | |||||
"os": false, | |||||
"path": false | |||||
}, | |||||
"private": true, | "private": true, | ||||
"dependencies": { | "dependencies": { | ||||
"@angular/common": "~10.0.0", | "@angular/common": "~10.0.0", | ||||
@@ -28,10 +33,12 @@ | |||||
"@ionic-native/status-bar": "^5.0.0", | "@ionic-native/status-bar": "^5.0.0", | ||||
"@ionic/angular": "^5.0.0", | "@ionic/angular": "^5.0.0", | ||||
"cordova-res": "^0.15.2", | "cordova-res": "^0.15.2", | ||||
"dom-to-image": "^2.6.0", | |||||
"face-api.js": "^0.22.2", | "face-api.js": "^0.22.2", | ||||
"faker": "^5.1.0", | "faker": "^5.1.0", | ||||
"firebase": "^8.2.6", | "firebase": "^8.2.6", | ||||
"hammerjs": "^2.0.8", | "hammerjs": "^2.0.8", | ||||
"html2canvas": "^1.0.0-rc.7", | |||||
"moment": "^2.29.1", | "moment": "^2.29.1", | ||||
"rxjs": "~6.5.5", | "rxjs": "~6.5.5", | ||||
"sharp": "^0.27.0", | "sharp": "^0.27.0", | ||||
@@ -47,6 +54,7 @@ | |||||
"@angular/compiler-cli": "~10.0.0", | "@angular/compiler-cli": "~10.0.0", | ||||
"@angular/language-service": "~10.0.0", | "@angular/language-service": "~10.0.0", | ||||
"@ionic/angular-toolkit": "^2.3.0", | "@ionic/angular-toolkit": "^2.3.0", | ||||
"@types/dom-mediacapture-record": "^1.0.7", | |||||
"@types/jasmine": "~3.5.0", | "@types/jasmine": "~3.5.0", | ||||
"@types/jasminewd2": "~2.0.3", | "@types/jasminewd2": "~2.0.3", | ||||
"@types/node": "^12.11.1", | "@types/node": "^12.11.1", | ||||
@@ -1,9 +1,21 @@ | |||||
<ion-content> | <ion-content> | ||||
<div class="container"> | |||||
<button class="back-button" (click)="back()"> <ion-icon name="close-outline"></ion-icon> </button> | |||||
<div class="container" #container id="container"> | |||||
<img class="glass-image" [ngStyle]="glassProperties" src="/assets/ar-accessories/glass.png" alt=""/> | <img class="glass-image" [ngStyle]="glassProperties" src="/assets/ar-accessories/glass.png" alt=""/> | ||||
<video id="playback-video" #videoElement autoPlay></video> | |||||
<button *ngIf="areNeuralNetsLoaded" (click)="getCameraStream()">Get access</button> | |||||
<button *ngIf="areNeuralNetsLoaded" (click)="stopCameraStream()">Stop stream</button> | |||||
<button *ngIf="areNeuralNetsLoaded" (click)="toggleDetection()">{{ isDetecting ? 'Stop detection' : 'Detect and draw' }}</button>} | |||||
<video id="playback-video" width="{{ width }}" height="{{ height }}" #videoElement autoPlay></video> | |||||
</div> | |||||
<img [src]="temp" *ngIf="temp" #temp class="test-img" width="100px" height="100px" alt=""> | |||||
<div class="action-buttons"> | |||||
<!-- <button *ngIf="areNeuralNetsLoaded" (click)="stopCameraStream()">Stop stream</button> --> | |||||
<!-- <button *ngIf="areNeuralNetsLoaded" (click)="toggleDetection()">{{ isDetecting ? 'Stop detection' : 'Detect and draw' }}</button> --> | |||||
<button class="camera-button" (click)="capture()"> <ion-icon name="camera"></ion-icon> </button> | |||||
<button class="skin-button" *ngIf="areNeuralNetsLoaded" (click)="toggleDetection()" | |||||
[ngClass]="{'active' : isDetecting }"> <ion-icon name="glasses"></ion-icon> </button> | |||||
</div> | </div> | ||||
</ion-content> | </ion-content> |
@@ -1,5 +1,32 @@ | |||||
@import '../colors'; | @import '../colors'; | ||||
.test-img { | |||||
position: fixed; | |||||
z-index: 1; | |||||
left: 50%; | |||||
top: 50%; | |||||
} | |||||
.back-button { | |||||
position: fixed; | |||||
top: 10px; | |||||
right: 10px; | |||||
width: 40px; | |||||
height: 40px; | |||||
background: rgba(white, 0.5); | |||||
border: 0px; | |||||
border-radius: 50%; | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: center; | |||||
z-index: 3; | |||||
ion-icon { | |||||
color: white; | |||||
font-size: 20px; | |||||
} | |||||
} | |||||
.container { | .container { | ||||
position: relative; | position: relative; | ||||
} | } | ||||
@@ -13,11 +40,6 @@ | |||||
#playback-video, #result-canvas, #three-container { | #playback-video, #result-canvas, #three-container { | ||||
display: block; | display: block; | ||||
width: 100vw; | |||||
height: 75vw; | |||||
max-width: 600px; | |||||
max-height: 450px; | |||||
} | } | ||||
#result-canvas, #three-container { | #result-canvas, #three-container { | ||||
@@ -39,4 +61,43 @@ | |||||
.right-eye { | .right-eye { | ||||
background-color: red; | background-color: red; | ||||
} | |||||
.action-buttons { | |||||
position: fixed; | |||||
left: 0; | |||||
bottom: 20px; | |||||
display: flex; | |||||
align-items: center; | |||||
width: 100%; | |||||
button { | |||||
width: 50px; | |||||
height: 50px; | |||||
background-color: white; | |||||
color: $pink; | |||||
border-radius: 50%; | |||||
ion-icon { | |||||
font-size: 25px; | |||||
} | |||||
&.camera-button { | |||||
margin-left: calc(50% - 25px); | |||||
transform: scale(1.5); | |||||
} | |||||
&.skin-button { | |||||
transform: scale(1.2); | |||||
margin-left: 40px; | |||||
background-color: transparent; | |||||
border: 2px solid $pink; | |||||
&.active { | |||||
background-color: $pink; | |||||
color: white; | |||||
} | |||||
} | |||||
} | |||||
} | } |
@@ -1,5 +1,7 @@ | |||||
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; | import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; | ||||
import { detectSingleFace, loadFaceExpressionModel, loadFaceLandmarkModel, loadFaceLandmarkTinyModel, loadFaceRecognitionModel, loadSsdMobilenetv1Model, loadTinyFaceDetectorModel, TinyFaceDetectorOptions } from 'face-api.js'; | import { detectSingleFace, loadFaceExpressionModel, loadFaceLandmarkModel, loadFaceLandmarkTinyModel, loadFaceRecognitionModel, loadSsdMobilenetv1Model, loadTinyFaceDetectorModel, TinyFaceDetectorOptions } from 'face-api.js'; | ||||
import domtoimage from 'dom-to-image'; | |||||
import { Location } from '@angular/common'; | |||||
@Component({ | @Component({ | ||||
selector: 'app-ar-fan-cam', | selector: 'app-ar-fan-cam', | ||||
@@ -8,6 +10,7 @@ import { detectSingleFace, loadFaceExpressionModel, loadFaceLandmarkModel, loadF | |||||
}) | }) | ||||
export class ArFanCamPage implements OnInit { | export class ArFanCamPage implements OnInit { | ||||
@ViewChild('videoElement', null) videoElement: ElementRef<HTMLVideoElement>; | @ViewChild('videoElement', null) videoElement: ElementRef<HTMLVideoElement>; | ||||
mediaStream: MediaStream|null = null; | mediaStream: MediaStream|null = null; | ||||
glassProperties: { | glassProperties: { | ||||
@@ -22,7 +25,14 @@ export class ArFanCamPage implements OnInit { | |||||
width = 360; | width = 360; | ||||
height = 270; | height = 270; | ||||
constructor() { } | |||||
temp: any; | |||||
stream: any; | |||||
constructor( | |||||
private location: Location | |||||
) { } | |||||
loadNeuralNetModels = async () => { | loadNeuralNetModels = async () => { | ||||
await loadTinyFaceDetectorModel('/assets/weights'); | await loadTinyFaceDetectorModel('/assets/weights'); | ||||
@@ -37,25 +47,47 @@ export class ArFanCamPage implements OnInit { | |||||
this.areNeuralNetsLoaded = true; | this.areNeuralNetsLoaded = true; | ||||
} | } | ||||
back() { | |||||
this.location.back(); | |||||
this.stopCameraStream(); | |||||
} | |||||
getCameraStream = async () => { | getCameraStream = async () => { | ||||
const stream = await window.navigator.mediaDevices.getUserMedia({ | const stream = await window.navigator.mediaDevices.getUserMedia({ | ||||
video: { | video: { | ||||
facingMode: 'user', | facingMode: 'user', | ||||
width: this.width, | width: this.width, | ||||
height: this.height | |||||
}, | }, | ||||
}); | |||||
this.mediaStream = stream; | |||||
this.videoElement.nativeElement.srcObject = stream; | |||||
}).then((stream) => { | |||||
this.mediaStream = stream; | |||||
this.videoElement.nativeElement.srcObject = stream; | |||||
}).catch(err => alert(JSON.stringify(err))); | |||||
}; | }; | ||||
stopCameraStream = async () => { | stopCameraStream = async () => { | ||||
if (this.mediaStream) { | if (this.mediaStream) { | ||||
this.mediaStream.getVideoTracks().forEach(track => track.stop()); | |||||
this.mediaStream.getVideoTracks().forEach(track => { | |||||
track.stop(); | |||||
}); | |||||
this.mediaStream = null; | this.mediaStream = null; | ||||
this.stream = null; | |||||
} | } | ||||
} | } | ||||
async capture() { | |||||
let element: HTMLElement = document.querySelector('#container'); | |||||
await domtoimage.toPng(element).then((dataUrl) => { | |||||
this.temp = dataUrl; | |||||
console.log(dataUrl); | |||||
}) | |||||
.catch((error) => { | |||||
console.error('oops, something went wrong!', error); | |||||
}); | |||||
} | |||||
detectAndDrawFace = async () => { | detectAndDrawFace = async () => { | ||||
const tinyFaceDetectorOptions = new TinyFaceDetectorOptions(); | const tinyFaceDetectorOptions = new TinyFaceDetectorOptions(); | ||||
@@ -87,14 +119,19 @@ export class ArFanCamPage implements OnInit { | |||||
} | } | ||||
} | } | ||||
ngOnInit() { | |||||
ngOnInit() { | |||||
} | |||||
ngAfterViewInit() { | |||||
this.loadNeuralNetModels(); | this.loadNeuralNetModels(); | ||||
const feedWidth = window.innerWidth > 600 ? 600 : window.innerWidth; | |||||
const feedHeight = feedWidth * 0.75; | |||||
const feedWidth = window.innerWidth; | |||||
const feedHeight = window.innerHeight; | |||||
this.width = feedWidth; | this.width = feedWidth; | ||||
this.height = feedHeight; | this.height = feedHeight; | ||||
this.getCameraStream().then(() => this.detectAndDrawFace(), (err) => console.log(err)); | |||||
} | } | ||||
} | } |
@@ -87,7 +87,13 @@ export class FanZonePage implements OnInit { | |||||
} | } | ||||
ngAfterViewInit() { | ngAfterViewInit() { | ||||
this.showSocialLogin = true; | |||||
if (localStorage.googleUserData) { | |||||
this.googleUserData = JSON.parse(localStorage.googleUserData); | |||||
this.showSocialLogin = false; | |||||
} else { | |||||
this.googleUserData = {}; | |||||
this.showSocialLogin = true; | |||||
} | |||||
} | } | ||||
generateEmojiStream() { | generateEmojiStream() { | ||||
@@ -153,6 +159,9 @@ export class FanZonePage implements OnInit { | |||||
profileImage: data.user.photoURL, | profileImage: data.user.photoURL, | ||||
credentials: data.credential | credentials: data.credential | ||||
}; | }; | ||||
localStorage.googleUserData = JSON.stringify(this.googleUserData); | |||||
this.showSocialLogin = false; | this.showSocialLogin = false; | ||||
}).catch(err => { | }).catch(err => { | ||||
alert(err.message); | alert(err.message); | ||||