@100mslive/hms-virtual-background 1.3.1-7e → 1.3.4

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.
@@ -1,5 +1,5 @@
1
1
  import '@tensorflow/tfjs-backend-webgl';
2
- import { HMSVideoPlugin, HMSVideoPluginType } from '@100mslive/hms-video';
2
+ import { HMSVideoPlugin, HMSVideoPluginType } from "@100mslive/hms-video";
3
3
  export declare class HMSVirtualBackgroundPlugin implements HMSVideoPlugin {
4
4
  background: string | HTMLImageElement;
5
5
  personMaskWidth: number;
@@ -20,13 +20,13 @@ export declare class HMSVirtualBackgroundPlugin implements HMSVideoPlugin {
20
20
  personMask: ImageData;
21
21
  personMaskCanvas: HTMLCanvasElement;
22
22
  personMaskCtx: any;
23
- Filters: any;
24
- constructor(background: string);
23
+ filters: any;
24
+ enableSharpening?: boolean | false;
25
+ constructor(background: string, enableSharpening?: boolean);
25
26
  init(): Promise<void>;
26
27
  isSupported(): boolean;
27
28
  getName(): string;
28
29
  getPluginType(): HMSVideoPluginType;
29
- initSharpenFilter(): any;
30
30
  setBackground(path?: string | HTMLImageElement): Promise<void>;
31
31
  stop(): void;
32
32
  processVideoFrame(input: HTMLCanvasElement, output: HTMLCanvasElement, skipProcessing?: boolean): Promise<void> | void;
@@ -35,9 +35,11 @@ export declare class HMSVirtualBackgroundPlugin implements HMSVideoPlugin {
35
35
  private resizeInputData;
36
36
  private infer;
37
37
  private postProcessing;
38
+ sharpenFilter(): void;
38
39
  private drawPersonMask;
39
40
  private drawSegmentedBackground;
40
41
  private runSegmentation;
41
42
  private fitImageToBackground;
42
43
  private addBlurToBackground;
44
+ initSharpenFilter(): any;
43
45
  }
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
3
5
  require('@tensorflow/tfjs-backend-webgl');
4
6
  var hmsVideo = require('@100mslive/hms-video');
5
7
 
@@ -916,10 +918,18 @@ var loadTFLite = /*#__PURE__*/function () {
916
918
 
917
919
  var TAG$1 = 'VBProcessor';
918
920
 
919
- var pkg$1 = /*#__PURE__*/require('../package.json');
921
+ var pkg$1 = /*#__PURE__*/require("../package.json");
920
922
 
923
+ var minVideoWidthForSharpening = 214;
924
+ var maxVideoWidthForSharpening = 855;
925
+ var minVideoHeightForSharpening = 120;
926
+ var maxVideoHeightForSharpening = 720;
921
927
  var HMSVirtualBackgroundPlugin = /*#__PURE__*/function () {
922
- function HMSVirtualBackgroundPlugin(background) {
928
+ function HMSVirtualBackgroundPlugin(background, enableSharpening) {
929
+ if (enableSharpening === void 0) {
930
+ enableSharpening = false;
931
+ }
932
+
923
933
  this.background = background;
924
934
  this.personMaskWidth = 256;
925
935
  this.personMaskHeight = 144;
@@ -939,8 +949,9 @@ var HMSVirtualBackgroundPlugin = /*#__PURE__*/function () {
939
949
  this.personMaskCanvas.width = this.personMaskWidth;
940
950
  this.personMaskCanvas.height = this.personMaskHeight;
941
951
  this.personMaskCtx = this.personMaskCanvas.getContext('2d');
942
- this.Filters = {};
943
- this.log(TAG$1, 'Virtual Background plugin created');
952
+ this.filters = {};
953
+ this.enableSharpening = enableSharpening;
954
+ this.log(TAG$1, "Virtual Background plugin created");
944
955
  this.setBackground(this.background);
945
956
  }
946
957
 
@@ -957,7 +968,7 @@ var HMSVirtualBackgroundPlugin = /*#__PURE__*/function () {
957
968
  break;
958
969
  }
959
970
 
960
- this.log(TAG$1, 'PREVIOUS LOADED MODEL IS ', this.tfLite);
971
+ this.log(TAG$1, "PREVIOUS LOADED MODEL IS ", this.tfLite);
961
972
  this.loadModelCalled = true;
962
973
  this.tfLitePromise = loadTFLite();
963
974
  _context.next = 6;
@@ -973,7 +984,9 @@ var HMSVirtualBackgroundPlugin = /*#__PURE__*/function () {
973
984
  return this.tfLitePromise;
974
985
 
975
986
  case 11:
976
- this.initSharpenFilter();
987
+ if (this.enableSharpening) {
988
+ this.initSharpenFilter();
989
+ }
977
990
 
978
991
  case 12:
979
992
  case "end":
@@ -992,7 +1005,7 @@ var HMSVirtualBackgroundPlugin = /*#__PURE__*/function () {
992
1005
 
993
1006
  _proto.isSupported = function isSupported() {
994
1007
  //support chrome, firefox, edge TODO: check this
995
- return navigator.userAgent.indexOf('Chrome') != -1 || navigator.userAgent.indexOf('Firefox') != -1 || navigator.userAgent.indexOf('Edg') != -1;
1008
+ return navigator.userAgent.indexOf("Chrome") != -1 || navigator.userAgent.indexOf("Firefox") != -1 || navigator.userAgent.indexOf("Edg") != -1;
996
1009
  };
997
1010
 
998
1011
  _proto.getName = function getName() {
@@ -1003,91 +1016,6 @@ var HMSVirtualBackgroundPlugin = /*#__PURE__*/function () {
1003
1016
  return hmsVideo.HMSVideoPluginType.TRANSFORM;
1004
1017
  };
1005
1018
 
1006
- _proto.initSharpenFilter = function initSharpenFilter() {
1007
- var _arguments = arguments,
1008
- _this = this;
1009
-
1010
- this.Filters.filterImage = function (filter, image, var_args) {
1011
- var args = [image];
1012
-
1013
- for (var i = 2; i < _arguments.length; i++) {
1014
- args.push(_arguments[i]);
1015
- }
1016
-
1017
- return filter.apply(null, args);
1018
- };
1019
-
1020
- this.Filters.tmpCanvas = document.createElement('canvas');
1021
- this.Filters.tmpCtx = this.Filters.tmpCanvas.getContext('2d');
1022
-
1023
- this.Filters.createImageData = function (w, h) {
1024
- return _this.Filters.tmpCtx.createImageData(w, h);
1025
- };
1026
-
1027
- this.Filters.convolute = function (pixels, weights, opaque) {
1028
- if (weights === void 0) {
1029
- weights = [0, -1, 0, -1, 5, -1, 0, -1, 0];
1030
- }
1031
-
1032
- var side = Math.round(Math.sqrt(weights.length));
1033
- var halfSide = Math.floor(side / 2);
1034
- var src = pixels.data;
1035
- var sw = pixels.width;
1036
- var sh = pixels.height; // pad output by the convolution matrix
1037
-
1038
- var w = sw;
1039
- var h = sh;
1040
-
1041
- var output = _this.Filters.createImageData(w, h);
1042
-
1043
- var dst = output.data; // go through the destination image pixels
1044
-
1045
- var alphaFac = opaque ? 1 : 0;
1046
-
1047
- for (var y = 0; y < h; y = y + 1) {
1048
- for (var x = 0; x < w; x = x + 1) {
1049
- var dstOff = (y * w + x) * 4;
1050
-
1051
- if (src[dstOff + 3] == 0) {
1052
- continue;
1053
- } else if (x < w && y < h) {
1054
- var sy = y;
1055
- var sx = x; // calculate the weighed sum of the source image pixels that
1056
- // fall under the convolution matrix
1057
-
1058
- var r = 0,
1059
- g = 0,
1060
- b = 0,
1061
- a = 0;
1062
-
1063
- for (var cy = 0; cy < side; cy++) {
1064
- for (var cx = 0; cx < side; cx++) {
1065
- var scy = sy + cy - halfSide;
1066
- var scx = sx + cx - halfSide;
1067
-
1068
- if (scy >= 0 && scy < sh && scx >= 0 && scx < sw) {
1069
- var srcOff = (scy * sw + scx) * 4;
1070
- var wt = weights[cy * side + cx];
1071
- r += src[srcOff] * wt;
1072
- g += src[srcOff + 1] * wt;
1073
- b += src[srcOff + 2] * wt;
1074
- a += src[srcOff + 3] * wt;
1075
- }
1076
- }
1077
- }
1078
-
1079
- dst[dstOff] = r;
1080
- dst[dstOff + 1] = g;
1081
- dst[dstOff + 2] = b;
1082
- dst[dstOff + 3] = a + alphaFac * (255 - a);
1083
- }
1084
- }
1085
- }
1086
-
1087
- return output;
1088
- };
1089
- };
1090
-
1091
1019
  _proto.setBackground = /*#__PURE__*/function () {
1092
1020
  var _setBackground = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(path) {
1093
1021
  var img;
@@ -1095,30 +1023,30 @@ var HMSVirtualBackgroundPlugin = /*#__PURE__*/function () {
1095
1023
  while (1) {
1096
1024
  switch (_context2.prev = _context2.next) {
1097
1025
  case 0:
1098
- if (!(path !== '')) {
1026
+ if (!(path !== "")) {
1099
1027
  _context2.next = 24;
1100
1028
  break;
1101
1029
  }
1102
1030
 
1103
- if (!(path === 'none')) {
1031
+ if (!(path === "none")) {
1104
1032
  _context2.next = 7;
1105
1033
  break;
1106
1034
  }
1107
1035
 
1108
1036
  this.log(TAG$1, 'setting background to :', path);
1109
- this.background = 'none';
1037
+ this.background = "none";
1110
1038
  this.isVirtualBackground = false;
1111
1039
  _context2.next = 22;
1112
1040
  break;
1113
1041
 
1114
1042
  case 7:
1115
- if (!(path === 'blur')) {
1043
+ if (!(path === "blur")) {
1116
1044
  _context2.next = 13;
1117
1045
  break;
1118
1046
  }
1119
1047
 
1120
1048
  this.log(TAG$1, 'setting background to :', path);
1121
- this.background = 'blur';
1049
+ this.background = "blur";
1122
1050
  this.isVirtualBackground = false;
1123
1051
  _context2.next = 22;
1124
1052
  break;
@@ -1146,7 +1074,7 @@ var HMSVirtualBackgroundPlugin = /*#__PURE__*/function () {
1146
1074
  break;
1147
1075
 
1148
1076
  case 24:
1149
- this.log(TAG$1, 'Not updating anything using the previous background Settings');
1077
+ this.log(TAG$1, "Not updating anything using the previous background Settings");
1150
1078
 
1151
1079
  case 25:
1152
1080
  case "end":
@@ -1177,7 +1105,7 @@ var HMSVirtualBackgroundPlugin = /*#__PURE__*/function () {
1177
1105
  };
1178
1106
 
1179
1107
  _proto.processVideoFrame = function processVideoFrame(input, output, skipProcessing) {
1180
- var _this2 = this;
1108
+ var _this = this;
1181
1109
 
1182
1110
  if (!input || !output) {
1183
1111
  throw new Error('Plugin invalid input/output');
@@ -1199,7 +1127,7 @@ var HMSVirtualBackgroundPlugin = /*#__PURE__*/function () {
1199
1127
  this.imageAspectRatio = input.width / input.height;
1200
1128
 
1201
1129
  if (this.imageAspectRatio <= 0) {
1202
- throw new Error('Invalid input width/height');
1130
+ throw new Error("Invalid input width/height");
1203
1131
  }
1204
1132
 
1205
1133
  var process = /*#__PURE__*/function () {
@@ -1209,7 +1137,7 @@ var HMSVirtualBackgroundPlugin = /*#__PURE__*/function () {
1209
1137
  switch (_context3.prev = _context3.next) {
1210
1138
  case 0:
1211
1139
  _context3.next = 2;
1212
- return _this2.runSegmentation(skipProcessing);
1140
+ return _this.runSegmentation(skipProcessing);
1213
1141
 
1214
1142
  case 2:
1215
1143
  case "end":
@@ -1224,7 +1152,7 @@ var HMSVirtualBackgroundPlugin = /*#__PURE__*/function () {
1224
1152
  };
1225
1153
  }();
1226
1154
 
1227
- if (this.background === 'none' && !this.isVirtualBackground) {
1155
+ if (this.background === "none" && !this.isVirtualBackground) {
1228
1156
  this.outputCtx.globalCompositeOperation = 'copy';
1229
1157
  this.outputCtx.filter = 'none';
1230
1158
  this.outputCtx.drawImage(input, 0, 0, input.width, input.height);
@@ -1322,31 +1250,33 @@ var HMSVirtualBackgroundPlugin = /*#__PURE__*/function () {
1322
1250
 
1323
1251
  this.drawPersonMask();
1324
1252
  this.outputCtx.globalCompositeOperation = 'source-in';
1325
- this.outputCtx.filter = 'none'; // // //Draw the foreground
1253
+ this.outputCtx.filter = 'none'; // //Draw the foreground
1326
1254
 
1327
1255
  this.outputCtx.drawImage(this.input, 0, 0);
1328
- var outputImageData = this.outputCtx.getImageData(0, 0, this.output.width, this.output.height); // [-1, -1, -1, -1, 9, -1, -1, -1, -1]
1256
+
1257
+ if (this.enableSharpening && this.output.width > minVideoWidthForSharpening && // minimum and maximum resolution to enable sharpening filter
1258
+ this.output.height > minVideoHeightForSharpening && this.output.width < maxVideoWidthForSharpening && this.output.height < maxVideoHeightForSharpening) {
1259
+ this.sharpenFilter();
1260
+ } // //Draw the background
1261
+
1262
+
1263
+ this.drawSegmentedBackground();
1264
+ };
1265
+
1266
+ _proto.sharpenFilter = function sharpenFilter() {
1267
+ // adding sharpening filter to each frame to improve edges and brightness
1268
+ // The basic idea is that you take the weighed sum of a rectangle of pixels from the source image and use that as the output value using convolution filter
1269
+ // It is applied intermediate output with black background and only mask data in frame
1270
+ // Filter currently used is 3 x 3 sharpening filter with values as shown:
1271
+ // [ 0, -1, 0,
1272
+ // -1, 5, -1,
1273
+ // 0, -1, 0 ]
1274
+ var outputImageData = this.outputCtx.getImageData(0, 0, this.output.width, this.output.height); // filters you may try
1275
+ // [-1, -1, -1, -1, 9, -1, -1, -1, -1]
1329
1276
  //[0, -1, 0, -1, 5, -1, 0, -1, 0]
1330
1277
 
1331
- var output = this.Filters.filterImage(this.Filters.convolute, outputImageData);
1332
- this.outputCtx.putImageData(output, 0, 0); // //Draw the background
1333
-
1334
- this.drawSegmentedBackground(); // //const t0 = performance.now();
1335
- // let outputImageData = this.outputCtx!.getImageData(
1336
- // 0,
1337
- // 0,
1338
- // this.output!.width,
1339
- // this.output!.height
1340
- // );
1341
- // // [-1, -1, -1, -1, 9, -1, -1, -1, -1]
1342
- // //[0, -1, 0, -1, 5, -1, 0, -1, 0]
1343
- // let output = this.Filters.filterImage(
1344
- // this.Filters.convolute,
1345
- // outputImageData
1346
- // );
1347
- // this.outputCtx!.putImageData(output, 0, 0);
1348
- // const t1 = performance.now();
1349
- //this.log(TAG, t1 - t0);
1278
+ var output = this.filters.convolute(outputImageData);
1279
+ this.outputCtx.putImageData(output, 0, 0);
1350
1280
  };
1351
1281
 
1352
1282
  _proto.drawPersonMask = function drawPersonMask() {
@@ -1367,27 +1297,25 @@ var HMSVirtualBackgroundPlugin = /*#__PURE__*/function () {
1367
1297
 
1368
1298
  _proto.runSegmentation = /*#__PURE__*/function () {
1369
1299
  var _runSegmentation = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee5(skipProcessing) {
1370
- var start, end;
1371
1300
  return runtime_1.wrap(function _callee5$(_context5) {
1372
1301
  while (1) {
1373
1302
  switch (_context5.prev = _context5.next) {
1374
1303
  case 0:
1375
1304
  if (!this.tfLite) {
1376
- _context5.next = 8;
1305
+ _context5.next = 5;
1377
1306
  break;
1378
1307
  }
1379
1308
 
1380
- start = performance.now();
1309
+ // const start = performance.now();
1381
1310
  this.resizeInputData();
1382
- _context5.next = 5;
1311
+ _context5.next = 4;
1383
1312
  return this.infer(skipProcessing);
1384
1313
 
1385
- case 5:
1386
- this.postProcessing();
1387
- end = performance.now();
1388
- this.log(TAG$1, 'time taken', end - start);
1314
+ case 4:
1315
+ this.postProcessing(); // const end = performance.now();
1316
+ // this.log(TAG,"time taken",end -start);
1389
1317
 
1390
- case 8:
1318
+ case 5:
1391
1319
  case "end":
1392
1320
  return _context5.stop();
1393
1321
  }
@@ -1447,6 +1375,80 @@ var HMSVirtualBackgroundPlugin = /*#__PURE__*/function () {
1447
1375
  return addBlurToBackground;
1448
1376
  }();
1449
1377
 
1378
+ _proto.initSharpenFilter = function initSharpenFilter() {
1379
+ var _this2 = this;
1380
+
1381
+ this.filters.tmpCanvas = document.createElement('canvas');
1382
+ this.filters.tmpCtx = this.filters.tmpCanvas.getContext('2d');
1383
+
1384
+ this.filters.createImageData = function (w, h) {
1385
+ return _this2.filters.tmpCtx.createImageData(w, h);
1386
+ };
1387
+
1388
+ this.filters.convolute = function (pixels, weights, opaque) {
1389
+ if (weights === void 0) {
1390
+ weights = [0, -1, 0, -1, 5, -1, 0, -1, 0];
1391
+ }
1392
+
1393
+ var side = Math.round(Math.sqrt(weights.length));
1394
+ var halfSide = Math.floor(side / 2);
1395
+ var src = pixels.data;
1396
+ var sw = pixels.width;
1397
+ var sh = pixels.height; // pad output by the convolution matrix
1398
+
1399
+ var w = sw;
1400
+ var h = sh;
1401
+
1402
+ var output = _this2.filters.createImageData(w, h);
1403
+
1404
+ var dst = output.data; // go through the destination image pixels
1405
+
1406
+ var alphaFac = opaque ? 1 : 0;
1407
+
1408
+ for (var y = 0; y < h; y = y + 1) {
1409
+ for (var x = 0; x < w; x = x + 1) {
1410
+ var dstOff = (y * w + x) * 4;
1411
+
1412
+ if (src[dstOff + 3] == 0) {
1413
+ continue;
1414
+ } else if (x < w && y < h) {
1415
+ var sy = y;
1416
+ var sx = x; // calculate the weighed sum of the source image pixels that
1417
+ // fall under the convolution matrix
1418
+
1419
+ var r = 0,
1420
+ g = 0,
1421
+ b = 0,
1422
+ a = 0;
1423
+
1424
+ for (var cy = 0; cy < side; cy++) {
1425
+ for (var cx = 0; cx < side; cx++) {
1426
+ var scy = sy + cy - halfSide;
1427
+ var scx = sx + cx - halfSide;
1428
+
1429
+ if (scy >= 0 && scy < sh && scx >= 0 && scx < sw) {
1430
+ var srcOff = (scy * sw + scx) * 4;
1431
+ var wt = weights[cy * side + cx];
1432
+ r += src[srcOff] * wt;
1433
+ g += src[srcOff + 1] * wt;
1434
+ b += src[srcOff + 2] * wt;
1435
+ a += src[srcOff + 3] * wt;
1436
+ }
1437
+ }
1438
+ }
1439
+
1440
+ dst[dstOff] = r;
1441
+ dst[dstOff + 1] = g;
1442
+ dst[dstOff + 2] = b;
1443
+ dst[dstOff + 3] = a + alphaFac * (255 - a);
1444
+ }
1445
+ }
1446
+ }
1447
+
1448
+ return output;
1449
+ };
1450
+ };
1451
+
1450
1452
  return HMSVirtualBackgroundPlugin;
1451
1453
  }();
1452
1454