426 lines
9.9 KiB
JavaScript
426 lines
9.9 KiB
JavaScript
const utils = require("../../utils/utils");
|
||
const CameraDevice = require("../utils/camera-device");
|
||
const module = require("../index.js");
|
||
|
||
const AiSports = requirePlugin("aiSport");
|
||
const PoseGraphs = AiSports.PoseGraphs;
|
||
const humanDetection = AiSports.humanDetection;
|
||
|
||
Component({
|
||
options: {
|
||
styleIsolation: 'shared'
|
||
},
|
||
properties: {
|
||
/**
|
||
* 是否启用全屏模式,true-是,全屏模式;false-否,自适应模式;
|
||
* 【全屏模式】: 检测组件大小为100vw 100vh;同时建议开启页面pageOrientation为自适应,navigationStyle为custom
|
||
*/
|
||
fullScreen: {
|
||
type: Boolean,
|
||
value: false
|
||
},
|
||
topp: {
|
||
type: Number,
|
||
value: 100
|
||
},
|
||
/**
|
||
* 是否开启骨骼图绘制,
|
||
* 此值最好不要动态改变
|
||
*/
|
||
poseDrawEnabled: {
|
||
type: Boolean,
|
||
value: false
|
||
},
|
||
/**
|
||
* 识别引擎选择
|
||
* 1-ve1识别引擎
|
||
* 2-ve2识别引擎
|
||
*/
|
||
ve: {
|
||
type: Number,
|
||
value: null
|
||
},
|
||
/**
|
||
* 是否启用VE1增强模式
|
||
* true-是; false-否 null-自动
|
||
*/
|
||
enhanced: {
|
||
type: Boolean,
|
||
value: null
|
||
},
|
||
/**
|
||
* 是否显示扩展信息
|
||
*/
|
||
extendInfo: {
|
||
type: Boolean,
|
||
value: true
|
||
}
|
||
},
|
||
data: {
|
||
zoom: 1,
|
||
deviceKey: "back",
|
||
previewWidth: 480,
|
||
previewHeight: 640,
|
||
status: 'unknown',
|
||
fps: 0,
|
||
poseFps: 0,
|
||
isHumanBody: false,
|
||
previewRate: 1,
|
||
previewOffsetX: 0,
|
||
previewOffsetY: 0,
|
||
frameWidth: 480,
|
||
frameHeight: 640,
|
||
videoStyle: 'width:100vw;height:100vh'
|
||
},
|
||
lifetimes: {
|
||
attached() {
|
||
this.autoFitPreview(480, 640);
|
||
this.initializeHumanDetection();
|
||
},
|
||
detached() {
|
||
if (!this.camera)
|
||
return;
|
||
|
||
this.camera.stop();
|
||
this.camera.dispose();
|
||
}
|
||
},
|
||
observers: {
|
||
'fullScreen, previewWidth, previewHeight': function () {
|
||
this.updateVideoStyle();
|
||
},
|
||
'poseDrawEnabled': function (val) {
|
||
this.initCanvas();
|
||
},
|
||
've, enhanced': function (ve, enhanced) {
|
||
this.stopCapture();
|
||
this.initializeHumanDetection();
|
||
}
|
||
},
|
||
methods: {
|
||
updateVideoStyle() {
|
||
const style = this.data.fullScreen ?
|
||
'width:100vw;height:100vh' :
|
||
`width:${this.data.previewWidth}px;height:${this.data.previewHeight}px;`;
|
||
this.setData({
|
||
videoStyle: style
|
||
});
|
||
},
|
||
|
||
openCameraAuth() {
|
||
const that = this;
|
||
wx.showModal({
|
||
content: '您未打开摄像头权限,无法使用本功能。',
|
||
confirmText: '去打开',
|
||
success(res) {
|
||
if (!res.confirm) {
|
||
wx.showToast({
|
||
icon: 'none',
|
||
title: '无法使用本功能。'
|
||
});
|
||
return;
|
||
}
|
||
|
||
wx.openSetting({
|
||
success(res) {
|
||
if (res.authSetting['scope.camera'] != true) {
|
||
that.openCameraAuth();
|
||
return;
|
||
}
|
||
|
||
wx.showToast({
|
||
icon: 'none',
|
||
title: '摄像头权限已打开,稍后请重新进入本页。'
|
||
});
|
||
setTimeout(() => wx.navigateBack(), 1500);
|
||
}
|
||
});
|
||
}
|
||
});
|
||
},
|
||
|
||
initializeHumanDetection() {
|
||
wx.showLoading({
|
||
title: '加载中...'
|
||
});
|
||
|
||
const ehd = module.judgeEnhanced(this.data.enhanced);
|
||
const that = this;
|
||
humanDetection.initialize({
|
||
ve: that.data.ve,
|
||
enhanced: ehd,
|
||
callback: (err) => {
|
||
wx.hideLoading();
|
||
if (!err)
|
||
return;
|
||
|
||
wx.showModal({
|
||
content: `初始化失败,详细信息:${err.message}`,
|
||
showCancel: false
|
||
});
|
||
}
|
||
});
|
||
},
|
||
|
||
fullScreenFit(width, height) {
|
||
const winfo = wx.getWindowInfo();
|
||
|
||
this.setData({
|
||
previewWidth: winfo.windowWidth,
|
||
previewHeight: winfo.windowHeight
|
||
});
|
||
|
||
if (winfo.windowHeight > winfo.windowWidth) {
|
||
// 竖屏模式
|
||
console.log('竖屏');
|
||
const previewRate = winfo.windowHeight / height;
|
||
const previewOffsetX = (winfo.windowWidth - width * previewRate) / 2;
|
||
|
||
this.setData({
|
||
previewRate: previewRate,
|
||
previewOffsetX: previewOffsetX,
|
||
previewOffsetY: 0
|
||
});
|
||
} else {
|
||
// 横屏模式
|
||
console.log('横屏');
|
||
const previewRate = winfo.windowWidth / width;
|
||
const previewOffsetY = (winfo.windowHeight - height * previewRate) / 2;
|
||
|
||
this.setData({
|
||
previewRate: previewRate,
|
||
previewOffsetX: 0,
|
||
previewOffsetY: previewOffsetY
|
||
});
|
||
}
|
||
},
|
||
|
||
autoFitPreview(width, height) {
|
||
this.setData({
|
||
frameWidth: width,
|
||
frameHeight: height
|
||
});
|
||
|
||
if (this.data.fullScreen) {
|
||
this.fullScreenFit(width, height);
|
||
return;
|
||
}
|
||
|
||
const winfo = wx.getWindowInfo();
|
||
const rate = winfo.windowWidth / width;
|
||
this.setData({
|
||
previewWidth: width * rate,
|
||
previewHeight: height * rate,
|
||
previewRate: rate,
|
||
previewOffsetX: 0,
|
||
previewOffsetY: 0
|
||
});
|
||
},
|
||
|
||
initCanvas() {
|
||
if (!this.data.poseDrawEnabled)
|
||
return;
|
||
|
||
const that = this;
|
||
const query = wx.createSelectorQuery().in(this);
|
||
|
||
query.select('#graphics')
|
||
.fields({
|
||
node: true,
|
||
size: true
|
||
})
|
||
.exec(res => {
|
||
if (utils.isEmptyArray(res))
|
||
return;
|
||
|
||
const canvas = res[0].node;
|
||
const dpr = wx.getWindowInfo().pixelRatio;
|
||
//res[0].width * dpr; //由于iPhone改变canvas样式后渲染有滞后性,取出的宽、高可能与样式不一致
|
||
canvas.width = that.data.previewWidth * dpr;
|
||
//res[0].height * dpr;
|
||
canvas.height = that.data.previewHeight * dpr;
|
||
|
||
const ctx = canvas.getContext('2d');
|
||
ctx.scale(dpr, dpr);
|
||
|
||
that.canvas = canvas;
|
||
that.ctx = ctx;
|
||
|
||
that.poseGraphs = new PoseGraphs(
|
||
ctx,
|
||
canvas.width,
|
||
canvas.height,
|
||
that.data.previewRate
|
||
);
|
||
|
||
that.poseGraphs.offsetX = that.data.previewOffsetX;
|
||
that.poseGraphs.offsetY = that.data.previewOffsetY;
|
||
|
||
that.poseGraphs.lineColor = "#FF8E148C";
|
||
that.poseGraphs.pointColor = '#00a500';
|
||
that.poseGraphs.leftColor = '#007fd3';
|
||
});
|
||
},
|
||
|
||
async detection(frame) {
|
||
|
||
let ts = (new Date()).getTime();
|
||
const human = await humanDetection.detectionAsync(frame);
|
||
ts = (new Date()).getTime() - ts;
|
||
|
||
this.setData({
|
||
poseFps: Math.floor(1000 / ts)
|
||
});
|
||
|
||
if (human) {
|
||
this.setData({
|
||
isHumanBody: true
|
||
});
|
||
this.triggerEvent('on-human-detecting', {
|
||
human: human,
|
||
frame: frame
|
||
});
|
||
} else {
|
||
this.setData({
|
||
isHumanBody: false
|
||
});
|
||
this.triggerEvent('on-human-detecting', {
|
||
human: null
|
||
});
|
||
}
|
||
|
||
if (!this.data.poseDrawEnabled)
|
||
return;
|
||
|
||
//无结果
|
||
if (!human)
|
||
this.poseGraphs.clear();
|
||
else
|
||
this.poseGraphs.drawing(human.keypoints);
|
||
},
|
||
|
||
initVideo() {
|
||
if (this.camera)
|
||
return;
|
||
|
||
const that = this;
|
||
this.camera = new CameraDevice();
|
||
this.camera.onFrame = frame => {
|
||
that.setData({
|
||
fps: that.camera.fps
|
||
});
|
||
|
||
//重新适应
|
||
if (frame.width != that.data.frameWidth || frame.height != that.data.frameHeight) {
|
||
that.camera.stop(true);
|
||
that.autoFitPreview(frame.width, frame.height);
|
||
that.initCanvas();
|
||
that.camera.start();
|
||
return;
|
||
}
|
||
|
||
try {
|
||
that.detection(frame);
|
||
} catch (err) {
|
||
console.error(err);
|
||
}
|
||
};
|
||
this.camera.onStatusChange = (val, text) => {
|
||
if (val === -1) {
|
||
wx.hideLoading();
|
||
that.setData({
|
||
isHumanBody: false
|
||
});
|
||
}
|
||
that.setData({
|
||
status: text
|
||
})
|
||
that.triggerEvent('on-camera-change', {
|
||
val: val,
|
||
text: text
|
||
})
|
||
};
|
||
},
|
||
startCapture() {
|
||
this.initVideo();
|
||
this.camera.start();
|
||
wx.setKeepScreenOn({
|
||
keepScreenOn: true
|
||
});
|
||
},
|
||
delayStart() {
|
||
if (this.data.camera) {
|
||
const status = this.camera.getStatus();
|
||
if (status != "unknown" && status != "stopped")
|
||
return;
|
||
}
|
||
|
||
//延时5s启动
|
||
const that = this;
|
||
setTimeout(() => that.startCapture(), 5000);
|
||
wx.showToast({
|
||
title: '5S后开始',
|
||
duration: 4900
|
||
});
|
||
},
|
||
stopCapture() {
|
||
if (!this.camera || this.camera.getStatus() != 'running')
|
||
return;
|
||
|
||
this.setData({
|
||
isHumanBody: false
|
||
});
|
||
|
||
if (this.camera)
|
||
this.camera.stop();
|
||
|
||
wx.setKeepScreenOn({
|
||
keepScreenOn: false
|
||
});
|
||
|
||
this.setData({
|
||
fps: this.camera.fps,
|
||
status: this.camera.getStatus()
|
||
});
|
||
|
||
wx.showLoading({
|
||
title: '正在停止...'
|
||
});
|
||
},
|
||
|
||
toggleCamera() {
|
||
this.setData({
|
||
deviceKey: this.data.deviceKey === 'back' ? 'front' : 'back'
|
||
});
|
||
},
|
||
|
||
onCameraReady(e) {
|
||
console.log('相机初始化完成。');
|
||
this.setData({
|
||
zoom: e.detail.maxZoom
|
||
});
|
||
this.initCanvas();
|
||
if (!this.camera)
|
||
return;
|
||
|
||
console.log('重新初始化CameraDevice');
|
||
const status = this.camera.getStatus();
|
||
this.camera.dispose();
|
||
this.camera = null;
|
||
this.initVideo();
|
||
if (status === 'running')
|
||
this.camera.start();
|
||
},
|
||
onCameraError(e) {
|
||
const err = e.detail.errMsg;
|
||
if (err.includes('auth')) {
|
||
this.openCameraAuth();
|
||
return;
|
||
}
|
||
wx.showModal({
|
||
content: err,
|
||
showCancel: false
|
||
});
|
||
}
|
||
}
|
||
}); |