javacv 实现目标轨迹框叠加
程序员文章站
2022-06-28 16:24:57
javacv 实现视频中物体目标坠落轨迹框叠加添加javacv依赖包: org.bytedeco javacv-platform 1.5.2 ...
javacv 实现视频中物体目标坠落轨迹框叠加
添加javacv依赖包:
<!-- Java CV依赖 -->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.2</version>
</dependency>
事先准备要执行叠加的视频和算法生成的视频帧数据 gaopao.json:
{
"track": [
{
"x": 1162,
"y": 338,
"width": 11,
"height": 12,
"pts": 182475634947
},
{
"x": 1161,
"y": 320,
"width": 14,
"height": 14,
"pts": 182475714922
},
{
"x": 1163,
"y": 301,
"width": 12,
"height": 13,
"pts": 182475794909
},
{
"x": 1164,
"y": 287,
"width": 10,
"height": 16,
"pts": 182475874977
},
{
"x": 1165,
"y": 283,
"width": 10,
"height": 11,
"pts": 182475954924
}
],
"Info": [
{
"channel": 100,
"frame_pts": 182473081868,
"pts_sys": 182472626937,
"size": 399091,
"width": 1080,
"height": 1920,
"format": 265,
"frame_type": 0,
"offset": 0
},
{
"channel": 100,
"frame_pts": 182473281868,
"pts_sys": 182472825672,
"size": 95054,
"width": 1080,
"height": 1920,
"format": 265,
"frame_type": 1,
"offset": 399091
},
{
"channel": 100,
"frame_pts": 182473481868,
"pts_sys": 182473025489,
"size": 85004,
"width": 1080,
"height": 1920,
"format": 265,
"frame_type": 1,
"offset": 494145
},
{
"channel": 100,
"frame_pts": 182473681867,
"pts_sys": 182473225433,
"size": 72923,
"width": 1080,
"height": 1920,
"format": 265,
"frame_type": 1,
"offset": 579149
},
{
"channel": 100,
"frame_pts": 182473881868,
"pts_sys": 182473425287,
"size": 78356,
"width": 1080,
"height": 1920,
"format": 265,
"frame_type": 1,
"offset": 652072
}
]
}
Info对象集合是帧数据,帧数都上往下,track对象集合是目标轨迹框坐标,与帧数据是一一对应。
代码执行部分:
package com.demo.common.testall;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.bytedeco.javacv.FrameGrabber.Exception;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import sun.font.FontDesignMetrics;
/**
* @author 作者 weidaoru:
* @version 创建时间:2020年12月30日 下午4:12:44
* 类说明
*/
public class JavaCVTest {
private final static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) throws Exception, org.bytedeco.javacv.FrameRecorder.Exception, InterruptedException, ExecutionException{
// 读取视频帧数相关数据文件
String filePath = "D:\\project\\test\\gaopao.json";
String dataStr = readJsonFile(filePath);
JSONObject dataJson = JSONObject.fromObject(dataStr);
// 设置源视频、目标框叠加的视频文件路径
FFmpegFrameGrabber grabber = FFmpegFrameGrabber.createDefault("D:\\project\\test\\gaopao.mp4");
grabber.start();
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder("D:\\project\\test\\javacv-2.mp4",1920, 1080, 2);
// 视频相关配置,取原视频配置
recorder.setFrameRate(grabber.getFrameRate());
recorder.setVideoCodec(grabber.getVideoCodec());
recorder.setVideoBitrate(grabber.getVideoBitrate());
recorder.start();
Java2DFrameConverter converter = new Java2DFrameConverter();
Frame frame;
System.out.println("视频帧数:" + grabber.getLengthInFrames());
int i = 0;
while ((frame = grabber.grab()) != null) {
// 从视频帧中获取图片
if (frame.image != null) {
BufferedImage bufferedImage = converter.getBufferedImage(frame);
bufferedImage = imageToOSD(bufferedImage,dataJson,i);
// 视频帧赋值,写入输出流
frame.image = converter.getFrame(bufferedImage).image;
recorder.record(frame);
}
i++;
}
grabber.stop();
recorder.stop();
}
private static BufferedImage imageToOSD(BufferedImage bufImg, JSONObject dataJson,int i) {
if (!dataJson.isEmpty()) {
Font font = new Font("微软雅黑", Font.BOLD, 25);
JSONArray infoArray = dataJson.getJSONArray("Info");
JSONArray trackArray = dataJson.getJSONArray("track");
JSONObject info = infoArray.getJSONObject(i);
long pts_sys = info.getLong("pts_sys");
for (int j=0,lens=trackArray.size();j<lens;j++) {
JSONObject track = trackArray.getJSONObject(j);
long pts = track.getLong("pts");
if (pts < pts_sys) {
int x1 = track.getInt("x");
int y1 = track.getInt("y");
int x2 = track.getInt("width");
int y2 = track.getInt("height");
Graphics2D graphics = bufImg.createGraphics();
graphics.setColor(Color.red);
graphics.setFont(font);
// 画矩形框(原点x坐标,原点y坐标,矩形的长,矩形的宽)
graphics.drawRect(x1, y1,x2, y2);
graphics.dispose();
}
}
}
return bufImg;
}
private static String readJsonFile(String filePath) {
String jsonStr = "";
try {
File jsonFile = new File(filePath);
FileReader fileReader = new FileReader(jsonFile);
Reader reader = new InputStreamReader(new FileInputStream(jsonFile),"utf-8");
int ch = 0;
StringBuffer sb = new StringBuffer();
while ((ch = reader.read()) != -1) {
sb.append((char) ch);
}
fileReader.close();
reader.close();
jsonStr = sb.toString();
return jsonStr;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
生成视频效果图:
这和在视频上添加字幕类似
本文地址:https://blog.csdn.net/m0_37715184/article/details/112019916