Java原来可以这么玩!CV视频合成处理,视频前后拼接,画面合并

news2024/11/25 9:45:22

前言

本章内容教会你如何用java代码实现 两个视频的画面合并 或者前后拼接。原理是使用了javacv开源jar包,代码经过反复修改,已经实现我能想到的最优最快的实现,如果你有更好更快的实现,欢迎评论区留言!!!

先展示一下效果吧!!!

两个视频前后拼接

两个视频画面合并

JAVACV

简介

JavaCV是一款基于JavaCPP调用方式(JNI的一层封装),由多种开源计算机视觉库组成的包装库,封装了包含FFmpeg、OpenCV、tensorflow、caffe、tesseract、libdc1394、OpenKinect、videoInput和ARToolKitPlus等在内的计算机视觉领域的常用库和实用程序类。

JavaCV基于Apache License Version 2.0协议和GPLv2两种协议,JavaCV支持Windows、Linux、MacOS,Android、IOS在内的Java平台上调用这些接口。

JavaCV是一个基于Java语言的计算机视觉库,它提供了对多种计算机视觉库的接口和包装,使得Java开发者可以方便地使用计算机视觉技术。计算机视觉是人工智能领域的一个重要分支,它涉及到图像处理、视频分析、模式识别、机器学习等多个领域。应用场景需要使用到计算机视觉技术,例如人脸识别、目标检测、物体跟踪、手势识别等等。

JavaCV的特点

  • 跨平台性:JavaCV支持Windows、Linux、MacOS等多个操作系统,同时也支持Android、IOS等移动平台,使得Java开发者可以方便地在不同的平台上使用计算机视觉技术。
  • 丰富的接口和包装:JavaCV提供了对多种计算机视觉库的接口和包装,例如FFmpeg、OpenCV、tensorflow、caffe、tesseract等等。这些库都是计算机视觉领域的常用库和实用程序类,JavaCV的封装使得Java开发者可以方便地使用这些库的功能。
  • 易于使用:JavaCV的使用非常简单,只需要调用相应的接口即可实现相应的功能。同时,JavaCV还提供了丰富的示例代码和文档,方便开发者学习和使用。
  • 灵活扩展:JavaCV的设计非常灵活,可以方便地扩展新的接口和功能。同时,JavaCV还提供了开源的代码库和社区支持,方便开发者进行二次开发和交流。

JavaCV的使用场景

  • 图像处理:JavaCV提供了对图像处理的各种功能,例如图像转换、图像增强、图像分割等等。这些功能可以用于图像处理的各种应用场景,例如人脸识别、目标检测、图像识别等等。
  • 视频分析:JavaCV提供了对视频分析的各种功能,例如视频帧提取、视频流处理、视频目标跟踪等等。这些功能可以用于视频监控、视频分析、视频编辑等等应用场景。
  • 机器学习:JavaCV提供了对机器学习的各种功能,例如特征提取、分类器训练、模型评估等等。这些功能可以用于机器学习应用场景的各种任务,例如图像分类、目标检测、情感分析等等。
  • 3D重建:JavaCV提供了对3D重建的各种功能,例如3D点云处理、3D模型重建等等。这些功能可以用于3D扫描、3D建模、3D打印等等应用场景。
  • 其他应用:除了以上几个应用场景之外,JavaCV还可以用于其他各种计算机视觉应用场景,例如手势识别、物体识别、人脸识别等等。

添加jar依赖

		<!-- https://mvnrepository.com/artifact/org.bytedeco/javacv-platform -->
		<dependency>
			<groupId>org.bytedeco</groupId>
			<artifactId>javacv-platform</artifactId>
			<version>1.5.5</version>
		</dependency>

完整代码展示

核心代码,单类实现,idea等编辑器内创建VideoMergeJoin类,复制粘贴下面代码,右键点击run运行主方法即可。

  • 其中 mergeVideo 方法是将两个帧数相同的的视频合并到一个画面中。
  • 其中 joinVideo 方法 是将两个视频进行前后拼接,第一个参数视频路径,拼接在前,第二个参数视频路径,拼接在后。
  • 修改 VIDEO_PATH1、VIDEO_PATH2 等需要合并和处理的视频文件路径
  • 修改MERGE_PATH、JOIN_PATH 视频合并或者拼接的生成文件路径

import org.bytedeco.javacv.*;
import org.bytedeco.javacv.Frame;

import java.awt.*;
import java.awt.image.BufferedImage;

/**
 * @author tarzan
 */
public class VideoMergeJoin {

    final static String VIDEO_PATH1 = "E:\\test.mp4";
    final static String VIDEO_PATH2 = "E:\\aivideo\\20231217-190828_with_snd.mp4";
    final static String MERGE_PATH= "E:\\test_merge.mp4";
    final static String JOIN_PATH= "E:\\test_join.mp4";

    public static void main(String[] args) throws Exception {
        long start=System.currentTimeMillis();
        mergeVideo(VIDEO_PATH1,VIDEO_PATH2,MERGE_PATH);
        joinVideo(VIDEO_PATH1,VIDEO_PATH2,JOIN_PATH);
        System.out.println("耗时 "+(System.currentTimeMillis()-start)+" ms");
    }

    public static void joinVideo(String videoPath1,String videoPath2, String outPath) throws Exception {
        // 初始化视频源
        FFmpegFrameGrabber grabber1 = new FFmpegFrameGrabber(videoPath1);
        FFmpegFrameGrabber grabber2 = new FFmpegFrameGrabber(videoPath2);
        grabber1.start();
        grabber2.start();
        // 初始化目标视频
        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outPath, grabber1.getImageWidth(), grabber1.getImageHeight(),grabber1.getAudioChannels());
        // 录制视频
        recorder.start();
        while (true){
            Frame frame= grabber1.grab();
            if (frame == null) {
                break;
            }
            recorder.record(frame);
        }
        while (true){
            Frame frame= grabber2.grab();
            if (frame == null) {
                break;
            }
            recorder.record(frame);
        }
        // 释放资源
        grabber1.stop();
        grabber2.stop();
        recorder.stop();
    }

    public static void mergeVideo(String videoPath1,String videoPath2, String outPath) throws Exception {
        // 初始化视频源
        FFmpegFrameGrabber grabber1 = new FFmpegFrameGrabber(videoPath1);
        FFmpegFrameGrabber grabber2 = new FFmpegFrameGrabber(videoPath2);
        grabber1.start();
        grabber2.start();
        // 检查帧率是否一样
        if (grabber1.getFrameRate() != grabber2.getFrameRate()) {
            throw new Exception("Video frame rates are not the same!");
        }
        // 初始化目标视频
        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outPath, (grabber1.getImageWidth()+grabber2.getImageWidth()), grabber1.getImageHeight(),grabber1.getAudioChannels());
        // 录制视频
        recorder.start();
        int i=1;
        int videoSize = grabber1.getLengthInVideoFrames();
        while (true){
            Frame frame1= grabber1.grab();
            if (frame1 == null) {
                break;
            }
            if (frame1.image != null) {
                // 将两个帧合并为一个画面
                Frame frame2=grabber2.grabImage();
                System.out.println("视频共" + videoSize + "帧,正处理第" + i  + "帧图片 ");
                // 创建一个新的 BufferedImage 用于合并画面
                BufferedImage combinedImage = new BufferedImage(grabber1.getImageWidth()+grabber2.getImageWidth(), grabber1.getImageHeight(), BufferedImage.TYPE_3BYTE_BGR);
                Graphics2D g2d = combinedImage.createGraphics();
                // 在合并画面上绘制两个视频帧
                g2d.drawImage(Java2DFrameUtils.toBufferedImage(frame1), 0, 0, null);
                g2d.drawImage(Java2DFrameUtils.toBufferedImage(frame2), grabber1.getImageWidth(), 0, null);
                g2d.dispose();
                // ImageIO.write(combinedImage,"png",new File("E:\\images1\\combinedImage"+i+".png"));
                // 将合并后的 BufferedImage 转换为帧并录制到目标视频中
                recorder.record(Java2DFrameUtils.toFrame(combinedImage));
                i++;
            }
            if (frame1.samples != null) {
                recorder.recordSamples(frame1.sampleRate, frame1.audioChannels, frame1.samples);
            }
        }
        // 释放资源
        grabber1.stop();
        grabber2.stop();
        recorder.stop();
    }

}

控制台运行输出日志
在这里插入图片描述

  • 两个 15s- 458帧的视频,合并画面 耗时 26s
  • 两个 15s- 458帧的视频,前后拼接 耗时 6.6s

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1319736.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YXLON高压发生器维修XRG160/160/GA

依科视朗YXLON高压发生器维修型号包括XRG100/110/120/130/160/225/320/450等。 维修包括&#xff1a;仪器高压发生器维修 X射线机高压发生器维修 CT高压发生器维修 安检设备高压发生器维修等。 高压发生器原理&#xff1a; 简单的说就是直流电震荡后升压,比如说1个小功率,利用…

MetaSploit工具的使用

在命令行输入&#xff1a;msfconsole 启动msf msfconsole 另外的方式 msfdb init msfdb run 查看数据库连接状态 db_status 扫描端口并存储 db_nmap 查看扫描到的数据信息 services MSF常用的模式和命令 搜索模块 search 模块名字 使用模块 use 编号 查看模块使用 sho…

目标检测应用场景—数据集【NO.19】车辆目标检测数据集

写在前面&#xff1a;数据集对应应用场景&#xff0c;不同的应用场景有不同的检测难点以及对应改进方法&#xff0c;本系列整理汇总领域内的数据集&#xff0c;方便大家下载数据集&#xff0c;若无法下载可关注后私信领取。关注免费领取整理好的数据集资料&#xff01;今天分享…

✺ch5——纹理贴图

目录 加载纹理图像文件纹理坐标在着色器中使用纹理&#xff1a;采样器变量和纹理单元纹理贴图&#xff1a;示例程序多级渐远纹理贴图各向异性过滤环绕和平铺透视变形材质——更多OpenGL细节补充说明 纹理贴图是在栅格化的模型表面上覆盖图像的技术。 它是为渲染场景添加真实感的…

Python三级 每周练习题31

如果你感觉有收获&#xff0c;欢迎给我微信扫打赏码 ———— 以激励我输出更多优质内容 练习一: 作业1:编写程序&#xff0c;在下面的字典中找出身高137的同学并输出姓名&#xff0c;如果没找到&#xff0c; 输出没有 a{‘小赵’:136,‘小钱’:141,‘小孙’:146,‘小李’:13…

操作系统基础知识

本文用于记录学习W3schools的操作系统教程&#xff0c;该教程的部分内容比较难懂&#xff0c;所以也参考了其他文章。 操作系统基础知识 一、操作系统概括二、操作系统的8个组件1 流程管理2 I/O设备管理3 文件管理4 网络管理5 内存管理6 磁盘管理(辅助存储管理)7 安全管理8 命令…

Elasticsearch——快速入门

从零基础的内容开始介绍Elasticsearch&#xff0c;主要包含以下内容&#xff1a; Elasticsearch的定义、优点&#xff0c;以及典型的业务场景。Elasticsearch中重要的概念。Elasticsearch典型的接入方式。安装Elasticsearch。使用Kibana调试Elasticsearch。Elasticsearch节点的…

【Transformer】ViT and TNT(2)

文章目录 VITTNT 太…完整了&#xff01;同济大佬唐宇迪博士终于把【Transformer】入门到精通全套课程分享出来了&#xff0c;最新前沿方向 学习笔记 VIT eg&#xff0c;图片分块&#xff0c;10x10x3 的 patch 通过 conv 拉成向量&#xff0c;就无缝对接了 位置编码可以多种方…

硬件基础:光耦、可控硅、继电器、达林顿管、干簧管

光耦 光电耦合器&#xff08;optical coupler&#xff0c;英文缩写为OC&#xff09;亦称光电隔离器&#xff0c;简称光耦。 光电耦合器是一种把发光器件和光敏器件封装在同一壳体内&#xff0c; 中间通过电→光→电的转换来传输电信号的半导体光电子器件。其中&#xff0c;发光…

三勾商城新功能-电子面单发货

商家快递发货时可以选择在线下单,在线获取和打印电子面单。免去手写面单信息以及避免填写运单号填错,系统会自动填写对应发货商品的运单信息 快递100电子面单1、进入快递100&#xff0c;点击登录 2、登录成功后&#xff0c;点击“电子面单与云打印” 3、进入电子面单与云打印后…

什么是缓存击穿、缓存穿透、缓存雪崩?

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

Yapi详细安装过程(亲测可用)

1. 前置条件 1、Git 2、NodeJs&#xff08;7.6&#xff09; 3、Mongodb&#xff08;2.6&#xff09; 2. NodeJs的安装 1、获取资源 curl -sL https://rpm.nodesource.com/setup_8.x | bash - 2、安装NodeJS yum install -y nodejs 3、查看NodeJs和Npm node -v npm -v…

算法——分治

思想&#xff1a;分而治之&#xff0c;将大问题转化为若干个相同或相似的子问题。快排的题目常见的方法是利用三指针法将数组分三块搭配随机选择基准元素的思想 颜色分类&#xff08;分治_快排&#xff09; 颜色分类 题目解析 原地对它们进行排序&#xff0c;使得相同颜色的元…

Appium 图像识别技术 OpenCV

在我们做App自动化测试的时候&#xff0c;会发现很多场景下元素没有id、content-desc、text等等属性&#xff0c;并且有可能也会碰到由于开发采用的是自定义View&#xff0c;View中的元素也无法识别到&#xff0c;很多的自动化测试框架对此类场景束手无策。Appium在V1.9.0中有给…

Temu、Shein、OZON测评自养号,IP和指纹浏览器的优缺点分析

随着全球电子商务的飞速发展&#xff0c;跨境电商环境展现出巨大的潜力和机遇。然而&#xff0c;跨境卖家们也面临着更激烈的竞争、更严格的规定和更高的运营成本等挑战。为了在这个环境中脱颖而出&#xff0c;一些卖家尝试使用自动脚本程序进行浏览和下单。然而&#xff0c;这…

【LeetCode刷题-回溯】--216.组合总和III

216.组合总和III 方法&#xff1a;回溯 class Solution {public List<List<Integer>> combinationSum3(int k, int n) {List<List<Integer>> ans new ArrayList<>();Deque<Integer> path new ArrayDeque<>(); dfs(ans,path,n,k,1…

复杂背景下的低空无人机检测与跟踪算法

doi&#xff1a;10.11884/HPLPB202335.230026 大视场中的目标丢失后需要再次检测&#xff0c;但是大视场的检测比较耗时。但是根据实验发现丢失目标通常发生在无人机运动区域的320x320范围内&#xff0c;所以设计辅助网络&#xff0c;当目标丢失后&#xff0c;以320x320区域图像…

SI24R03国产自主可控RISC-V架构MCU低功耗2.4GHz收发芯片SoC

目录 RISC-V架构的优势SI24R03/04特性射频收发器模块特征MCU 模块特征 其他特征 RISC-V架构的优势 相对于目前主流的英特尔X86架构及ARM等架构来说&#xff0c;RISC-V架构具有指令精简、模块化、可扩展、开源、免费等优点。RISC-V的基础指令集只有40多条&#xff0c;加上其他基…

AI智剪:一键批量剪辑,高效助力创作无限可能

你是否曾经因为视频剪辑工作繁琐而感到烦恼&#xff1f;是否曾经因为视频剪辑效率低下而无法按时完成任务&#xff1f;如果你也有这样的困扰&#xff0c;那么AI智剪将为你提供解决方案。 第一步&#xff1a;首先进入媒体梦工厂主页面&#xff0c; 并在板块栏里选择“AI智剪”板…

脉冲群EFT整改措施和影响?|深圳比创达电子

一、什么是脉冲群EFT&#xff1f; 脉冲群EFT是一种电磁兼容性测试方法&#xff0c;用于评估电子设备在电力系统中的耐受能力。它模拟了由电网中的突然切换或开关操作引起的瞬态电磁干扰&#xff0c;并对设备的性能进行测试。 二、影响脉冲群EFT测试的因素 在进行脉冲群EFT测试…