@@ -21,7 +21,7 @@ import {isMobile} from './util';
2121
2222// These anchor points allow the hand pointcloud to resize according to its
2323// position in the input.
24- const ANCHOR_POINTS = [ [ 0 , 0 , 0 ] , [ 0 , 1 , 0 ] , [ - 1 , 0 , 0 ] , [ - 1 , - 1 , 0 ] ] ;
24+ const ANCHOR_POINTS = [ [ 0 , 0 , 0 ] , [ 0 , 0. 1, 0 ] , [ - 0. 1, 0 , 0 ] , [ - 0. 1, - 0. 1, 0 ] ] ;
2525
2626const fingerLookupIndices = {
2727 thumb : [ 0 , 1 , 2 , 3 , 4 ] ,
@@ -39,18 +39,27 @@ const connections = [
3939 [ 0 , 17 ] , [ 17 , 18 ] , [ 18 , 19 ] , [ 19 , 20 ]
4040] ;
4141
42+ function createScatterGLContext ( selectors ) {
43+ const scatterGLEl = document . querySelector ( selectors ) ;
44+ return {
45+ scatterGLEl,
46+ scatterGL : new scatter . ScatterGL ( scatterGLEl , {
47+ 'rotateOnStart' : true ,
48+ 'selectEnabled' : false ,
49+ 'styles' : { polyline : { defaultOpacity : 1 , deselectedOpacity : 1 } }
50+ } ) ,
51+ scatterGLHasInitialized : false ,
52+ } ;
53+ }
54+
55+ const scatterGLCtxtLeftHand = createScatterGLContext ( '#scatter-gl-container-left' ) ;
56+ const scatterGLCtxtRightHand = createScatterGLContext ( '#scatter-gl-container-right' ) ;
57+
4258export class Camera {
4359 constructor ( ) {
4460 this . video = document . getElementById ( 'video' ) ;
4561 this . canvas = document . getElementById ( 'output' ) ;
4662 this . ctx = this . canvas . getContext ( '2d' ) ;
47- this . scatterGLEl = document . querySelector ( '#scatter-gl-container' ) ;
48- this . scatterGL = new scatter . ScatterGL ( this . scatterGLEl , {
49- 'rotateOnStart' : true ,
50- 'selectEnabled' : false ,
51- 'styles' : { polyline : { defaultOpacity : 1 , deselectedOpacity : 1 } }
52- } ) ;
53- this . scatterGLHasInitialized = false ;
5463 }
5564
5665 /**
@@ -108,12 +117,14 @@ export class Camera {
108117 camera . ctx . translate ( camera . video . videoWidth , 0 ) ;
109118 camera . ctx . scale ( - 1 , 1 ) ;
110119
111- camera . scatterGLEl . style =
112- `width: ${ videoWidth } px; height: ${ videoHeight } px;` ;
113- camera . scatterGL . resize ( ) ;
120+ for ( const ctxt of [ scatterGLCtxtLeftHand , scatterGLCtxtRightHand ] ) {
121+ ctxt . scatterGLEl . style =
122+ `width: ${ videoWidth / 2 } px; height: ${ videoHeight / 2 } px;` ;
123+ ctxt . scatterGL . resize ( ) ;
114124
115- camera . scatterGLEl . style . display =
116- params . STATE . modelConfig . render3D ? 'inline-block' : 'none' ;
125+ ctxt . scatterGLEl . style . display =
126+ params . STATE . modelConfig . render3D ? 'inline-block' : 'none' ;
127+ }
117128
118129 return camera ;
119130 }
@@ -132,31 +143,53 @@ export class Camera {
132143 * @param hands A list of hands to render.
133144 */
134145 drawResults ( hands ) {
135- for ( const hand of hands ) {
136- this . drawResult ( hand ) ;
146+ // Sort by right to left hands.
147+ hands . sort ( ( hand1 , hand2 ) => {
148+ if ( hand1 . handedness < hand2 . handedness ) return 1 ;
149+ if ( hand1 . handedness > hand2 . handedness ) return - 1 ;
150+ return 0 ;
151+ } ) ;
152+
153+ // Pad hands to clear empty scatter GL plots.
154+ while ( hands . length < 2 ) hands . push ( { } ) ;
155+
156+ for ( let i = 0 ; i < hands . length ; ++ i ) {
157+ // Third hand and onwards scatterGL context is set to null since we
158+ // don't render them.
159+ const ctxt = [ scatterGLCtxtLeftHand , scatterGLCtxtRightHand ] [ i ] ;
160+ this . drawResult ( hands [ i ] , ctxt ) ;
137161 }
138162 }
139163
140164 /**
141165 * Draw the keypoints on the video.
142166 * @param hand A hand with keypoints to render.
167+ * @param ctxt Scatter GL context to render 3D keypoints to.
143168 */
144- drawResult ( hand ) {
169+ drawResult ( hand , ctxt ) {
145170 if ( hand . keypoints != null ) {
146- this . drawKeypoints ( hand . keypoints ) ;
171+ this . drawKeypoints ( hand . keypoints , hand . handedness ) ;
172+ }
173+ // Don't render 3D hands after first two.
174+ if ( ctxt == null ) {
175+ return ;
147176 }
148177 if ( hand . keypoints3D != null && params . STATE . modelConfig . render3D ) {
149- this . drawKeypoints3D ( hand . keypoints3D ) ;
178+ this . drawKeypoints3D ( hand . keypoints3D , hand . handedness , ctxt ) ;
179+ } else {
180+ // Clear scatter plot.
181+ this . drawKeypoints3D ( [ ] , '' , ctxt ) ;
150182 }
151183 }
152184
153185 /**
154186 * Draw the keypoints on the video.
155187 * @param keypoints A list of keypoints.
188+ * @param handedness Label of hand (either Left or Right).
156189 */
157- drawKeypoints ( keypoints ) {
190+ drawKeypoints ( keypoints , handedness ) {
158191 const keypointsArray = keypoints ;
159- this . ctx . fillStyle = ' Red';
192+ this . ctx . fillStyle = handedness === 'Left' ? ' Red' : 'Blue ';
160193 this . ctx . strokeStyle = 'White' ;
161194 this . ctx . lineWidth = params . DEFAULT_LINE_WIDTH ;
162195
@@ -194,29 +227,29 @@ export class Camera {
194227 this . ctx . fill ( ) ;
195228 }
196229
197- drawKeypoints3D ( keypoints ) {
230+ drawKeypoints3D ( keypoints , handedness , ctxt ) {
198231 const scoreThreshold = params . STATE . modelConfig . scoreThreshold || 0 ;
199232 const pointsData =
200233 keypoints . map ( keypoint => ( [ - keypoint . x , - keypoint . y , - keypoint . z ] ) ) ;
201234
202235 const dataset =
203236 new scatter . ScatterGL . Dataset ( [ ...pointsData , ...ANCHOR_POINTS ] ) ;
204237
205- this . scatterGL . setPointColorer ( ( i ) => {
238+ ctxt . scatterGL . setPointColorer ( ( i ) => {
206239 if ( keypoints [ i ] == null || keypoints [ i ] . score < scoreThreshold ) {
207240 // hide anchor points and low-confident points.
208241 return '#ffffff' ;
209242 }
210- return ' #ff0000' /* Red */ ;
243+ return handedness === 'Left' ? ' #ff0000' : '#0000ff' ;
211244 } ) ;
212245
213- if ( ! this . scatterGLHasInitialized ) {
214- this . scatterGL . render ( dataset ) ;
246+ if ( ! ctxt . scatterGLHasInitialized ) {
247+ ctxt . scatterGL . render ( dataset ) ;
215248 } else {
216- this . scatterGL . updateDataset ( dataset ) ;
249+ ctxt . scatterGL . updateDataset ( dataset ) ;
217250 }
218251 const sequences = connections . map ( pair => ( { indices : pair } ) ) ;
219- this . scatterGL . setSequences ( sequences ) ;
220- this . scatterGLHasInitialized = true ;
252+ ctxt . scatterGL . setSequences ( sequences ) ;
253+ ctxt . scatterGLHasInitialized = true ;
221254 }
222255}
0 commit comments