-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
better abstractions for VideoContainer. implemented basic clm image e…
…xample (no manual selection yet)
- Loading branch information
Showing
18 changed files
with
516 additions
and
133 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "lib/stats.js"] | ||
path = lib/stats.js | ||
url = https://github.com/jsio-private/stats.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,8 +8,8 @@ body | |
.app-cmpt | ||
display flex | ||
|
||
* | ||
flex-shrink 0 | ||
// * | ||
// flex-shrink 0 | ||
|
||
.example-wrapper | ||
padding 20px | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
import React from 'react'; | ||
import classNames from 'classnames'; | ||
|
||
import RaisedButton from 'material-ui/RaisedButton'; | ||
|
||
import Tracker from 'clmtrackr/js/Tracker'; | ||
import { resizeImage } from 'clmtrackr/js/utils/image'; | ||
import { requestAnimFrame, cancelRequestAnimFrame } from 'clmtrackr/js/utils/anim'; | ||
|
||
import TrackerContainer from 'clmtrackr/ui/container/TrackerContainer'; | ||
|
||
import './ClmImageExample.styl'; | ||
|
||
|
||
const MEDIA_SRC = 'media/franck_02159.jpg'; | ||
const MEDIA_SIZE = { width: 625, height: 500 }; | ||
|
||
|
||
export default class SimpleExample extends React.Component { | ||
constructor () { | ||
super(); | ||
this.state = { | ||
tracker: null, | ||
isTrackerRunning: false, | ||
|
||
showLoadImageText: false, | ||
convergenceText: 'n/a', | ||
convergenceStatus: '', | ||
|
||
fileList: [], | ||
fileIndex: 0 | ||
}; | ||
|
||
this._boundOnFrame = this._onFrame.bind(this); | ||
} | ||
|
||
_loadMediaSrc (src) { | ||
const img = new Image(); | ||
img.onload = () => { | ||
const trackerContainer = this.refs.trackerContainer; | ||
const mediaCanvas = trackerContainer.refs.media; | ||
resizeImage(img, { | ||
canvas: mediaCanvas, | ||
padding: 0, | ||
paddingJitter: 0 | ||
}); | ||
}; | ||
img.src = MEDIA_SRC; | ||
} | ||
|
||
componentDidMount () { | ||
this._loadMediaSrc(MEDIA_SRC); | ||
|
||
const tracker = new Tracker({ stopOnConvergence: true }); | ||
this.setState({ tracker }); | ||
tracker.init(); | ||
|
||
tracker.on('notFound', (event) => { | ||
tracker.stop(); | ||
alert('The tracking had problems with finding a face in this image. Try selecting the face in the image manually.') | ||
}); | ||
|
||
// detect if tracker loses tracking of face | ||
tracker.on('lost', (event) => { | ||
tracker.stop(); | ||
alert('The tracking had problems converging on a face in this image. Try selecting the face in the image manually.') | ||
}); | ||
|
||
// detect if tracker has converged | ||
tracker.on('converged', (event) => { | ||
this.setState({ convergenceText: 'CONVERGED', convergenceStatus: 'good' }); | ||
// stop drawloop | ||
cancelRequestAnimFrame(this._boundOnFrame); | ||
}); | ||
|
||
tracker.on('started', () => this.setState({ isTrackerRunning: true })); | ||
tracker.on('stopped', () => this.setState({ isTrackerRunning: false })); | ||
} | ||
|
||
_onFrame () { | ||
// Update overlay | ||
const trackerContainer = this.refs.trackerContainer; | ||
if (trackerContainer) { | ||
const tracker = this.state.tracker; | ||
const cc = trackerContainer.refs.canvas.getContext('2d'); | ||
cc.clearRect(0, 0, MEDIA_SIZE.width, MEDIA_SIZE.height); | ||
tracker.draw(cc.canvas); | ||
} | ||
requestAnimFrame(this._boundOnFrame); | ||
} | ||
|
||
_start (e) { | ||
const trackerContainer = this.refs.trackerContainer; | ||
const tracker = this.state.tracker; | ||
tracker.start(trackerContainer.refs.media); | ||
this._onFrame(); | ||
} | ||
|
||
_selectBox (e) { | ||
alert('Coming soon!'); | ||
} | ||
|
||
_selectFile (e) { | ||
e.preventDefault(); | ||
const fileInput = this.refs.fileInput; | ||
fileInput.click(); | ||
} | ||
|
||
_handleFileSelect (e) { | ||
const files = e.target.files; | ||
const fileList = []; | ||
for (let i = 0; i < files.length; i++) { | ||
if (!files[i].type.match('image.*')) { | ||
continue; | ||
} | ||
fileList.push(files[i]); | ||
} | ||
if (files.length > 0) { | ||
this.setState({ fileIndex: 0 }); | ||
} | ||
|
||
this.setState({ fileList }); | ||
|
||
setTimeout(() => { this._loadImage(); }); | ||
} | ||
|
||
_loadImage () { | ||
const { fileList, fileIndex, tracker } = this.state; | ||
if (fileList.indexOf(fileIndex) >= 0) { return; } | ||
|
||
const reader = new FileReader(); | ||
reader.onload = (e) => { | ||
// Render thumbnail. | ||
this._loadMediaSrc(e.target.result); | ||
}; | ||
reader.readAsDataURL(fileList[fileIndex]); | ||
|
||
const trackerContainer = this.refs.trackerContainer; | ||
const overlayCC = trackerContainer.refs.canvas.getContext('2d'); | ||
overlayCC.clearRect(0, 0, MEDIA_SIZE.width, MEDIA_SIZE.height); | ||
this.setState({ convergenceText: 'n/a', convergenceStatus: '' }); | ||
tracker.stop(); | ||
tracker.reset(); | ||
} | ||
|
||
render () { | ||
let loadImageText; | ||
if (this.state.showLoadImageText) { | ||
loadImageText = <p>To try it out with your own image, choose a file above by clicking "choose file". If the tracking has problems, try selecting the face in the image manually by clicking "manually select face", and click and hold to drag a square around the face in the image.</p>; | ||
} | ||
|
||
return ( | ||
<div className='clm-image-example-cmpt'> | ||
<h1>Tracking a video tag</h1> | ||
|
||
<TrackerContainer | ||
ref='trackerContainer' | ||
mediaType={'image'} | ||
mediaSrc={MEDIA_SRC} | ||
mediaSize={MEDIA_SIZE} | ||
showStats={true} | ||
tracker={this.state.tracker} | ||
/> | ||
|
||
<div className='control-row'> | ||
<div> | ||
<RaisedButton | ||
label='start' | ||
onClick={this._start.bind(this)} | ||
disabled={this.state.isTrackerRunning} | ||
/> | ||
<RaisedButton | ||
label='manually select face' | ||
onClick={this._selectBox.bind(this)} | ||
/> | ||
<RaisedButton | ||
label='Choose File' | ||
onClick={this._selectFile.bind(this)} | ||
/> | ||
<input | ||
type='file' | ||
className='file-input' | ||
ref='fileInput' | ||
onChange={this._handleFileSelect.bind(this)} | ||
/> | ||
</div> | ||
|
||
<div | ||
className={classNames( | ||
'convergence-text', | ||
this.state.convergenceStatus | ||
)} | ||
> | ||
Convergence: {this.state.convergenceText} | ||
</div> | ||
</div> | ||
|
||
<div> | ||
<p>This is an example of precise face-tracking in an image using the javascript library <a href='https://github.com/auduno/clmtrackr'><em>clmtrackr</em></a>. To try it out, simply click start.</p> | ||
{loadImageText} | ||
</div> | ||
|
||
<p>The image is from the <a href='http://www-prima.inrialpes.fr/FGnet/data/01-TalkingFace/talking_face.html'>FG-net Talking Face</a> project</p> | ||
</div> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
.clm-image-example-cmpt | ||
position relative | ||
|
||
.control-row | ||
display flex | ||
justify-content space-between | ||
align-items center | ||
|
||
.file-input | ||
visibility hidden | ||
position absolute | ||
|
||
.convergence-text | ||
background-color #cccc00 | ||
transition background-color 0.2s | ||
min-width 100px | ||
|
||
&.good | ||
background-color #00FF00 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import React from 'react'; | ||
|
||
import Tracker from 'clmtrackr/js/Tracker'; | ||
|
||
import TrackerContainer from 'clmtrackr/ui/container/TrackerContainer'; | ||
|
||
import './ClmImageExample.styl'; | ||
|
||
|
||
const MEDIA_SRC = 'media/franck.ogv'; | ||
const MEDIA_SIZE = { width: 368, height: 288 }; | ||
|
||
|
||
export default class SimpleExample extends React.Component { | ||
constructor () { | ||
super(); | ||
this.state = { | ||
tracker: null, | ||
points: null | ||
}; | ||
} | ||
|
||
componentDidMount () { | ||
const tracker = new Tracker(); | ||
this.setState({ tracker }); | ||
tracker.init(); | ||
|
||
const trackerContainer = this.refs.trackerContainer; | ||
tracker.start(trackerContainer.refs.media); | ||
|
||
requestAnimationFrame(this._onFrame.bind(this)); | ||
} | ||
|
||
_onFrame () { | ||
// Update overlay | ||
const trackerContainer = this.refs.trackerContainer; | ||
if (trackerContainer) { | ||
const tracker = this.state.tracker; | ||
const cc = trackerContainer.refs.canvas.getContext('2d'); | ||
cc.clearRect(0, 0, MEDIA_SIZE.width, MEDIA_SIZE.height); | ||
tracker.draw(cc.canvas); | ||
|
||
// Update the rendered points | ||
this.setState({ points: tracker.getCurrentPosition() }); | ||
} | ||
requestAnimationFrame(this._onFrame.bind(this)); | ||
} | ||
|
||
render () { | ||
const positionChildren = []; | ||
|
||
const points = this.state.points; | ||
if (points) { | ||
for (let p = 0; p < 10; p++) { | ||
const positionString = ( | ||
'featurepoint ' + p + ' : ' + | ||
'[' + | ||
points[p][0].toFixed(2) + | ||
', ' + | ||
points[p][1].toFixed(2) + | ||
']' | ||
); | ||
positionChildren.push(<div key={p}>{positionString}</div>); | ||
} | ||
} | ||
|
||
return ( | ||
<div className='clm-image-example-cmpt'> | ||
<h1>Tracking a video tag</h1> | ||
|
||
<TrackerContainer | ||
ref='trackerContainer' | ||
mediaType={'video'} | ||
mediaSrc={MEDIA_SRC} | ||
mediaSize={MEDIA_SIZE} | ||
showStats={true} | ||
tracker={this.state.tracker} | ||
/> | ||
|
||
<p>Printing coordinates of the first 10 points in facial features:</p> | ||
|
||
<div className='positions'> | ||
{positionChildren} | ||
</div> | ||
</div> | ||
); | ||
} | ||
} |
Oops, something went wrong.