需求:掃描識別實物,根據實物展示出對應的效果,實際就是一個camera然后弄了點動畫偽裝成掃描,然后截取圖片,傳給后端,后端進行識別。因為是快一年前的項目了 ,有些地方記不太清楚了。
開始是用camera組件takePhoto每500毫秒獲取一次圖片然后發送請求識別圖片發現在 IOS下會有快門聲音
this.cameraCtx.takePhoto({ quality: 'high', success: (res) => { wx.uploadFile({ url: "https://****", method: "post", filePath: res.tempImagePath, name: 'file', header: { "content-type": "multipart/form-data" }, success: (res) => { //..... } }); }, fail: () => { } });
快門聲音是iOS系統的限制,除非用戶靜音,目前沒辦法關閉,於是又換成camera組件onCameraFrame(獲取 Camera 實時幀數據)通過UPNG.js將實時幀數據轉成base64,然后在
通過wx.getFileSystemManager().writeFile()將base64轉成臨時圖片發送給后端進行圖片識別。
快門聲是沒有了,但是轉出來的臨時圖片不夠清晰,影響到識別的准確率,而且好像UPNG.js方法在真機上有些慢具體記不太清了。
import upng from '../../utils/UPNG.js'
this.cameraCtx.onCameraFrame((frame) => { this.transformArrayBufferToBase64(frame); });
//轉化base64編碼格式
transformArrayBufferToBase64: function (frame) {
let base64x = upng.encode([frame.data], frame.width, frame.height, 0)
let base64 = "data:image/png;base64," + wx.arrayBufferToBase64(base64x)
const fsm = wx.getFileSystemManager();
const FILE_BASE_NAME = 'tmp_base64src';
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
if (!format) {
console.log('format')
console.log(base64)
return (new Error('ERROR_BASE64SRC_PARSE'));
}
const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}`;
const buffer = base64x;
const _this = this
fsm.writeFile({
filePath,
data: buffer,
encoding: 'binary',
success() {
wx.uploadFile({
url: "http://192.168.0.117:9000/searchVideo",
method: "post",
filePath: filePath,
name: 'file',
header: {
"content-type": "multipart/form-data"
},
success: (res) => {
},
fail() {
}
});
},
fail() {
return (new Error('ERROR_BASE64SRC_WRITE'));
}
})
},
因為圖片不夠清晰,於是又找到wx.canvasPutImageData畫到canvas上然后用wx.canvasToTempFilePath返回個圖片。(這么做好像是安卓手機上返回的圖片大小有問題,影響到識別的准確率,具體記不太清楚了,反正是安卓有點問題)
<canvas id="tempCanvas" height="{{Height*2}}" width="{{Width*2}}" canvas-id="tempCanvas" style="width:{{Width}}px; height:{{Height}}px"></canvas>
this.cameraCtx.onCameraFrame((frame) => {
this.setData({
Height: frame.height,
Width: frame.width
})
var data = new Uint8Array(frame.data);
var clamped = new Uint8ClampedArray(data);
this.temframe = {};
this.temframe.width = frame.width;
this.temframe.height = frame.height;
this.temframe.data = clamped;
this.transformArrayBuffer();
});
transformArrayBuffer: function () {
var tf = this.temframe; var _this = this; console.log(tf) wx.canvasPutImageData({ canvasId: 'tempCanvas', x: 0, y: 0, width: tf.width, height: tf.height, data: tf.data, success: function (res) { console.log('繪制成功', res) _this.scaning = true; wx.canvasToTempFilePath({ x: 0, y: 0, width: tf.width, height: tf.height, canvasId: 'tempCanvas', fileType: 'jpg', destWidth: tf.width, destHeight: tf.height, // 精度修改 quality: 1, success(res) { console.log(res.tempFilePath) wx.uploadFile({url: "http://192.168.0.128:9000/searchVideo", method: "post", filePath: res.tempFilePath, name: 'file', header: { "content-type": "multipart/form-data" }, success: (res) => { }, fail(res) { } }) }, fail(res) { console.log('console.log(res);', res); setTimeout(() => { _this._takePhoto(); }, 500); } }); }, fail: function (e) { console.log('res', e); setTimeout(() => { _this._takePhoto(); }, 500); } }); },
最后經過思考決定安卓手機用最開始的takePhoto獲取圖片,ios手機用wx.canvasPutImageData畫到canvas的方法,這樣圖片清晰了,快門聲音也沒有了。
<canvas wx:if="{{system=='ios'}}" id="tempCanvas" height="{{Height*2}}" width="{{Width*2}}" canvas-id="tempCanvas" style="width:{{Width}}px; height:{{Height}}px"></canvas>
onLoad: function () { this.setData({ isShow: false }) this.temframe = {}; this.scanOk = false; this.scaning = false; this.cameraCtx = wx.createCameraContext();var _this = this wx.getSystemInfo({ success: function (res) { _this.setData({ pixelRatio: res.pixelRatio }) if (res.platform == "devtools") { _this.setData({ system: 'pc' }) //PC } else if (res.platform == "ios") { _this.setData({ system: 'ios' }) //IOS } else if (res.platform == "android") { _this.setData({ system: 'android' }) } } }) setTimeout(this._takePhoto, 500); this.donghua() },
_takePhoto: function () {
if (this.scanOk || this.scaning) {
return false;
}
// ios和android區分獲取圖片方式
if (this.data.system == 'ios') {
this.setData({
isReuqest: false
});
this.listener = this.cameraCtx.onCameraFrame((frame) => {
if (!this.data.isReuqest) {
this.setData({
Height: frame.height,
Width: frame.width
})
var data = new Uint8Array(frame.data);
var clamped = new Uint8ClampedArray(data);
console.log(frame.width, frame.height, clamped)
this.temframe = {};
this.temframe.width = frame.width;
this.temframe.height = frame.height;
this.temframe.data = clamped;
this.transformArrayBuffer();
}
});
this.listener.start()
} else {
const _this = this
this.cameraCtx.takePhoto({
quality: 'high',
success: (res) => {
const context = wx.createCameraContext();
this.scaning = true;
wx.uploadFile({
url: "http://192.168.0.128:9000/searchVideo",
method: "post",
filePath: res.tempImagePath,
name: 'file',
header: {
"content-type": "multipart/form-data"
},
success: (res) => {
this.scaning = false;
}
});
},
fail: () => {
setTimeout(() => {
this._takePhoto();
}, 500);
}
});
}
},
transformArrayBuffer: function () {
this.setData({
isReuqest: true
});
var tf = this.temframe;
var _this = this;
wx.canvasPutImageData({
canvasId: 'tempCanvas',
x: 0,
y: 0,
width: tf.width,
height: tf.height,
data: tf.data,
success: function (res) {
console.log('繪制成功', res)
_this.scaning = true;
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: tf.width,
height: tf.height,
canvasId: 'tempCanvas',
fileType: 'jpg',
destWidth: tf.width,
destHeight: tf.height,
// 精度修改
quality: 1,
success(res) {
console.log(res.tempFilePath)
wx.uploadFile({
url: "http://192.168.0.128:9000/searchVideo",
method: "post",
filePath: res.tempFilePath,
name: 'file',
header: {
"content-type": "multipart/form-data"
},
success: (res) => {
},
fail(res) {
console.log('fail識別失敗')
}
})
},
fail(res) {
setTimeout(() => {
_this._takePhoto();
}, 500);
}
});
},
fail: function (e) {
console.log('res', e);
setTimeout(() => {
_this._takePhoto();
}, 500);
}
});
},