1
|
npm install kinect2
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
var
Kinect2 = require(
'../../lib/kinect2'
),
express = require(
'express'
),
app = express(),
server = require(
'http'
).createServer(app),
io = require(
'socket.io'
).listen(server);
var
kinect =
new
Kinect2();
// 打開kinect
if
(kinect.open()) {
// 監聽8000端口
server.listen(8000);
// 指定請求指向根目錄
app.get(
'/'
,
function
(req, res) {
res.sendFile(__dirname +
'/public/index.html'
);
});
// 將骨骼數據發送給瀏覽器端
kinect.on(
'bodyFrame'
,
function
(bodyFrame){
io.sockets.emit(
'bodyFrame'
, bodyFrame);
});
// 開始讀取骨骼數據
kinect.openBodyReader();
}
|
二、瀏覽器端 瀏覽器端獲取骨骼數據,並用canvas描繪出來,關鍵代碼以下:javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
var
socket = io.connect(
'/'
);
var
ctx = canvas.getContext(
'2d'
);
socket.on(
'bodyFrame'
,
function
(bodyFrame){
ctx.clearRect(0, 0, canvas.width, canvas.height);
var
index = 0;
// 遍歷全部骨骼數據
bodyFrame.bodies.forEach(
function
(body){
if
(body.tracked) {
for
(
var
jointType
in
body.joints) {
var
joint = body.joints[jointType];
ctx.fillStyle = colors[index];
// 若是骨骼節點爲脊椎中點
if
(jointType == 1) {
ctx.fillStyle = colors[2];
}
ctx.fillRect(joint.depthX * 512, joint.depthY * 424, 10, 10);
}
// 識別左右手手勢
updateHandState(body.leftHandState, body.joints[7]);
updateHandState(body.rightHandState, body.joints[11]);
index++;
}
});
});
|
很簡單的幾行代碼,咱們便完成了玩家骨骼捕獲,有必定 javascript基礎的同窗應該很容易能看明白,但不明白的是咱們能獲取哪些數據?如何獲取?骨骼節點名稱分別是什麼?而node-kienct2並無文檔告訴咱們這些。html
1
|
kinect.on(
'bodyFrame'
,
function
(bodyFrame){});
//還有哪些數據類型呢?
|
bodyFrame | 骨骼數據 |
infraredFrame | 紅外數據 |
longExposureInfraredFrame | 相似infraredFrame,貌似精度更高,優化後的數據 |
rawDepthFrame | 未經處理的景深數據 |
depthFrame | 景深數據 |
colorFrame | 彩色圖像 |
multiSourceFrame | 全部數據 |
audio | 音頻數據,未測試 |
1
|
body.joints[11]
// joints包括哪些呢?
|
節點類型 | JointType | 節點名稱 |
0 | spineBase | 脊椎基部 |
1 | spineMid | 脊椎中部 |
2 | neck | 頸部 |
3 | head | 頭部 |
4 | shoulderLeft | 左肩 |
5 | elbowLeft | 左肘 |
6 | wristLeft | 左腕 |
7 | handLeft | 左手掌 |
8 | shoulderRight | 右肩 |
9 | elbowRight | 右肘 |
10 | wristRight | 右腕 |
11 | handRight | 右手掌 |
12 | hipLeft | 左屁 |
13 | kneeLeft | 左膝 |
14 | ankleLeft | 左踝 |
15 | footLeft | 左腳 |
16 | hipRight | 右屁 |
17 | kneeRight | 右膝 |
18 | ankleRight | 右踝 |
19 | footRight | 右腳 |
20 | spineShoulder | 頸下脊椎 |
21 | handTipLeft | 左手指(食中無小) |
22 | thumbLeft | 左拇指 |
23 | handTipRight | 右手指 |
24 | thumbRight | 右拇指 |
0 | unknown | 不能識別 |
1 | notTracked | 未能檢測到 |
2 | open | 手掌 |
3 | closed | 握拳 |
4 | lasso | 剪刀手,併合並中食指 |
on | 監聽數據 |
open | 打開Kinect |
close | 關閉 |
openBodyReader | 讀取骨骼數據 |
open**Reader | 相似如上方法,讀取其它類型數據 |
1.一、經過手勢觸發開始遊戲前端 |
1.二、玩家化身四代,左右跑動躲避九尾攻擊java |
1.三、擺出手勢「奧義」,觸發四代大招node |
1.四、用戶掃描二維碼獲取本身現場照片git |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
var
emitColorFrame =
false
;
io.sockets.on(
'connection'
,
function
(socket){
socket.on(
'startColorFrame'
,
function
(data){
emitColorFrame =
true
;
});
});
kinect.on(
'multiSourceFrame'
,
function
(frame){
// 發送玩家骨骼數據
io.sockets.emit(
'bodyFrame'
, frame.body);
// 玩家拍照
if
(emitColorFrame) {
var
compression = 1;
var
origWidth = 1920;
var
origHeight = 1080;
var
origLength = 4 * origWidth * origHeight;
var
compressedWidth = origWidth / compression;
var
compressedHeight = origHeight / compression;
var
resizedLength = 4 * compressedWidth * compressedHeight;
var
resizedBuffer =
new
Buffer(resizedLength);
// ...
// 照片數據過大,須要壓縮提升傳輸性能
zlib.deflate(resizedBuffer,
function
(err, result){
if
(!err) {
var
buffer = result.toString(
'base64'
);
io.sockets.emit(
'colorFrame'
, buffer);
}
});
emitColorFrame =
false
;
}
});
kinect.openMultiSourceReader({
frameTypes: Kinect2.FrameType.body | Kinect2.FrameType.color
});
|
三、客戶端 客戶端業務邏輯較複雜,咱們提取關鍵步驟進行講解。 3.一、用戶拍照時,因爲處理的數據比較大,爲防止頁面出現卡頓,咱們須要使用web workergithub
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
(
function
(){
importScripts(
'pako.inflate.min.js'
);
var
imageData;
function
init() {
addEventListener(
'message'
,
function
(event) {
switch
(event.data.message) {
case
"setImageData"
:
imageData = event.data.imageData;
break
;
case
"processImageData"
:
processImageData(event.data.imageBuffer);
break
;
}
});
}
function
processImageData(compressedData) {
var
imageBuffer = pako.inflate(atob(compressedData));
var
pixelArray = imageData.data;
var
newPixelData =
new
Uint8Array(imageBuffer);
var
imageDataSize = imageData.data.length;
for
(
var
i = 0; i < imageDataSize; i++) {
imageData.data[i] = newPixelData[i];
}
for
(
var
x = 0; x < 1920; x++) {
for
(
var
y = 0; y < 1080; y++) {
var
idx = (x + y * 1920) * 4;
var
r = imageData.data[idx + 0];
var
g = imageData.data[idx + 1];
var
b = imageData.data[idx + 2];
}
}
self.postMessage({
"message"
:
"imageReady"
,
"imageData"
: imageData });
}
init();
})();
|
3.二、接投影儀後,若是渲染面積比較大,會出現白屏,須要關閉瀏覽器硬件加速。 web
3.三、現場光線較暗,其它玩家干擾,在追蹤玩家運動軌跡的過程當中,可能會出現抖動的狀況,咱們須要去除干擾數據。(當忽然出現很大位移時,須要將數據移除)express
1
2
3
4
5
6
7
8
9
10
|
var
tracks =
this
.tracks;
var
len = tracks.length;
// 數據過濾
if
(tracks[len-1] !== window.undefined) {
if
(Math.abs(n - tracks[len-1]) > 0.2) {
return
;
}
}
this
.tracks.push(n);
|
3.四、當玩家站立,只是左右少許晃動時,咱們認爲玩家是站立狀態。npm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
// 保留5個數據
if
(
this
.tracks.length > 5) {
this
.tracks.shift();
}
else
{
return
;
}
// 位移總量
var
dis = 0;
for
(
var
i = 1; i <
this
.tracks.length; i++) {
dis +=
this
.tracks[i] -
this
.tracks[i-1];
}
if
(Math.abs(dis) < 0.01) {
this
.stand();
}
else
{
if
(
this
.tracks[4] >
this
.tracks[3]) {
this
.turnRight();
}
else
{
this
.turnLeft();
}
this
.run();
}
|