node-red-node-rdk-tools
Version:
配合RDK硬件及TROS使用的Node-RED功能包(Node-RED nodes for using TROS on a RDK hardware and TROS)
613 lines (563 loc) • 20.7 kB
JavaScript
// 'use strict';
let FPS = 30;
let timeout;
let frames = [];
let videos = [];
let AwesomeMessage = null;
let messageShowSelect = {};
let socketParameters = getURLParameter();
let pathNum = getVideoNum();
let pathNumArr = [...new Array(pathNum).keys()];
function fullFloatMatrix(width, height) {
let widths = [...new Array(width).keys()];
let heights = [...new Array(height).keys()];
let FullFloatMatrix = []
widths.map(() => {
heights.map(() => {
FullFloatMatrix.push(255, 255, 255, 255)
})
})
return FullFloatMatrix;
}
function getVideoNum() {
let num = 1;
let obj = {};
const cookies = document.cookie.split('; ');
cookies.map(item => {
let arr = item.split('=');
obj[arr[0]] = arr[1] * 1;
})
if (typeof obj.path_num !== 'undefined') {
num = obj.path_num;
}
return num;
}
function createVideo() {
let w = 100;
let h = 100;
let names = 'video';
if (pathNum === 2) {
w /= 2;
names = 'video two';
}
if (pathNum === 3 || pathNum === 4) {
w /= 2;
h /= 2;
names = 'video four';
}
if (pathNum === 5 || pathNum === 6) {
w /= 3;
h /= 2;
names = 'video six';
}
if (pathNum === 7 || pathNum === 8) {
w /= 3;
h /= 3;
names = 'video eight';
}
const videocontHtml = document.getElementById('wrapper-cnt');
const performanceHtml = document.getElementById('performance-message');
// <img class="logo1" src="../assets/images/usbcam-top.png" alt="">
pathNumArr.map(i => {
const port = 8080 + i * 2;
const str = `
<div class="${names}" id="video-wrap-${port}" style="width: ${w}%; height: ${h}%;">
<div class="cont">
<div class="cam" id="cam">
<img class="logo2" src="../assets/images/aionhorizon.png" alt="">
<img src="" class="layer" id="video-${port}" alt="">
<canvas class="canvas" id="canvas-${port}-1"></canvas>
<canvas class="canvas" id="canvas-${port}-2"></canvas>
<ul class="canvas info-panel-1" id="info-panel-${port}-1">
</ul>
<ul class="canvas info-panel-2" id="info-panel-${port}-2">
</ul>
</div>
</div>
</div>
`;
const str2 = `<li id="performance-${port}"></li>`
videocontHtml.innerHTML += str;
performanceHtml.innerHTML += str2;
})
}
function getURLParameter() {
let socketIP = '';
let port = '';
let netId = '';
let cameraId = '';
let id = '';
let doc_socketIP = '';
let doc_port = '';
let cam_id = '';
return {
socketIP,
port,
netId,
cameraId,
id,
doc_socketIP,
doc_port,
cam_id
}
}
function changeCheckboxSelect() {
const performanceHtml = document.getElementById('performance');
const messageShows = Array.from(document.querySelectorAll('.message-show'));
messageShows.forEach(item => {
messageShowSelect[item.getAttribute('dataType')] = item.checked;
item.onclick = () => {
messageShowSelect[item.getAttribute('dataType')] = item.checked;
performanceHtml.style.display = messageShowSelect.performance ? 'block' : 'none';
}
})
}
function changeCheckboxShow() {
let messageChangeV = document.querySelector('.message-v');
let messageChangeH = document.querySelector('.message-h');
let messageDiv = document.getElementById('message');
messageChangeH.onclick = function () {
messageDiv.style.display = 'block';
this.style.display = 'none';
messageChangeV.style.display = 'block';
}
messageChangeV.onclick = function () {
messageDiv.style.display = 'none';
this.style.display = 'none';
messageChangeH.style.display = 'block';
}
}
function protobufInit() {
protobuf.load('../../protos/x3.proto', function (err, root) {
if (err) throw err;
AwesomeMessage = root.lookupType('x3.FrameMessage');
});
}
function multipathInit() {
pathNumArr.map(i => {
const port = 8080 + 2 * i;
videos[i] = new RenderFrame(
{ canvasId: `canvas-${port}-1` },
{ canvasId: `canvas-${port}-2` },
`info-panel-${port}-1`,
`info-panel-${port}-2`,
`video-${port}`,
`performance-${port}`
);
wsInit(i, port);
})
pathNumArr = null;
}
function wsInit(i, port) {
let { socketIP, cameraId, id, netId } = socketParameters;
// 部署
hostport = document.location.hostname;
socketIP = hostport.replace(/_/g, '.');
socket = new ReconnectingWebSocket(`ws://${socketIP}:${port}`, null, { binaryType: 'arraybuffer' });
// 本地开发用
// let ip = '10.64.35.196'
// let socket = new ReconnectingWebSocket(`ws://${ip}:${port}`, null, { binaryType: 'arraybuffer' });
socket.onopen = function (e) {
if (e.type === 'open') {
let data = { filter_prefix: netId + '/' + cameraId + '/' + id };
socket.send(JSON.stringify(data));
console.log('opened');
}
};
socket.onclose = function (e) {
if (socket) {
console.log(`close:${socket.url} `, e);
socket.close();
}
};
socket.onerror = function (e) {
if (socket) {
console.log(`error:${socket.url} `, e);
}
};
socket.onmessage = function (e) {
// console.log(e)
if (e.data) {
frames[i] = transformData(e.data);
}
delete e;
};
clearTimeout(timeout);
sendMessage();
}
function sendMessage() {
videos.map((item, index) => {
if (item && frames[index]) {
item.render(frames[index]);
frames[index] = null;
}
})
timeout = setTimeout(() => {
sendMessage();
}, 1000 / FPS);
}
function transformData(buffer, AwesomeMessage) {
messageShowSelect.boxes = true;
messageShowSelect.floatMatrixsMatting = true;
messageShowSelect.scoreShow = true;
messageShowSelect.handBox = true;
messageShowSelect.body = true;
messageShowSelect.face = true;
messageShowSelect.handMarks = true;
messageShowSelect.attributes = true;
messageShowSelect.floatMatrixsMatting = true;
// console.time('渲染计时器')
// console.time('解析计时器')
let unit8Array = new Uint8Array(buffer);
// console.log(222, unit8Array)
let message = AwesomeMessage.decode(unit8Array);
let object = AwesomeMessage.toObject(message);
// console.log(333, object);
let imageBlob;
let imageWidth = 1920;
let imageHeight = 1080;
let performance = [];
let smartMsgData = [];
if (object) {
// 性能数据
if (object['StatisticsMsg_'] &&
object['StatisticsMsg_']['attributes_'] &&
object['StatisticsMsg_']['attributes_'].length
) {
performance = object['StatisticsMsg_']['attributes_']
}
// 图片
if (object['img_'] &&
object['img_']['buf_'] &&
object['img_']['buf_'].length
) {
imageBlob = new Blob([object['img_']['buf_']], { type: 'image/jpeg' });
imageWidth = object['img_']['width_'] || 1920
imageHeight = object['img_']['height_'] || 1080
}
// 智能数据
if (object['smartMsg_'] &&
object['smartMsg_']['targets_'] &&
object['smartMsg_']['targets_'].length
) {
let FullFloatMatrix = null;
if (messageShowSelect.floatMatrixsMatting) {
FullFloatMatrix = fullFloatMatrix(imageWidth, imageHeight);
}
object['smartMsg_']['targets_'].map(item => {
if (item) {
let obj = {
id: messageShowSelect.trackId ? item['trackId_'] : undefined,
boxes: [],
attributes: { attributes: [], type: item['type_'] },
fall: { fallShow: false },
points: [],
segmentation: [],
}
let labelStart = 0;
let labelCount = 20;
let labelBodyBox = null;
let k = 0;
// 检测框
if (messageShowSelect.boxes && item['boxes_'] && item['boxes_'].length ) {
item['boxes_'].map((val, ind) => {
let boxs = transformBoxes(val)
if (boxs) {
obj.boxes.push({ type: val['type_'] || '', p1: boxs.box1, p2: boxs.box2 });
if (ind === 0) {
obj.attributes.box = { p1: boxs.box1, p2: boxs.box2 }
obj.fall.box = { p1: boxs.box1, p2: boxs.box2 }
}
if (val['type_'] === 'body') {
labelBodyBox = boxs
}
boxs = null;
}
if (messageShowSelect.scoreShow && ind === 0) {
obj.attributes.score = val.score
}
})
obj.boxes = !messageShowSelect.handBox && obj.boxes.length ? obj.boxes.filter(item => item.type !== 'hand') : obj.boxes
}
// 关节点
if (item['points_'] && item['points_'].length ) {
item['points_'].map(val => {
if (val['points_'] && val['points_'].length) {
let bodyType = messageShowSelect.body ? '' : 'body_landmarks'
let faceType = messageShowSelect.face ? '' : 'face_landmarks'
if (val['type_'] === 'mask') {
// 目标分割
if (messageShowSelect.floatMatrixsMask) {
obj.segmentation.push({ type: 'target_img', data: val['points_'] })
}
} else if (val['type_'] === 'hand_landmarks') {
if (messageShowSelect.handMarks) {
obj.points.push({ type: val['type_'], skeletonPoints: transformPoints(val['points_'])})
}
} else if (val['type_'] === 'corner') {
if (messageShowSelect.corner) {
obj.points.push({ type: val['type_'], skeletonPoints: transformPoints(val['points_'])})
}
} else if (val['type_'] === 'lmk_106pts') {
if (messageShowSelect.face) {
obj.points.push({ type: val['type_'], skeletonPoints: transformPoints(val['points_']), diameterSize: 2 })
}
} else if (val['type_'] === 'parking') {
if (messageShowSelect.boxes) {
obj.points.push({ type: val['type_'], skeletonPoints: transformPoints(val['points_'])})
}
} else if (val['type_'] !== bodyType && val['type_'] !== faceType) {
let skeletonPoints = [];
val['points_'].map((val, index) => {
let key = Config.skeletonKey[index];
skeletonPoints[key] = {
x: val['x_'],
y: val['y_'],
score: val['score_'] || 0
};
});
obj.points.push({ type: val['type_'], skeletonPoints })
}
}
})
}
// 属性
if (item['attributes_'] && item['attributes_'].length) {
item['attributes_'].map(val => {
// 分割的颜色参数
labelStart = val['type_'] === "segmentation_label_start" ? val['value_'] : 0
labelCount = val['type_'] === "segmentation_label_count" ? val['value_'] : 20
// 分割的系数
k = val['type_'] === 'expansion_ratio' && val['value_'] ? val['value_'] : 0
// 摔倒
if (val['type_'] === 'fall' && val['value_'] === 1) {
obj.fall.fallShow = true;
obj.fall.attributes = {
type: val['type_'],
value: val['value_'],
score: messageShowSelect.scoreShow ? val['score_'] : undefined
};
} else if (messageShowSelect.attributes && val['valueString_']) {
obj.attributes.attributes.push({
type: val['type_'],
value: val['valueString_'],
score: messageShowSelect.scoreShow ? val['score_'] : undefined
})
}
})
}
// 车
if (item['subTargets_'] && item['subTargets_'].length) {
item['subTargets_'].map(val => {
if (messageShowSelect.boxes && val['boxes_'] && val['boxes_'].length) {
let boxs = transformBoxes(val['boxes_'][0])
if (boxs) {
obj.boxes.push({ p1: boxs.box1, p2: boxs.box2 })
boxs = null;
}
}
// 车牌框数据
if (messageShowSelect.attributes && val['attributes_'] && val['attributes_'].length) {
val['attributes_'].map(v => {
if (v['valueString_']) {
obj.attributes.attributes.push({
type: v['type_'],
value: v['valueString_'],
score: messageShowSelect.scoreShow ? v['score_'] : undefined
})
}
})
}
})
}
// 全图分割 segmentation
if ( item['floatMatrixs_'] && item['floatMatrixs_'].length ) {
let floatType = item['floatMatrixs_'][0]['type_']
if (floatType === 'segmentation' && messageShowSelect.floatMatrixs) {
let color = [];
let step = 255 * 3 / labelCount;
for (let i = 0; i < labelCount; ++i) {
let R = (labelStart / 3 * 3) % 256;
let G = (labelStart / 3 * 2) % 256;
let B = (labelStart / 3) % 256;
color.push([R, G, B]);
labelStart += step;
}
if (color.length) {
let floatdata = []
item['floatMatrixs_'][0]['arrays_'].map(values => {
values['value_'].map(index => {
let colors = color[Math.trunc(index)]
floatdata.push(colors[0], colors[1], colors[2], 155)
})
})
obj.segmentation.push({
type: 'full_img',
w: item['floatMatrixs_'][0]['arrays_'][0]['value_'].length,
h: item['floatMatrixs_'][0]['arrays_'].length,
data: floatdata
})
}
} else { // 抠图分割
if (messageShowSelect.floatMatrixsMatting && labelBodyBox && FullFloatMatrix) {
let labelWidth = labelBodyBox.box2.x - labelBodyBox.box1.x;
let labelHeight = labelBodyBox.box2.y - labelBodyBox.box1.y;
if (floatType === 'matting') {
let dataWidth = Math.trunc(item['floatMatrixs_'][0]['arrays_'][0]['value_'].length * labelWidth / 224)
let dataHeight = Math.trunc(item['floatMatrixs_'][0]['arrays_'].length * labelHeight / 224)
let datas = scaleData(dataWidth, dataHeight, item['floatMatrixs_'][0]['arrays_']);
datas.map((values, i) => {
values['value_'].map((valuess, j) => {
if (valuess > 0) {
let x = (j - labelWidth / 224 * 16) + labelBodyBox.box1.x;
let y = (i - labelHeight / 224 * 16) + labelBodyBox.box1.y;
let index = Math.trunc(y) * 1920 * 4 + Math.trunc(x) * 4 + 3;
FullFloatMatrix[index] = 255 - valuess;
}
})
})
obj.segmentation.push({ type: 'full_img', w: imageWidth, h: imageHeight, data: FullFloatMatrix })
}
}
}
}
// matting_trimapfree抠图分割
if ( item['imgs_'] && item['imgs_'].length ) {
let floatType = item['imgs_'][0]['type_']
if (messageShowSelect.floatMatrixsMatting && labelBodyBox && FullFloatMatrix) {
let labelWidth = labelBodyBox.box2.x - labelBodyBox.box1.x;
let labelHeight = labelBodyBox.box2.y - labelBodyBox.box1.y;
if (floatType === 'matting_trimapfree' && k >= 0){
// 计算出状态 3
let expand_roi_x1 = labelBodyBox.box1.x - labelWidth * k;
let expand_roi_y1 = labelBodyBox.box1.y - labelHeight * k;
let expand_roi_height = Math.trunc(labelHeight + 2 * labelHeight * k);
let expand_roi_width = Math.trunc(labelWidth + 2 * labelWidth * k);
// 计算出状态 2 的缩放系数
let ratio = 0;
let ratio1 = item['imgs_'][0]['height_'] * 1.0 / expand_roi_height;
let ratio2 = item['imgs_'][0]['width_'] * 1.0 / expand_roi_width;
if (ratio1 > ratio2) {
ratio = ratio2;
} else {
ratio = ratio1;
}
// 计算出状态 2 的框
let resize_roi_height = Math.trunc(expand_roi_height * ratio);
let resize_roi_width = Math.trunc(expand_roi_width * ratio);
// 创建一个 resize_matting[resize_roi_height][resize_roi_width] 的数组,
// 并将抠图结果映射到状态 2 的框即 resize_matting 数组
let arrHeight = [...new Array(resize_roi_height).keys()];
let arrWidth = [...new Array(resize_roi_width).keys()];
let resize_matting = arrHeight.map((values) => {
return {
value_: arrWidth.map(valuess => {
return item['imgs_'][0]['buf_'][values * item['imgs_'][0]['width_'] + valuess];
})
}
});
// 二插值计算出状态 1
let expand_matting = scaleData(expand_roi_width, expand_roi_height, resize_matting);
// 渲染到 原图
expand_matting.map((values, i) => {
values['value_'].map((valuess, j) => {
let row = i + expand_roi_y1;
let col = j + expand_roi_x1;
if (valuess > 0 && row >= 0 && col >= 0 && row < 1080 && col < 1980) {
valuess = valuess * 4;
if (valuess > 255) {
valuess = 255;
}
let temp = 255 - valuess;
let index = Math.trunc(row) * 1920 * 4 + Math.trunc(col) * 4 + 3;
FullFloatMatrix[index] = Math.min(FullFloatMatrix[index], temp);
}
})
})
obj.segmentation.push({ type: 'full_img', w: imageWidth, h: imageHeight, data: FullFloatMatrix })
}
}
}
smartMsgData.push(obj);
obj = null;
}
return null;
})
}
}
// console.timeEnd('解析计时器')
return {
imageBlob,
imageWidth,
imageHeight,
performance,
smartMsgData
};
};
function transformBoxes(box) {
if (box &&
box['topLeft_']['x_'] &&
box['topLeft_']['y_'] &&
box['bottomRight_']['x_'] &&
box['bottomRight_']['y_']
) {
let box1 = {
x: box['topLeft_']['x_'],
y: box['topLeft_']['y_']
};
let box2 = {
x: box['bottomRight_']['x_'],
y: box['bottomRight_']['y_']
};
return { box1, box2 };
}
};
function transformPoints(points) {
let skeletonPoints = [];
points.map((val) => {
skeletonPoints.push({
x: val['x_'],
y: val['y_'],
score: val['score_'] || 0
});
});
return skeletonPoints;
};
function scaleData(w, h, data) {
let resData = new Array(h);
for (let j = 0; j < h; j++) {
let line = new Array(w);
for (let i = 0; i < w; i++) {
let v = bilinearInter(w, h, i, j, data);
line[i] = Math.round(v);
}
resData[j] = { value_: line };
}
return resData;
}
function bilinearInter(sw, sh, x_, y_, data) {
let w = data[0]['value_'].length;
let h = data.length;
let x = (x_ + 0.5) * w / sw - 0.5;
let y = (y_ + 0.5) * h / sh - 0.5;
let x1 = Math.floor(x);
let x2 = Math.floor(x + 0.5);
let y1 = Math.floor(y);
let y2 = Math.floor(y + 0.5);
x1 = x1 < 0 ? 0 : x1;
y1 = y1 < 0 ? 0 : y1;
x1 = x1 < w - 1 ? x1 : w - 1;
y1 = y1 < h - 1 ? y1 : h - 1;
x2 = x2 < w - 1 ? x2 : w - 1;
y2 = y2 < h - 1 ? y2 : h - 1;
let f11 = data[y1]['value_'][x1];
let f21 = data[y1]['value_'][x2];
let f12 = data[y2]['value_'][x1];
let f22 = data[y2]['value_'][x2];
let xm = x - x1;
let ym = y - y1;
let r1 = (1 - xm) * f11 + xm * f21;
let r2 = (1 - xm) * f12 + xm * f22;
let value = (1-ym) * r1 + ym * r2;
return value;
}