Skip to content

Commit

Permalink
Merge pull request #1 from nhtua/master
Browse files Browse the repository at this point in the history
Init project
  • Loading branch information
nhtua committed Oct 21, 2020
2 parents e2d5353 + edda2f9 commit c04e62b
Show file tree
Hide file tree
Showing 7 changed files with 516 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# GreenCam

## What is GreenCam?

GreenCam is **a virtual green backdrop** for OBS Studio. Yep! you are not crazy. It basically replaces every things around you by green color. So that you can use the Chroma Key filter in OBS Studio to put yourself in any other video. GreenCam is powered by a machine learning technology called [Tensorflow](https://github.com/tensorflow/tfjs) and its public model [BodyPix](https://github.com/tensorflow/tfjs-models/tree/master/body-pix).

I do a lot of live streaming at home. There is a small living room, a lot of messy stuffs that needs to hide, not much spaces (and budget) to setup a standard professional studio. I found there are some applications, like XSplit VCam or Chroma Cam, which removes/changes the background of your video, but I don't want to pay them since I can do exactly the same thing for FREE!!

## How to use GreenCam with OBS Studio

### Prerequisite
I tested GreenCam with my OBS Studio 26. But you should able to run GreenCam in any version support Browser plugin.

- OBS Studio with Browser plugin enabled
- NodeJS Erbium (12 LTS) or later
- A webcam

### Follow steps below to setup:

1. Download source code from [Github](https://github.com/nhtua/greencam).
2. Run commands:
```
$ cd /path/to/greencam
$ npm install
```
3. Edit your application shortcut. I'm using Linux, but Windows should be similar. The ideas is to add some options to the starting command which enables OBS loading a webpage with a WebCam.
```
$ cd /usr/share/applications/
$ ls | grep obs
# pick the name that you see here. For me, it's `com.obsproject.Studio.desktop`
$ sudo vi com.obsproject.Studio.desktop
# find the line `Exec=`, modify it into the line below
Exec=obs --enable-gpu --enable-media-stream
# press : and "x", then press Enter to escape Vi editor
```
4. Open OBS studio, in a scene
- click `+` button on the `source` panel
- choose `Browser`.
- Name it `GreenCam` then click `OK`
5. In the next dialog
- tick the box `Local file`
- Pick the file `index.html` from GreenCam source code
- input width=640, height=480
- leave everything else default
- click `OK` at the end.
6. Right click on your new `source` - `GreenCam`
- Choose Filter
- On the `Effect Filters` panel, click `+`
- Choose `Chroma Key`
- Key color type = `green`
7. Close the dialog of filters. **Congrats!** You have your new webcam with background removed.

## Development
It is a hack I did in one night. But might be some errors, or incompatible problems will happens in your machine. Also, there are a lot of features that may be included in next version of GreenCam, like:
- Custom parameters/algorithm to have smoother, better shapes
- Custom background color, video
- Add an editor that can run in browser to test customized parameters and generate a link to run in OBS

All Pull Requests are welcome!!
82 changes: 82 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
window.onload = (event) => {
start()
}

function getVideo() {
return document.getElementById("inputVideo");
}
function getCanvasContext(id) {
const canvas = document.getElementById(id);
return canvas.getContext('2d');
}

function start() {
const video = getVideo();
if (navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({ video: true })
.then(function (stream) {
video.srcObject = stream;
video.play();

video.onloadeddata = (e) => {
initMLModel()
}
})
.catch(function (err) {
console.log("Something went wrong!");
console.error(err);
});
}
}

function initMLModel() {
const video = getVideo();
const context = getCanvasContext("outputVideo");
bodyPix.load({
architechture: 'MobileNetV1',
outputStride: 16,
multiplier: 0.75,
quantBytes: 2
}).then(model => {
console.log('BodyPix model loaded.');
transformFrame(model, video, context)
}).catch(err => {
console.error(err);
})
}

function transformFrame(model, sourceVideo, targetCanvasCtx) {
const w = sourceVideo.videoWidth || sourceVideo.width;
const h = sourceVideo.videoHeight || sourceVideo.height;
const tempCanvas = document.getElementById('bufferVideo');
const tempCtx = tempCanvas.getContext('2d');
tempCtx.drawImage(sourceVideo, 0, 0, w, h);
const frame = tempCtx.getImageData(0, 0, w, h);
console.log(frame);
model.segmentPerson(tempCanvas, {
flipHorizontal: true,
internalResolution: 'high',
segmentationThreshold: 0.3,
scoreThreshold: 0.3,
maxDetections: 1,
nmsRadius: 20
}).then(segment => {
for (let x = 0; x < w; x++) {
for (let y = 0; y < h; y++) {
let n = x + y * w;
if(segment.data[n] == 0) {
frame.data[n * 4 + 0] = 0;
frame.data[n * 4 + 1] = 255;
frame.data[n * 4 + 2] = 0;
frame.data[n * 4 + 3] = 255;
}
}
}
targetCanvasCtx.putImageData(frame, 0, 0);
window.requestAnimationFrame(()=>{
transformFrame(model, sourceVideo, targetCanvasCtx)
});
}).catch(err => {
console.error(err);
});
}
17 changes: 17 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Virtual Green Background</title>
<script src="node_modules/@tensorflow/tfjs/dist/tf.min.js" charset="utf-8"></script>
<script src="node_modules/@tensorflow-models/body-pix/dist/body-pix.min.js" charset="utf-8"></script>
<script src="node_modules/bluebird/js/browser/bluebird.min.js" charset="utf-8"></script>
<script src="app.js" charset="utf-8"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<video id="inputVideo" width="640" height="480" autoplay="true" muted></video>
<canvas id="outputVideo" width="640" height="480"></canvas>
<canvas id="bufferVideo" width="640" height="480"></canvas>
</body>
</html>
Loading

0 comments on commit c04e62b

Please sign in to comment.