Skip to content

Commit

Permalink
Merge pull request #2 from zaru/feat
Browse files Browse the repository at this point in the history
Added the background transparency quality menu
  • Loading branch information
zaru authored May 20, 2020
2 parents 8bbcb70 + ccbe6dd commit 39cd0f6
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 48 deletions.
65 changes: 28 additions & 37 deletions app/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const bodyPix = require('@tensorflow-models/body-pix');
const VideoManager = require('./video-manager');
const TrayMenu = require('./tray-menu');
const Settings = require('./settings');
const settings = new Settings;

Expand All @@ -13,6 +14,9 @@ const state = {
return this.videoHeight / this.videoWidth;
},
tray: null,
trayMenu: null,
net: null,
changingQuality: false,
};

/**
Expand All @@ -26,15 +30,15 @@ async function workload(deviceId) {

_resizeElement(window.innerWidth, window.innerHeight);

const net = await bodyPix.load(settings.getBodyPixModel());
state.net = await bodyPix.load(settings.getBodyPixModelParam());

const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const originalCanvas = document.getElementById('original-canvas');

async function segmentationFrame() {
if (!state.changingVideo) {
const segmentation = await net.segmentPerson(state.video);
if (!state.changingVideo || !state.changingQuality) {
const segmentation = await state.net.segmentPerson(state.video);

const originalCtx = originalCanvas.getContext('2d');
const scale = originalCanvas.width / video.videoWidth;
Expand Down Expand Up @@ -65,6 +69,18 @@ function switchVideo(deviceId) {
settings.setDeviceId(deviceId);
}

/**
* Switch BodyPix quality
* @param {string} quality
* @return {Promise<void>}
*/
async function switchQuality(quality) {
state.changingQuality = true;
settings.setBodyPixModel(quality);
state.net = await bodyPix.load(settings.getBodyPixModelParam());
state.changingQuality = false;
}

function stopExistingVideoCapture() {
if (state.video && state.video.srcObject) {
state.video.srcObject.getTracks().forEach((track) => {
Expand Down Expand Up @@ -204,40 +220,15 @@ window.addEventListener('resize', () => {
}, 500);
});

/**
* Build tray menu
* @param {MediaDeviceInfo[]} videoList
*/
function buildTrayMenu(videoList) {
const remote = window.remote;
const {Tray, Menu} = remote;
const icon = window.os.platform() === 'darwin' ? 'TrayIconTemplate.png' : '[email protected]';
state.tray = new Tray(window.__dirname + `/assets/${icon}`);

const videoMenu = [];
videoList.forEach((device) => {
videoMenu.push({
label: device.label,
click() {
switchVideo(device.deviceId);
},
});
});

const menu = Menu.buildFromTemplate([
{
label: 'Select Video',
submenu: videoMenu,
},
]);

state.tray.setContextMenu(menu);
}

const videoManager = new VideoManager;
const trayMenu = new TrayMenu(window);
videoManager.getVideoList().then((list) => {
buildTrayMenu(list);

const deviceId = settings.getDeviceId() || list[0].deviceId;
workload(deviceId);
state.deviceId = settings.getDeviceId() || list[0].deviceId;
trayMenu.deviceId = state.deviceId;
trayMenu.quality = settings.getBodyPixModel();
trayMenu.videoList = list;
trayMenu.addEventListenerToVideoMenu(switchVideo);
trayMenu.addEventListenerToQualityMenu(switchQuality);
trayMenu.launch();
workload(state.deviceId);
});
24 changes: 20 additions & 4 deletions app/main.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const {app, BrowserWindow} = require('electron');
const {app, BrowserWindow, ipcMain} = require('electron');
const isDev = require('electron-is-dev');
const os = require('os');
const path = require('path');
Expand All @@ -8,13 +8,19 @@ if (isDev) {
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = true;
}


/**
* @type {BrowserWindow}
*/
let win = null;

/**
* MainWindow
*/
function createWindow() {
const win = new BrowserWindow({
width: 640,
height: 480,
win = new BrowserWindow({
width: 320,
height: 240,
hasShadow: false,
transparent: true,
frame: false,
Expand Down Expand Up @@ -62,3 +68,13 @@ app.on('activate', () => {
createWindow();
}
});

ipcMain.on('windowResize', (event, arg) => {
let size = [320, 240];
if (arg === 'Small') {
size = [160, 120];
} else if (arg === 'Big') {
size = [640, 480];
}
win.setSize(...size);
});
1 change: 1 addition & 0 deletions app/preload.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
window.remote = require('electron').remote;
window.ipcRenderer = require('electron').ipcRenderer;
window.__dirname = __dirname;
window.os = require('os');
26 changes: 20 additions & 6 deletions app/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,27 @@ module.exports = class Settings {
}

/**
* Set deviceId
* Set quality
* @param {string} key
*/
setBodyPixModel(key) {
localStorage.setItem('bodyPixModel', key);
}

/**
* Get deviceId
* Get quality
* @return {string}
*/
getBodyPixModel() {
const key = localStorage.getItem('bodyPixModel') || 'low';
return localStorage.getItem('bodyPixModel') || 'Middle';
}

/**
* Get BodyPix model param
* @return {string}
*/
getBodyPixModelParam() {
const key = this.getBodyPixModel();
return this._bodyPixModelList()[key];
}

Expand All @@ -48,13 +56,19 @@ module.exports = class Settings {
*/
_bodyPixModelList() {
return {
low: {
Low: {
architecture: 'MobileNetV1',
outputStride: 16,
multiplier: 0.5,
multiplier: 0.75,
quantBytes: 2,
},
high: {
Middle: {
architecture: 'MobileNetV1',
outputStride: 8,
multiplier: 1.0,
quantBytes: 4,
},
High: {
architecture: 'ResNet50',
outputStride: 16,
multiplier: 1.0,
Expand Down
160 changes: 160 additions & 0 deletions app/tray-menu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/**
* TrayMenu class
*/
module.exports = class TrayMenu {
/**
* Constractor
* @param {Window} window
*/
constructor(window) {
this.window = window;

this._deviceId = '';
this._videoList = [];
this._quality = '';

this.tray = null;
this.trayMenu = null;
this.callbackVideoMenu = null;
this.callbackQualityMenu = null;
}

/**
* Set deviceId
* @param {string} deviceId
*/
set deviceId(deviceId) {
this._deviceId = deviceId;
}

/**
* Set video list
* @param {MediaDeviceInfo[]} videoList
*/
set videoList(videoList) {
this._videoList = videoList;
}

/**
* Set quality
* @param {string} quality
*/
set quality(quality) {
this._quality = quality;
}

/**
* Add event listener to video menu
* @param {function} callback
*/
addEventListenerToVideoMenu(callback) {
this.callbackVideoMenu = callback;
}

/**
* Add event listener to quality menu
* @param {function} callback
*/
addEventListenerToQualityMenu(callback) {
this.callbackQualityMenu = callback;
}

/**
* Launch tray menu
*/
launch() {
this._buildTrayMenu();
}

/**
* Build video sub menu
* @return {[]}
* @private
*/
_buildVideoSubMenu() {
const videoMenu = [];
this._videoList.forEach((device) => {
videoMenu.push({
label: device.label,
click: () => {
if (this.callbackVideoMenu) {
this.callbackVideoMenu(device.deviceId);
}
},
type: 'radio',
checked: this._deviceId === device.deviceId,
});
});
return videoMenu;
}

/**
* Build window size sub menu
* @return {{checked: boolean, label: string, type: string, click(): void}[]}
* @private
*/
_buildSizeSubMenu() {
const menu = [];
['Big', 'Middle', 'Small'].forEach((size) => {
menu.push({
label: size,
click() {
this.window.ipcRenderer.send('windowResize', size);
},
type: 'radio',
checked: size === 'Middle',
});
});
return menu;
}

/**
* Build quality sub menu
* @return {{checked: boolean, label: string, type: string, click(): void}[]}
* @private
*/
_buildQualitySubMenu() {
const menu = [];
['High', 'Middle', 'Low'].forEach((size) => {
menu.push({
label: size,
click: () => {
if (this.callbackQualityMenu) {
this.callbackQualityMenu(size);
}
},
type: 'radio',
checked: this._quality === size,
});
});
return menu;
}

/**
* Build video sub menu
*/
_buildTrayMenu() {
const remote = this.window.remote;
const {Tray, Menu} = remote;
const icon = this.window.os.platform() === 'darwin' ?
'TrayIconTemplate.png' : '[email protected]';
this.tray = new Tray(this.window.__dirname + `/assets/${icon}`);

const menu = Menu.buildFromTemplate([
{
label: 'Select video',
submenu: this._buildVideoSubMenu(),
},
{
label: 'Select size',
submenu: this._buildSizeSubMenu(),
},
{
label: 'Select quality',
submenu: this._buildQualitySubMenu(),
},
]);

this.tray.setContextMenu(menu);
}
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
{
"name": "mewcam",
"version": "1.2.0",
"version": "1.3.0",
"description": "",
"main": "app/main.js",
"scripts": {
"start": "concurrently \"cross-env NODE_ENV=development parcel ./app/index.html --no-hmr\" \"wait-on http://localhost:1234 && electron . \"",
"build": "cross-env NODE_ENV=production parcel build ./app/index.html --public-url ./ --out-dir ./dist-bodypix-app",
"pack:mac": "electron-builder --mac --x64",
"pack:win": "electron-builder --win --x64",
"pack:all": "npm run build && electron-builder --mac --win --x64",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
Expand Down

0 comments on commit 39cd0f6

Please sign in to comment.