canvas 实现目标轨迹框叠加
事先准备视频片段和算法生成视频帧数据json:
{
"algorithm_frame_size": {
"width": 1280,
"height": 720
},
"venc_fps": 25,
"Floor": [
{
"beg_x": 0,
"beg_y": 648,
"end_x": 1280,
"end_y": 648,
"name": "1层"
},
{
"beg_x": 0,
"beg_y": 360,
"end_x": 1280,
"end_y": 360,
"name": "5层"
},
{
"beg_x": 0,
"beg_y": 216,
"end_x": 1280,
"end_y": 216,
"name": "12层"
},
{
"beg_x": 0,
"beg_y": 144,
"end_x": 1280,
"end_y": 144,
"name": "20层"
}
],
"track": [
{
"x": 477,
"y": 369,
"width": 4,
"height": 5,
"pts": 777885979341
},
{
"x": 477,
"y": 369,
"width": 4,
"height": 5,
"pts": 777886059297
},
{
"x": 470,
"y": 402,
"width": 5,
"height": 6,
"pts": 777886179311
},
{
"x": 464,
"y": 430,
"width": 5,
"height": 6,
"pts": 777886259319
},
{
"x": 460,
"y": 449,
"width": 5,
"height": 6,
"pts": 777886339326
},
{
"x": 455,
"y": 469,
"width": 5,
"height": 7,
"pts": 777886419514
},
{
"x": 450,
"y": 490,
"width": 6,
"height": 7,
"pts": 777886499365
},
{
"x": 446,
"y": 512,
"width": 6,
"height": 6,
"pts": 777886579313
},
{
"x": 442,
"y": 534,
"width": 5,
"height": 6,
"pts": 777886659376
},
{
"x": 437,
"y": 557,
"width": 6,
"height": 5,
"pts": 777886739292
}
],
"Info": [
{
"channel": 100,
"frame_pts": 777883306220,
"pts_sys": 777882848707,
"size": 160759,
"width": 1280,
"height": 720,
"format": 96,
"frame_type": 0,
"offset": 0
},
{
"channel": 100,
"frame_pts": 777883346220,
"pts_sys": 777882888131,
"size": 3179,
"width": 1280,
"height": 720,
"format": 96,
"frame_type": 1,
"offset": 160759
},
{
"channel": 100,
"frame_pts": 777883386221,
"pts_sys": 777882928976,
"size": 3309,
"width": 1280,
"height": 720,
"format": 96,
"frame_type": 1,
"offset": 163938
},
{
"channel": 100,
"frame_pts": 777883426228,
"pts_sys": 777882968472,
"size": 3336,
"width": 1280,
"height": 720,
"format": 96,
"frame_type": 1,
"offset": 167247
},
{
"channel": 100,
"frame_pts": 777883466222,
"pts_sys": 777883008653,
"size": 4023,
"width": 1280,
"height": 720,
"format": 96,
"frame_type": 1,
"offset": 170583
},
{
"channel": 100,
"frame_pts": 777883506221,
"pts_sys": 777883048183,
"size": 4254,
"width": 1280,
"height": 720,
"format": 96,
"frame_type": 1,
"offset": 174606
},
{
"channel": 100,
"frame_pts": 777883546220,
"pts_sys": 777883088177,
"size": 3814,
"width": 1280,
"height": 720,
"format": 96,
"frame_type": 1,
"offset": 178860
},
{
"channel": 100,
"frame_pts": 777883586220,
"pts_sys": 777883128164,
"size": 3648,
"width": 1280,
"height": 720,
"format": 96,
"frame_type": 1,
"offset": 182674
},
{
"channel": 100,
"frame_pts": 777883626219,
"pts_sys": 777883168261,
"size": 3723,
"width": 1280,
"height": 720,
"format": 96,
"frame_type": 1,
"offset": 186322
},
{
"channel": 100,
"frame_pts": 777883666224,
"pts_sys": 777883208298,
"size": 3594,
"width": 1280,
"height": 720,
"format": 96,
"frame_type": 1,
"offset": 190045
}
]
}
增加画布,在视频播放时实时进行目标轨迹框叠加:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="js/VideoFrame.min.js"></script>
<script src="js/jquery.2.2.4.min.js"></script>
<style type="text/css">
.tanchuang{
width: 960px;
height: 540px;
margin: 50px auto;
position: relative;
}
.videoCss{
position: absolute;
top: 0;
left: 0;
z-index: 9999;
}
#canvas{
position: absolute;
top: 0;
left: 0;
z-index: 99999;
}
</style>
</head>
<body>
<div class="frame">
<span id="currentFrame">0</span>
</div>
<div class="tanchuang">
<video width="960" height="540" controls="controls" autoplay="autoplay" id="video">
<source src="" type="video/mp4" id="sourceId"></source>
</video>
<canvas id="canvas" width="960" height="500"></canvas>
</div>
</body>
<script type="text/javascript">
//json文件里边的数据
var datajson = {};
var frameRate = 25;
$.ajax({
url : "alarm/queryJsonData",
method : 'POST',
success : function(data) {
datajson = data;
frameRate = datajson.venc_fps;
},
error : function(err) {
console.log("err:" + err);
}
});
var currentFrame = $('#currentFrame');
var videoFrame = {};
videoFrame.id = "video";
videoFrame.frameRate = frameRate;
videoFrame.callback = function dataDeal(frame) {
drawIt(frame, datajson);
// 帧数
currentFrame.html(frame);
};
var video = VideoFrame(videoFrame);
function ChangeButtonText() {
if (video.video.paused) {
video.listen('frame');
} else {
video.video.pause();
video.stopListen();
}
}
ChangeButtonText();
function drawIt(frame,datajson) {
var can = document.getElementById("canvas");//获得画板数据
var con = can.getContext('2d');//获得笔刷
// 清除画布上一帧的数据
con.clearRect(0,0,960,500);
/*
* context.rect(x, y, w, h) - 以路径的方式绘制一个矩形
* x - 矩形左上角的 x 坐标
* y - 矩形左上角的 y 坐标
* w - 矩形的宽
* h - 矩形的高
*/
var imageWidth = datajson.algorithm_frame_size.width
var imageHeight = datajson.algorithm_frame_size.height;
var width = document.getElementById("video").width;
var height = document.getElementById("video").height;
var InfoData = datajson.Info;
// 目标轨迹叠加
if (InfoData.length > 0){
var pts_sys = InfoData[frame].pts_sys;
var trackData = datajson.track;
for (var i=0;i<trackData.length;i++){
var track = trackData[i];
var pts = track.pts;
if (pts < pts_sys){
var x = Math.round(track.x * width / imageWidth);
var y = Math.round(track.y * height / imageHeight);
con.beginPath();
con.strokeStyle = "red";
// 第一个抛点框
if (i == 0){
con.lineWidth = 4;
con.rect(x, y, 32, 32);
}else{
con.lineWidth = 2;
con.rect(x, y, 16, 16);
}
con.stroke();
}
}
}
// 楼层数据添加
var floorData = datajson.Floor;
if (floorData != undefined){
for (var i=0;i<floorData.length;i++){
var floor = floorData[i];
var startX = Math.round(floor.beg_x * width / imageWidth);
var startY = Math.round(floor.beg_y * height / imageHeight);
var endX = Math.round(floor.end_x * width / imageWidth);
var endY = Math.round(floor.end_y * height / imageHeight);
// 画线
con.beginPath();
con.lineWidth = 1;
con.strokeStyle = "#00FF00";
con.moveTo(startX,startY);
con.lineTo(endX,endY);
// 添加字幕
var name = floor.name;
// 设置字体
con.font = "20px bold 微软雅黑";
// 设置颜色
con.fillStyle = "#00FF00";
// 设置水平对齐方式
con.textAlign = "center";
con.fillText(name,endX - 30,endY - 5);
con.stroke();
}
}
}
document.getElementById("video").src = "alarm/alarmVideoOSD";
</script>
</html>
生成效果图: