@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.
- package/dist/HMSVirtualBackgroundPlugin.d.ts +6 -4
- package/dist/hms-virtual-background.cjs.development.js +134 -132
- package/dist/hms-virtual-background.cjs.development.js.map +1 -1
- package/dist/hms-virtual-background.cjs.production.min.js +1 -1
- package/dist/hms-virtual-background.cjs.production.min.js.map +1 -1
- package/dist/hms-virtual-background.esm.js +132 -132
- package/dist/hms-virtual-background.esm.js.map +1 -1
- package/package.json +2 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import '@tensorflow/tfjs-backend-webgl';
|
|
2
|
-
import { HMSVideoPlugin, HMSVideoPluginType } from
|
|
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
|
-
|
|
24
|
-
|
|
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(
|
|
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.
|
|
943
|
-
this.
|
|
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,
|
|
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.
|
|
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(
|
|
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 ===
|
|
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 =
|
|
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 ===
|
|
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 =
|
|
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,
|
|
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
|
|
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(
|
|
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
|
|
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 ===
|
|
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'; // //
|
|
1253
|
+
this.outputCtx.filter = 'none'; // //Draw the foreground
|
|
1326
1254
|
|
|
1327
1255
|
this.outputCtx.drawImage(this.input, 0, 0);
|
|
1328
|
-
|
|
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.
|
|
1332
|
-
this.outputCtx.putImageData(output, 0, 0);
|
|
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 =
|
|
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 =
|
|
1311
|
+
_context5.next = 4;
|
|
1383
1312
|
return this.infer(skipProcessing);
|
|
1384
1313
|
|
|
1385
|
-
case
|
|
1386
|
-
this.postProcessing();
|
|
1387
|
-
|
|
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
|
|
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
|
|