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 }); } } });