UNPKG

@lightsailed/ngx-open-cv

Version:
297 lines (291 loc) 10.8 kB
import * as i0 from '@angular/core'; import { InjectionToken, Inject, Injectable, NgModule } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; const OPEN_CV_CONFIGURATION = new InjectionToken('Angular OpenCV Configuration Object'); class NgOpenCVService { errorOutput; src = null; dstC1 = null; dstC3 = null; dstC4 = null; stream; video; isReady = new BehaviorSubject({ ready: false, error: false, loading: true }); isReady$ = this.isReady.asObservable(); onCameraStartedCallback; OPENCV_URL = 'opencv.js'; DEFAULT_OPTIONS = { scriptUrl: 'assets/opencv/asm/3.4/opencv.js', wasmBinaryFile: 'wasm/3.4/opencv_js.wasm', usingWasm: false, locateFile: this.locateFile.bind(this), onRuntimeInitialized: () => { } }; constructor(options) { this.setScriptUrl(options.scriptUrl); const opts = { ...this.DEFAULT_OPTIONS, options }; this.loadOpenCv(opts); } locateFile(path, scriptDirectory) { if (path === 'opencv_js.wasm') { return scriptDirectory + '/wasm/' + path; } else { return scriptDirectory + path; } } setScriptUrl(url) { this.OPENCV_URL = url; } loadOpenCv(options) { this.isReady.next({ ready: false, error: false, loading: true }); window['Module'] = { ...options }; const script = document.createElement('script'); script.setAttribute('async', ''); script.setAttribute('type', 'text/javascript'); script.addEventListener('load', () => { const onRuntimeInitializedCallback = () => { if (options.onRuntimeInitialized) { options.onRuntimeInitialized(); } this.isReady.next({ ready: true, error: false, loading: false }); }; cv.onRuntimeInitialized = onRuntimeInitializedCallback; }); script.addEventListener('error', () => { const err = this.printError('Failed to load ' + this.OPENCV_URL); this.isReady.next({ ready: false, error: true, loading: false }); this.isReady.error(err); }); script.src = this.OPENCV_URL; const node = document.getElementsByTagName('script')[0]; if (node) { node.parentNode.insertBefore(script, node); } else { document.head.appendChild(script); } } createFileFromUrl(path, url) { const request = new XMLHttpRequest(); request.open('GET', url, true); request.responseType = 'arraybuffer'; return new Observable(observer => { const { next, error: catchError, complete } = observer; request.onload = ev => { if (request.readyState === 4) { if (request.status === 200) { const data = new Uint8Array(request.response); cv.FS_createDataFile('/', path, data, true, false, false); observer.next(); observer.complete(); } else { this.printError('Failed to load ' + url + ' status: ' + request.status); observer.error(); } } }; request.send(); }); } loadImageToCanvas(imageUrl, canvasId) { return Observable.create(observer => { const canvas = document.getElementById(canvasId); const ctx = canvas.getContext('2d'); const img = new Image(); img.crossOrigin = 'anonymous'; img.onload = () => { canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0, img.width, img.height); observer.next(); observer.complete(); }; img.src = imageUrl; }); } loadImageToHTMLCanvas(imageUrl, canvas) { return Observable.create(observer => { const ctx = canvas.getContext('2d'); const img = new Image(); img.crossOrigin = 'anonymous'; img.onload = () => { canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0, img.width, img.height); observer.next(); observer.complete(); }; img.src = imageUrl; }); } clearError() { this.errorOutput.innerHTML = ''; } printError(err) { if (typeof err === 'undefined') { err = ''; } else if (typeof err === 'number') { if (!isNaN(err)) { if (typeof cv !== 'undefined') { err = 'Exception: ' + cv.exceptionFromPtr(err).msg; } } } else if (typeof err === 'string') { const ptr = Number(err.split(' ')[0]); if (!isNaN(ptr)) { if (typeof cv !== 'undefined') { err = 'Exception: ' + cv.exceptionFromPtr(ptr).msg; } } } else if (err instanceof Error) { err = err.stack.replace(/\n/g, '<br>'); } throw new Error(err); } loadCode(scriptId, textAreaId) { const scriptNode = document.getElementById(scriptId); const textArea = document.getElementById(textAreaId); if (scriptNode.type !== 'text/code-snippet') { throw Error('Unknown code snippet type'); } textArea.value = scriptNode.text.replace(/^\n/, ''); } addFileInputHandler(fileInputId, canvasId) { const inputElement = document.getElementById(fileInputId); inputElement.addEventListener('change', e => { const files = e.target['files']; if (files.length > 0) { const imgUrl = URL.createObjectURL(files[0]); this.loadImageToCanvas(imgUrl, canvasId); } }, false); } onVideoCanPlay() { if (this.onCameraStartedCallback) { this.onCameraStartedCallback(this.stream, this.video); } } startCamera(resolution, callback, videoId) { const constraints = { qvga: { width: { exact: 320 }, height: { exact: 240 } }, vga: { width: { exact: 640 }, height: { exact: 480 } } }; let video = document.getElementById(videoId); if (!video) { video = document.createElement('video'); } let videoConstraint = constraints[resolution]; if (!videoConstraint) { videoConstraint = true; } navigator.mediaDevices .getUserMedia({ video: videoConstraint, audio: false }) .then(stream => { video.srcObject = stream; video.play(); this.video = video; this.stream = stream; this.onCameraStartedCallback = callback; video.addEventListener('canplay', this.onVideoCanPlay.bind(this), false); }) .catch(err => { this.printError('Camera Error: ' + err.name + ' ' + err.message); }); } stopCamera() { if (this.video) { this.video.pause(); this.video.srcObject = null; this.video.removeEventListener('canplay', this.onVideoCanPlay.bind(this)); } if (this.stream) { this.stream.getVideoTracks()[0].stop(); } } getContours(src, width, height) { cv.cvtColor(src, this.dstC1, cv.COLOR_RGBA2GRAY); cv.threshold(this.dstC1, this.dstC4, 120, 200, cv.THRESH_BINARY); const contours = new cv.MatVector(); const hierarchy = new cv.Mat(); cv.findContours(this.dstC4, contours, hierarchy, cv.RETR_CCOMP, cv.CHAIN_APPROX_SIMPLE, { x: 0, y: 0 }); this.dstC3.delete(); this.dstC3 = cv.Mat.ones(height, width, cv.CV_8UC3); for (let i = 0; i < contours.size(); ++i) { const color = new cv.Scalar(0, 255, 0); cv.drawContours(this.dstC3, contours, i, color, 1, cv.LINE_8, hierarchy); } contours.delete(); hierarchy.delete(); return this.dstC3; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.3", ngImport: i0, type: NgOpenCVService, deps: [{ token: OPEN_CV_CONFIGURATION }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.3", ngImport: i0, type: NgOpenCVService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.3", ngImport: i0, type: NgOpenCVService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: undefined, decorators: [{ type: Inject, args: [OPEN_CV_CONFIGURATION] }] }] }); class NgOpenCVModule { /** * * Setup the module in your application's root bootstrap. * * * @memberOf NgOpenCvModule */ static forRoot(config) { return { ngModule: NgOpenCVModule, providers: [{ provide: OPEN_CV_CONFIGURATION, useValue: config }] }; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.3", ngImport: i0, type: NgOpenCVModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.3", ngImport: i0, type: NgOpenCVModule }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.3", ngImport: i0, type: NgOpenCVModule, providers: [NgOpenCVService] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.3", ngImport: i0, type: NgOpenCVModule, decorators: [{ type: NgModule, args: [{ imports: [], declarations: [], exports: [], providers: [NgOpenCVService] }] }] }); /* * Public API Surface of ngx-open-cv */ /** * Generated bundle index. Do not edit. */ export { NgOpenCVModule, NgOpenCVService, OPEN_CV_CONFIGURATION }; //# sourceMappingURL=lightsailed-ngx-open-cv.mjs.map