learning_model 1.0.49 → 1.0.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.bundle.js +1 -1
- package/dist/index.bundle.js.LICENSE.txt +17 -0
- package/dist/learning/mobilenet.d.ts +3 -0
- package/dist/learning/mobilenet.js +42 -3
- package/dist/learning/mobilenet.test.js +11 -9
- package/dist/lib/learning/mobilenet.d.ts +3 -0
- package/dist/lib/utils/tf.d.ts +1 -1
- package/dist/utils/tf.d.ts +1 -1
- package/dist/utils/tf.js +11 -9
- package/jest.config.js +2 -2
- package/lib/learning/mobilenet.test.ts +14 -10
- package/lib/learning/mobilenet.ts +50 -3
- package/lib/utils/tf.ts +2 -1
- package/package.json +2 -1
|
@@ -105,6 +105,23 @@
|
|
|
105
105
|
* =============================================================================
|
|
106
106
|
*/
|
|
107
107
|
|
|
108
|
+
/**
|
|
109
|
+
* @license
|
|
110
|
+
* Copyright 2019 Google LLC. All Rights Reserved.
|
|
111
|
+
* Licensed under the Apache License, Version 2.0 (the 'License');
|
|
112
|
+
* you may not use this file except in compliance with the License.
|
|
113
|
+
* You may obtain a copy of the License at
|
|
114
|
+
*
|
|
115
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
116
|
+
*
|
|
117
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
118
|
+
* distributed under the License is distributed on an 'AS IS' BASIS,
|
|
119
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
120
|
+
* See the License for the specific language governing permissions and
|
|
121
|
+
* limitations under the License.
|
|
122
|
+
* =============================================================================
|
|
123
|
+
*/
|
|
124
|
+
|
|
108
125
|
/**
|
|
109
126
|
* @license
|
|
110
127
|
* Copyright 2020 Google Inc. All Rights Reserved.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as tf from '@tensorflow/tfjs';
|
|
2
|
+
import '@tensorflow/tfjs-backend-wasm';
|
|
2
3
|
import { io } from '@tensorflow/tfjs-core';
|
|
3
4
|
import LearningInterface from './base';
|
|
4
5
|
declare class LearningMobilenet implements LearningInterface {
|
|
@@ -39,6 +40,8 @@ declare class LearningMobilenet implements LearningInterface {
|
|
|
39
40
|
private _convertToTfDataset;
|
|
40
41
|
addData(label: string, data: any): Promise<void>;
|
|
41
42
|
init(): Promise<void>;
|
|
43
|
+
private setupBackend;
|
|
44
|
+
private checkWasmSupport;
|
|
42
45
|
train(): Promise<tf.History>;
|
|
43
46
|
infer(data: any): Promise<Map<string, number>>;
|
|
44
47
|
saveModel(handlerOrURL: io.IOHandler | string, config?: io.SaveConfig): Promise<void>;
|
|
@@ -38,6 +38,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
38
38
|
};
|
|
39
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
40
|
const tf = __importStar(require("@tensorflow/tfjs"));
|
|
41
|
+
require("@tensorflow/tfjs-backend-wasm"); // WebAssembly 백엔드 추가
|
|
41
42
|
const tfjs_1 = require("@tensorflow/tfjs");
|
|
42
43
|
const tf_1 = require("../utils/tf");
|
|
43
44
|
const canvas_1 = require("../utils/canvas");
|
|
@@ -138,8 +139,10 @@ class LearningMobilenet {
|
|
|
138
139
|
return __awaiter(this, void 0, void 0, function* () {
|
|
139
140
|
try {
|
|
140
141
|
if (this.mobilenetModule !== null) {
|
|
141
|
-
const cap = (0, tf_1.isTensor)(data) ? data : (0, tf_1.capture)(data, false);
|
|
142
|
-
const predict =
|
|
142
|
+
const cap = (0, tf_1.isTensor)(data) ? data : yield (0, tf_1.capture)(data, false);
|
|
143
|
+
const predict = tf.tidy(() => {
|
|
144
|
+
return this.mobilenetModule.predict(cap);
|
|
145
|
+
});
|
|
143
146
|
const activation = yield predict.data();
|
|
144
147
|
const classIndex = this.registerClassNumber(label);
|
|
145
148
|
if (!this.imageExamples[classIndex]) {
|
|
@@ -149,6 +152,12 @@ class LearningMobilenet {
|
|
|
149
152
|
if (this.classNumber.length >= this.limitSize) {
|
|
150
153
|
this.isReady = true;
|
|
151
154
|
}
|
|
155
|
+
// Dispose of the prediction tensor to free memory
|
|
156
|
+
predict.dispose();
|
|
157
|
+
// If cap is not a tensor, we don't need to dispose it. Otherwise, we should.
|
|
158
|
+
if (!(0, tf_1.isTensor)(data)) {
|
|
159
|
+
cap.dispose();
|
|
160
|
+
}
|
|
152
161
|
}
|
|
153
162
|
else {
|
|
154
163
|
throw new Error('mobilenetModule is null');
|
|
@@ -164,6 +173,8 @@ class LearningMobilenet {
|
|
|
164
173
|
init() {
|
|
165
174
|
return __awaiter(this, void 0, void 0, function* () {
|
|
166
175
|
try {
|
|
176
|
+
console.log('init call');
|
|
177
|
+
yield this.setupBackend();
|
|
167
178
|
this.mobilenetModule = yield (0, tf_1.loadModel)();
|
|
168
179
|
}
|
|
169
180
|
catch (error) {
|
|
@@ -172,6 +183,34 @@ class LearningMobilenet {
|
|
|
172
183
|
}
|
|
173
184
|
});
|
|
174
185
|
}
|
|
186
|
+
setupBackend() {
|
|
187
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
188
|
+
const isWasmSupported = yield this.checkWasmSupport();
|
|
189
|
+
if (isWasmSupported) {
|
|
190
|
+
yield tf.setBackend('wasm');
|
|
191
|
+
yield tf.ready();
|
|
192
|
+
console.log('Backend is set to WebAssembly');
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
yield tf.setBackend('cpu');
|
|
196
|
+
yield tf.ready();
|
|
197
|
+
console.log('Backend is set to CPU');
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
checkWasmSupport() {
|
|
202
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
203
|
+
try {
|
|
204
|
+
yield tf.setBackend('wasm');
|
|
205
|
+
yield tf.ready();
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
console.warn('WASM backend is not supported in this environment.', error);
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
175
214
|
// 모델 학습 처리
|
|
176
215
|
train() {
|
|
177
216
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -246,8 +285,8 @@ class LearningMobilenet {
|
|
|
246
285
|
try {
|
|
247
286
|
const classProbabilities = new Map();
|
|
248
287
|
const croppedImage = (0, canvas_1.cropTo)(data, 224, false);
|
|
288
|
+
const captured = yield (0, tf_1.capture)(croppedImage, false);
|
|
249
289
|
const logits = tf.tidy(() => {
|
|
250
|
-
const captured = (0, tf_1.capture)(croppedImage, false);
|
|
251
290
|
return this.model.predict(captured);
|
|
252
291
|
});
|
|
253
292
|
const values = yield logits.data();
|
|
@@ -56,22 +56,24 @@ function ImagePathToTensor(imagePath) {
|
|
|
56
56
|
}
|
|
57
57
|
describe('LearningMobilenetImage', () => {
|
|
58
58
|
const learning = new mobilenet_1.default({});
|
|
59
|
+
const image1Path = path.join(__dirname, '../../public/images/image1.jpeg');
|
|
60
|
+
const image2Path = path.join(__dirname, '../../public/images/image2.jpeg');
|
|
61
|
+
console.log('Resolved path for image1:', image1Path);
|
|
59
62
|
beforeAll(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
60
|
-
|
|
61
|
-
const image2Path = path.join(__dirname, '../../public/images/image2.jpeg');
|
|
63
|
+
learning.init();
|
|
62
64
|
imageTensor1 = yield ImagePathToTensor(image1Path);
|
|
63
65
|
imageTensor2 = yield ImagePathToTensor(image2Path);
|
|
64
66
|
}));
|
|
65
|
-
|
|
67
|
+
it('loads an image and converts it to a tensor', () => {
|
|
66
68
|
expect(imageTensor1).toBeDefined();
|
|
67
69
|
expect(imageTensor1 instanceof tf.Tensor).toBe(true);
|
|
68
70
|
expect(imageTensor2).toBeDefined();
|
|
69
71
|
expect(imageTensor2 instanceof tf.Tensor).toBe(true);
|
|
70
72
|
});
|
|
71
|
-
test('mobilenet add data', () => {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
});
|
|
73
|
+
// test('mobilenet add data', () => {
|
|
74
|
+
// learning.addData("라벨1", imageTensor1);
|
|
75
|
+
// learning.addData("라벨1", imageTensor1);
|
|
76
|
+
// learning.addData("라벨2", imageTensor2);
|
|
77
|
+
// learning.addData("라벨2", imageTensor2);
|
|
78
|
+
// });
|
|
77
79
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as tf from '@tensorflow/tfjs';
|
|
2
|
+
import '@tensorflow/tfjs-backend-wasm';
|
|
2
3
|
import { io } from '@tensorflow/tfjs-core';
|
|
3
4
|
import LearningInterface from './base';
|
|
4
5
|
declare class LearningMobilenet implements LearningInterface {
|
|
@@ -39,6 +40,8 @@ declare class LearningMobilenet implements LearningInterface {
|
|
|
39
40
|
private _convertToTfDataset;
|
|
40
41
|
addData(label: string, data: any): Promise<void>;
|
|
41
42
|
init(): Promise<void>;
|
|
43
|
+
private setupBackend;
|
|
44
|
+
private checkWasmSupport;
|
|
42
45
|
train(): Promise<tf.History>;
|
|
43
46
|
infer(data: any): Promise<Map<string, number>>;
|
|
44
47
|
saveModel(handlerOrURL: io.IOHandler | string, config?: io.SaveConfig): Promise<void>;
|
package/dist/lib/utils/tf.d.ts
CHANGED
|
@@ -3,5 +3,5 @@ export declare function isTensor(c: any): c is tf.Tensor;
|
|
|
3
3
|
export declare function loadModel(): Promise<tf.LayersModel>;
|
|
4
4
|
export declare function mobileNetURL(version: number): string;
|
|
5
5
|
export declare function imageToTensor(data: any): tf.Tensor3D;
|
|
6
|
-
export declare function capture(rasterElement: HTMLImageElement | HTMLVideoElement | HTMLCanvasElement, grayscale?: boolean): tf.Tensor<tf.Rank
|
|
6
|
+
export declare function capture(rasterElement: HTMLImageElement | HTMLVideoElement | HTMLCanvasElement, grayscale?: boolean): Promise<tf.Tensor<tf.Rank>>;
|
|
7
7
|
export declare function cropTensor(img: tf.Tensor3D, grayscaleModel?: boolean, grayscaleInput?: boolean): tf.Tensor3D;
|
package/dist/utils/tf.d.ts
CHANGED
|
@@ -3,5 +3,5 @@ export declare function isTensor(c: any): c is tf.Tensor;
|
|
|
3
3
|
export declare function loadModel(): Promise<tf.LayersModel>;
|
|
4
4
|
export declare function mobileNetURL(version: number): string;
|
|
5
5
|
export declare function imageToTensor(data: any): tf.Tensor3D;
|
|
6
|
-
export declare function capture(rasterElement: HTMLImageElement | HTMLVideoElement | HTMLCanvasElement, grayscale?: boolean): tf.Tensor<tf.Rank
|
|
6
|
+
export declare function capture(rasterElement: HTMLImageElement | HTMLVideoElement | HTMLCanvasElement, grayscale?: boolean): Promise<tf.Tensor<tf.Rank>>;
|
|
7
7
|
export declare function cropTensor(img: tf.Tensor3D, grayscaleModel?: boolean, grayscaleInput?: boolean): tf.Tensor3D;
|
package/dist/utils/tf.js
CHANGED
|
@@ -90,15 +90,17 @@ function imageToTensor(data) {
|
|
|
90
90
|
}
|
|
91
91
|
exports.imageToTensor = imageToTensor;
|
|
92
92
|
function capture(rasterElement, grayscale) {
|
|
93
|
-
return
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
93
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
94
|
+
return tf.tidy(() => {
|
|
95
|
+
const pixels = tf.browser.fromPixels(rasterElement);
|
|
96
|
+
// crop the image so we're using the center square
|
|
97
|
+
const cropped = cropTensor(pixels, grayscale);
|
|
98
|
+
// Expand the outer most dimension so we have a batch size of 1
|
|
99
|
+
const batchedImage = cropped.expandDims(0);
|
|
100
|
+
// Normalize the image between -1 and a1. The image comes in between 0-255
|
|
101
|
+
// so we divide by 127 and subtract 1.
|
|
102
|
+
return batchedImage.toFloat().div(tf.scalar(127)).sub(tf.scalar(1));
|
|
103
|
+
});
|
|
102
104
|
});
|
|
103
105
|
}
|
|
104
106
|
exports.capture = capture;
|
package/jest.config.js
CHANGED
|
@@ -2,7 +2,7 @@ module.exports = {
|
|
|
2
2
|
preset: 'ts-jest',
|
|
3
3
|
testEnvironment: 'node',
|
|
4
4
|
// 기타 Jest 구성 옵션
|
|
5
|
-
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
|
|
6
|
-
|
|
5
|
+
//testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
|
|
6
|
+
testMatch: ['**/mobile(*.)+(spec|test).[jt]s?(x)'],
|
|
7
7
|
testPathIgnorePatterns: ['/node_modules/'],
|
|
8
8
|
};
|
|
@@ -20,25 +20,29 @@ async function ImagePathToTensor(imagePath: string): Promise<tf.Tensor3D> {
|
|
|
20
20
|
|
|
21
21
|
describe('LearningMobilenetImage', () => {
|
|
22
22
|
const learning = new LearningMobilenetImage({});
|
|
23
|
-
|
|
23
|
+
|
|
24
|
+
const image1Path = path.join(__dirname, '../../public/images/image1.jpeg');
|
|
25
|
+
const image2Path = path.join(__dirname, '../../public/images/image2.jpeg');
|
|
26
|
+
console.log('Resolved path for image1:', image1Path);
|
|
24
27
|
beforeAll(async () => {
|
|
25
|
-
|
|
26
|
-
const image2Path = path.join(__dirname, '../../public/images/image2.jpeg');
|
|
28
|
+
learning.init();
|
|
27
29
|
imageTensor1 = await ImagePathToTensor(image1Path);
|
|
28
30
|
imageTensor2 = await ImagePathToTensor(image2Path);
|
|
29
31
|
});
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
|
|
34
|
+
it('loads an image and converts it to a tensor', () => {
|
|
32
35
|
expect(imageTensor1).toBeDefined();
|
|
33
36
|
expect(imageTensor1 instanceof tf.Tensor).toBe(true);
|
|
34
37
|
expect(imageTensor2).toBeDefined();
|
|
35
38
|
expect(imageTensor2 instanceof tf.Tensor).toBe(true);
|
|
36
39
|
});
|
|
37
40
|
|
|
38
|
-
test('mobilenet add data', () => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
});
|
|
41
|
+
// test('mobilenet add data', () => {
|
|
42
|
+
// learning.addData("라벨1", imageTensor1);
|
|
43
|
+
// learning.addData("라벨1", imageTensor1);
|
|
44
|
+
// learning.addData("라벨2", imageTensor2);
|
|
45
|
+
// learning.addData("라벨2", imageTensor2);
|
|
46
|
+
// });
|
|
44
47
|
});
|
|
48
|
+
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
///////////////////////////////////////////////////////////////////////////
|
|
6
6
|
|
|
7
7
|
import * as tf from '@tensorflow/tfjs';
|
|
8
|
+
import '@tensorflow/tfjs-backend-wasm'; // WebAssembly 백엔드 추가
|
|
8
9
|
import { dispose } from '@tensorflow/tfjs';
|
|
9
10
|
import { io } from '@tensorflow/tfjs-core';
|
|
10
11
|
import LearningInterface from './base';
|
|
@@ -150,17 +151,32 @@ class LearningMobilenet implements LearningInterface {
|
|
|
150
151
|
public async addData(label: string, data: any): Promise<void> {
|
|
151
152
|
try {
|
|
152
153
|
if (this.mobilenetModule !== null) {
|
|
153
|
-
const cap = isTensor(data) ? data : capture(data, false);
|
|
154
|
-
|
|
154
|
+
const cap = isTensor(data) ? data : await capture(data, false);
|
|
155
|
+
|
|
156
|
+
const predict = tf.tidy(() => {
|
|
157
|
+
return this.mobilenetModule!.predict(cap) as tf.Tensor;
|
|
158
|
+
});
|
|
159
|
+
|
|
155
160
|
const activation = await predict.data() as Float32Array;
|
|
161
|
+
|
|
156
162
|
const classIndex = this.registerClassNumber(label);
|
|
157
163
|
if (!this.imageExamples[classIndex]) {
|
|
158
164
|
this.imageExamples[classIndex] = [];
|
|
159
165
|
}
|
|
160
166
|
this.imageExamples[classIndex].push(activation);
|
|
167
|
+
|
|
161
168
|
if(this.classNumber.length >= this.limitSize) {
|
|
162
169
|
this.isReady = true;
|
|
163
170
|
}
|
|
171
|
+
|
|
172
|
+
// Dispose of the prediction tensor to free memory
|
|
173
|
+
predict.dispose();
|
|
174
|
+
|
|
175
|
+
// If cap is not a tensor, we don't need to dispose it. Otherwise, we should.
|
|
176
|
+
if (!isTensor(data)) {
|
|
177
|
+
cap.dispose();
|
|
178
|
+
}
|
|
179
|
+
|
|
164
180
|
} else {
|
|
165
181
|
throw new Error('mobilenetModule is null');
|
|
166
182
|
}
|
|
@@ -173,6 +189,8 @@ class LearningMobilenet implements LearningInterface {
|
|
|
173
189
|
|
|
174
190
|
public async init() {
|
|
175
191
|
try {
|
|
192
|
+
console.log('init call')
|
|
193
|
+
await this.setupBackend();
|
|
176
194
|
this.mobilenetModule = await loadModel();
|
|
177
195
|
} catch(error) {
|
|
178
196
|
console.log('init Error', error);
|
|
@@ -180,6 +198,29 @@ class LearningMobilenet implements LearningInterface {
|
|
|
180
198
|
}
|
|
181
199
|
}
|
|
182
200
|
|
|
201
|
+
private async setupBackend() {
|
|
202
|
+
const isWasmSupported = await this.checkWasmSupport();
|
|
203
|
+
if (isWasmSupported) {
|
|
204
|
+
await tf.setBackend('wasm');
|
|
205
|
+
await tf.ready();
|
|
206
|
+
console.log('Backend is set to WebAssembly');
|
|
207
|
+
} else {
|
|
208
|
+
await tf.setBackend('cpu');
|
|
209
|
+
await tf.ready();
|
|
210
|
+
console.log('Backend is set to CPU');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private async checkWasmSupport(): Promise<boolean> {
|
|
215
|
+
try {
|
|
216
|
+
await tf.setBackend('wasm');
|
|
217
|
+
await tf.ready();
|
|
218
|
+
return true;
|
|
219
|
+
} catch (error) {
|
|
220
|
+
console.warn('WASM backend is not supported in this environment.', error);
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
183
224
|
|
|
184
225
|
// 모델 학습 처리
|
|
185
226
|
public async train(): Promise<tf.History> {
|
|
@@ -227,7 +268,9 @@ class LearningMobilenet implements LearningInterface {
|
|
|
227
268
|
const trainData = datasets.trainDataset.batch(this.batchSize);
|
|
228
269
|
const validationData = datasets.validationDataset.batch(this.batchSize);
|
|
229
270
|
const optimizer = tf.train.adam(this.learningRate);
|
|
271
|
+
|
|
230
272
|
const trainModel = await this._createModel(optimizer);
|
|
273
|
+
|
|
231
274
|
const jointModel = tf.sequential();
|
|
232
275
|
jointModel.add(this.mobilenetModule!);
|
|
233
276
|
jointModel.add(trainModel);
|
|
@@ -257,16 +300,19 @@ class LearningMobilenet implements LearningInterface {
|
|
|
257
300
|
try {
|
|
258
301
|
const classProbabilities = new Map<string, number>();
|
|
259
302
|
const croppedImage = cropTo(data, 224, false);
|
|
303
|
+
const captured = await capture(croppedImage, false);
|
|
260
304
|
|
|
261
305
|
const logits = tf.tidy(() => {
|
|
262
|
-
const captured = capture(croppedImage, false);
|
|
263
306
|
return this.model!.predict(captured);
|
|
264
307
|
});
|
|
308
|
+
|
|
265
309
|
const values = await (logits as tf.Tensor<tf.Rank>).data();
|
|
266
310
|
const EPSILON = 1e-6; // 매우 작은 값을 표현하기 위한 엡실론
|
|
311
|
+
|
|
267
312
|
for (let i = 0; i < values.length; i++) {
|
|
268
313
|
let probability = Math.max(0, Math.min(1, values[i])); // 확률 값을 0과 1 사이로 조정
|
|
269
314
|
probability = probability < EPSILON ? 0 : probability; // 매우 작은 확률 값을 0으로 간주
|
|
315
|
+
|
|
270
316
|
const className = this.classNumber[i]; // 클래스 이름
|
|
271
317
|
const existingProbability = classProbabilities.get(className);
|
|
272
318
|
if (existingProbability !== undefined) {
|
|
@@ -275,6 +321,7 @@ class LearningMobilenet implements LearningInterface {
|
|
|
275
321
|
classProbabilities.set(className, probability);
|
|
276
322
|
}
|
|
277
323
|
}
|
|
324
|
+
|
|
278
325
|
console.log('classProbabilities', classProbabilities);
|
|
279
326
|
dispose(logits);
|
|
280
327
|
return classProbabilities;
|
package/lib/utils/tf.ts
CHANGED
|
@@ -54,7 +54,7 @@ export function imageToTensor(data: any): tf.Tensor3D {
|
|
|
54
54
|
return tensor;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
export function capture(rasterElement: HTMLImageElement | HTMLVideoElement | HTMLCanvasElement, grayscale?: boolean) {
|
|
57
|
+
export async function capture(rasterElement: HTMLImageElement | HTMLVideoElement | HTMLCanvasElement, grayscale?: boolean) {
|
|
58
58
|
return tf.tidy(() => {
|
|
59
59
|
const pixels = tf.browser.fromPixels(rasterElement);
|
|
60
60
|
|
|
@@ -70,6 +70,7 @@ export function capture(rasterElement: HTMLImageElement | HTMLVideoElement | HTM
|
|
|
70
70
|
});
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
|
|
73
74
|
export function cropTensor( img: tf.Tensor3D, grayscaleModel?: boolean, grayscaleInput?: boolean ) : tf.Tensor3D {
|
|
74
75
|
const size = Math.min(img.shape[0], img.shape[1]);
|
|
75
76
|
const centerHeight = img.shape[0] / 2;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "learning_model",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.51",
|
|
4
4
|
"description": "learning model develop",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"@tensorflow-models/mobilenet": "^2.1.0",
|
|
21
21
|
"@tensorflow/tfjs": "^4.6.0",
|
|
22
22
|
"@tensorflow/tfjs-layers": "^4.6.0",
|
|
23
|
+
"@tensorflow/tfjs-backend-wasm": "^4.20.0",
|
|
23
24
|
"canvas": "^2.11.2",
|
|
24
25
|
"learning_model": "^1.0.0"
|
|
25
26
|
},
|