当前位置: 首页 > news >正文

springboot(JavaCV )实现视频截取第N帧并保存图片

springboot(JavaCV )实现视频截取第N帧并保存图片

现在视频网站展示列表都是用img标签展示的,动图用的是gif,但是我们上传视频时并没有视屏封面,就这需要上传到服务器时自动生成封面并保存

本博客使用jar包的方式实现上传视频文件并且截取视频第一帧,保存到阿里云的OSS(也可以保存到本地获取其他任何地方)。

JavaCV 是一款开源的视觉处理库,基于GPLv2协议,对各种常用计算机视觉库封装后的一组jar包,

封装了OpenCV、libdc1394、OpenKinect、videoInput和ARToolKitPlus等计算机视觉编程人员常用库的接口。

此方法的好处是不需要再服务器上安装插件,直接代码中就可以实现视频截取。

我们需要截取视频第一帧,主要用到了ffmpeg和opencv。

一 , 引入jar包
我用到的maven的目前最新javacv版本,1.4.3,它应该支持jdk1.7及以上,我项目用的还是jdk1.8.

不过需要注意的是在使用的过程当中 , maven引入jar的时候 会引入所有平台的版本

全部引入大小在五百兆左右(不建议使用)

<!--视频截取第一帧--><dependency><groupId>org.bytedeco</groupId><artifactId>javacv</artifactId><version>1.4.3</version></dependency><dependency><groupId>org.bytedeco.javacpp-presets</groupId><artifactId>ffmpeg-platform</artifactId><version>4.0.2-1.4.3</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>RELEASE</version></dependency>

二 , java 代码实现

public class ImgTools {//util调用application.propertiesprivate final static ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle("application");private final static String aliyuVideonImg = RESOURCE_BUNDLE.getString("aliyun.video.img");//    public static void main(String[] args) throws Exception {
//        ImgTools imgTools = new ImgTools();
//        System.out.println(imgTools.randomGrabberFFmpegVideoImage
//                ("视频地址,可以是网络视频,也可以是本地视频"));
//    }/*** 获取视频缩略图** @param filePath:视频路径* @throws Exception*/public String randomGrabberFFmpegVideoImage(String filePath) throws Exception {String targetFilePath = "";FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);ff.start();//判断是否是竖屏小视频String rotate = ff.getVideoMetadata("rotate");int ffLength = ff.getLengthInFrames();Frame f;int i = 0;int index = 3;//截取图片第几帧while (i < ffLength) {f = ff.grabImage();if (i == index) {if (null != rotate && rotate.length() > 1) {targetFilePath = doExecuteFrame(f, true);   //获取缩略图} else {targetFilePath = doExecuteFrame(f, false);   //获取缩略图}break;}i++;}ff.stop();return targetFilePath;  //返回的是视频第N帧}/*** 截取缩略图,存入阿里云OSS(按自己的上传类型自定义转换文件格式)** @param f* @return* @throws Exception*/public String doExecuteFrame(Frame f, boolean bool) throws Exception {if (null == f || null == f.image) {return "";}Java2DFrameConverter converter = new Java2DFrameConverter();BufferedImage bi = converter.getBufferedImage(f);if (bool == true) {Image image = (Image) bi;bi = rotate(image, 90);//图片旋转90度}ByteArrayOutputStream os = new ByteArrayOutputStream();ImageIO.write(bi, "png", os);byte[] sdf = os.toByteArray();InputStream input = new ByteArrayInputStream(os.toByteArray());MultipartFile multipartFile = new MockMultipartFile("temp.jpg", "temp.jpg", "temp.jpg", input);Aliyunoss aliyunoss = new Aliyunoss();//如需了解阿里云OSS,请详读我的另一篇博客("https://blog.csdn.net/weixin_44401989/article/details/105732856")String url = aliyunoss.uploadAli(multipartFile, aliyuVideonImg);return url;}/*** 图片旋转角度** @param src   源图片* @param angel 角度* @return 目标图片*/public static BufferedImage rotate(Image src, int angel) {int src_width = src.getWidth(null);int src_height = src.getHeight(null);// calculate the new image sizeRectangle rect_des = CalcRotatedSize(new Rectangle(new Dimension(src_width, src_height)), angel);BufferedImage res = null;res = new BufferedImage(rect_des.width, rect_des.height,BufferedImage.TYPE_INT_RGB);Graphics2D g2 = res.createGraphics();// transform(这里先平移、再旋转比较方便处理;绘图时会采用这些变化,绘图默认从画布的左上顶点开始绘画,源图片的左上顶点与画布左上顶点对齐,然后开始绘画,修改坐标原点后,绘画对应的画布起始点改变,起到平移的效果;然后旋转图片即可)//平移(原理修改坐标系原点,绘图起点变了,起到了平移的效果,如果作用于旋转,则为旋转中心点)g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2);//旋转(原理transalte(dx,dy)->rotate(radians)->transalte(-dx,-dy);修改坐标系原点后,旋转90度,然后再还原坐标系原点为(0,0),但是整个坐标系已经旋转了相应的度数 )g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);//        //先旋转(以目标区域中心点为旋转中心点,源图片左上顶点对准目标区域中心点,然后旋转)
//        g2.translate(rect_des.width/2,rect_des.height/ 2);
//        g2.rotate(Math.toRadians(angel));
//        //再平移(原点恢复到源图的左上顶点处(现在的右上顶点处),否则只能画出1/4)
//        g2.translate(-src_width/2,-src_height/2);g2.drawImage(src, null, null);return res;}/*** 计算转换后目标矩形的宽高** @param src   源矩形* @param angel 角度* @return 目标矩形*/private static Rectangle CalcRotatedSize(Rectangle src, int angel) {double cos = Math.abs(Math.cos(Math.toRadians(angel)));double sin = Math.abs(Math.sin(Math.toRadians(angel)));int des_width = (int) (src.width * cos) + (int) (src.height * sin);int des_height = (int) (src.height * cos) + (int) (src.width * sin);return new java.awt.Rectangle(new Dimension(des_width, des_height));}
}
public class ImgTools {//util调用application.propertiesprivate final static ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle("application");private final static String aliyuVideonImg = RESOURCE_BUNDLE.getString("aliyun.video.img");//    public static void main(String[] args) throws Exception {
//        ImgTools imgTools = new ImgTools();
//        System.out.println(imgTools.randomGrabberFFmpegVideoImage
//                ("视频地址,可以是网络视频,也可以是本地视频"));
//    }/*** 获取视频缩略图** @param filePath:视频路径* @throws Exception*/public String randomGrabberFFmpegVideoImage(String filePath) throws Exception {String targetFilePath = "";FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);ff.start();//判断是否是竖屏小视频String rotate = ff.getVideoMetadata("rotate");int ffLength = ff.getLengthInFrames();Frame f;int i = 0;int index = 3;//截取图片第几帧while (i < ffLength) {f = ff.grabImage();if (i == index) {if (null != rotate && rotate.length() > 1) {targetFilePath = doExecuteFrame(f, true);   //获取缩略图} else {targetFilePath = doExecuteFrame(f, false);   //获取缩略图}break;}i++;}ff.stop();return targetFilePath;  //返回的是视频第N帧}/*** 截取缩略图,存入阿里云OSS(按自己的上传类型自定义转换文件格式)** @param f* @return* @throws Exception*/public String doExecuteFrame(Frame f, boolean bool) throws Exception {if (null == f || null == f.image) {return "";}Java2DFrameConverter converter = new Java2DFrameConverter();BufferedImage bi = converter.getBufferedImage(f);if (bool == true) {Image image = (Image) bi;bi = rotate(image, 90);//图片旋转90度}ByteArrayOutputStream os = new ByteArrayOutputStream();ImageIO.write(bi, "png", os);byte[] sdf = os.toByteArray();InputStream input = new ByteArrayInputStream(os.toByteArray());MultipartFile multipartFile = new MockMultipartFile("temp.jpg", "temp.jpg", "temp.jpg", input);Aliyunoss aliyunoss = new Aliyunoss();//如需了解阿里云OSS,请详读我的另一篇博客("https://blog.csdn.net/weixin_44401989/article/details/105732856")String url = aliyunoss.uploadAli(multipartFile, aliyuVideonImg);return url;}/*** 图片旋转角度** @param src   源图片* @param angel 角度* @return 目标图片*/public static BufferedImage rotate(Image src, int angel) {int src_width = src.getWidth(null);int src_height = src.getHeight(null);// calculate the new image sizeRectangle rect_des = CalcRotatedSize(new Rectangle(new Dimension(src_width, src_height)), angel);BufferedImage res = null;res = new BufferedImage(rect_des.width, rect_des.height,BufferedImage.TYPE_INT_RGB);Graphics2D g2 = res.createGraphics();// transform(这里先平移、再旋转比较方便处理;绘图时会采用这些变化,绘图默认从画布的左上顶点开始绘画,源图片的左上顶点与画布左上顶点对齐,然后开始绘画,修改坐标原点后,绘画对应的画布起始点改变,起到平移的效果;然后旋转图片即可)//平移(原理修改坐标系原点,绘图起点变了,起到了平移的效果,如果作用于旋转,则为旋转中心点)g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2);//旋转(原理transalte(dx,dy)->rotate(radians)->transalte(-dx,-dy);修改坐标系原点后,旋转90度,然后再还原坐标系原点为(0,0),但是整个坐标系已经旋转了相应的度数 )g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);//        //先旋转(以目标区域中心点为旋转中心点,源图片左上顶点对准目标区域中心点,然后旋转)
//        g2.translate(rect_des.width/2,rect_des.height/ 2);
//        g2.rotate(Math.toRadians(angel));
//        //再平移(原点恢复到源图的左上顶点处(现在的右上顶点处),否则只能画出1/4)
//        g2.translate(-src_width/2,-src_height/2);g2.drawImage(src, null, null);return res;}/*** 计算转换后目标矩形的宽高** @param src   源矩形* @param angel 角度* @return 目标矩形*/private static Rectangle CalcRotatedSize(Rectangle src, int angel) {double cos = Math.abs(Math.cos(Math.toRadians(angel)));double sin = Math.abs(Math.sin(Math.toRadians(angel)));int des_width = (int) (src.width * cos) + (int) (src.height * sin);int des_height = (int) (src.height * cos) + (int) (src.width * sin);return new java.awt.Rectangle(new Dimension(des_width, des_height));}
}

相关文章:

springboot(JavaCV )实现视频截取第N帧并保存图片

springboot&#xff08;JavaCV &#xff09;实现视频截取第N帧并保存图片 现在视频网站展示列表都是用img标签展示的&#xff0c;动图用的是gif&#xff0c;但是我们上传视频时并没有视屏封面&#xff0c;就这需要上传到服务器时自动生成封面并保存 本博客使用jar包的方式实现…...

Linux面试笔试题(5)

79、下列工具中可以直接连接mysql的工具有【c 】。 A.xhsell B.plsql C.navicat D.以上都不是 Navicat 是一套可创建多个连接的数据库开发工具&#xff0c; 让你从单一应用程序中同时连接 MySQL、Redis、MariaDB、MongoDB、 SQL Server、Oracle、PostgreSQL和 SQLite 。它与…...

WordPress文章:创建和优化您的网站内容

WordPress是一种流行的内容管理系统&#xff08;CMS&#xff09;&#xff0c;用于创建和管理网站。无论您是个人博客作者、企业网站管理员还是电子商务店主&#xff0c;WordPress都是一个强大而灵活的平台&#xff0c;可帮助您展示和传达您的信息。本文将为您提供一些关于创建和…...

Selenium webdriver_manager根据浏览器版本自动下载对应驱动程序

前言 webdriver_manager是什么&#xff1f; webdriver_manager 是 Python 中的一个库&#xff0c;用于管理 Web 驱动程序。它的作用是自动下载和设置不同浏览器&#xff08;如 Chrome、Firefox、Edge 等&#xff09;的 Web 驱动程序&#xff0c;以便在自动化测试中使用这些浏…...

2023 - java - 强制类型转换和装箱

强制类型转换和装箱&#xff1a; 在 Java 中&#xff0c;(Integer) 和(int) 是两个不同的类型转换操作符&#xff0c;它们的效果是不一样的。 int a (Integer) t.getContent(); 这条语句使用了装箱&#xff08;Boxing&#xff09;操作&#xff0c;将一个整数对象&#xff08;…...

使用ansible自动化部署Kubernetes

使用 kubeasz 部署 Kubernetes 集群 服务器列表&#xff1a; IP主机名角色192.168.100.142kube-master1,kube-master1.suosuoli.cnK8s 集群主节点 1192.168.100.144kube-master2,kube-master2.suosuoli.cnK8s 集群主节点 2192.168.100.146kube-master3,kube-master3.suosuoli…...

k8s v1.27.4 部署metrics-serverv:0.6.4,kube-prometheus

只有一个问题&#xff0c;原来的httpGet存活、就绪检测一直不通过&#xff0c;于是改为tcpSocket后pod正常。 wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml修改后的yaml文件&#xff0c;镜像修改为阿里云 apiVersion: …...

6-模板初步使用

官网: 中文版: 介绍-Jinja2中文文档 英文版: Template Designer Documentation — Jinja Documentation (2.11.x) 模板语法 1. 模板渲染 (1) app.py 准备数据 import jsonfrom flask import Flask,render_templateimport settingsapp Flask(__name__) app.config.from_obj…...

STM32CubeMX配置STM32F103 USB Virtual Port Com(HAL库开发)

1.配置外部高速晶振 2.勾选USB功能 3.将USB模式配置Virtual Port Com 4.将系统主频配置为72M,USB频率配置为48M. 5.配置好项目名称&#xff0c;开发环境&#xff0c;最后获取代码。 6.在CDC_Receive_FS函数中写入USB发送函数。这样USB接收到的数据就好原样发送。 7.将串口助手打…...

RocketMQ与Kafka对比(18项差异)

淘宝内部的交易系统使用了淘宝自主研发的Notify消息中间件,使用MySQL作为消息存储媒介,可完全水平扩容,为了进一步降低成本,我们认为存储部分可以进一步优化,2011年初,Linkin开源了Kafka这个优秀的消息中间件,淘宝中间件团队在对Kafka做过充分Review之后,Kafka无限消息…...

英文翻译照片怎么做?掌握这个方法轻松翻译

在现代社会中&#xff0c;英文已经成为了一种全球性的语言&#xff0c;因此&#xff0c;我们在阅读文章或者查看图片时&#xff0c;经常会遇到英文的内容。为了更好地理解这些英文内容&#xff0c;我们需要将其翻译成中文。在本文中&#xff0c;我将探讨图片中英文内容翻译的方…...

Linux介绍

目录 unix linux的版本号 linux对unix的继承 linux特性&#xff1a;安全性高 unix Unix是一个先进的、多用户、多任务的操作系统&#xff0c;被广泛用于服务器、工作站和移动设备。以下是Unix的一些关键特点和组件&#xff1a; 多用户系统&#xff1a;允许多个用户同时访…...

计算机竞赛 卷积神经网络手写字符识别 - 深度学习

文章目录 0 前言1 简介2 LeNet-5 模型的介绍2.1 结构解析2.2 C1层2.3 S2层S2层和C3层连接 2.4 F6与C5层 3 写数字识别算法模型的构建3.1 输入层设计3.2 激活函数的选取3.3 卷积层设计3.4 降采样层3.5 输出层设计 4 网络模型的总体结构5 部分实现代码6 在线手写识别7 最后 0 前言…...

[Go版]算法通关村第十三关白银——数组实现加法和幂运算

目录 数组实现加法专题题目&#xff1a;数组实现整数加法思路分析&#xff1a;复杂度&#xff1a;Go代码 题目&#xff1a;字符串加法思路分析&#xff1a;复杂度&#xff1a;Go代码 题目&#xff1a;二进制加法思路分析&#xff1a;复杂度&#xff1a;Go代码 幂运算专题题目&a…...

React笔记[tsx]-解决Property ‘frames‘ does not exist on type ‘Readonly<{}>‘

浏览器报错如下&#xff1a; 编辑器是这样的&#xff1a; 原因是React.Component<any>少了后面的any&#xff0c;改成这样即可&#xff1a; export class CustomFrame extends React.Component<any, any>{............ }...

ThinkPHP6.0+ 使用Redis 原始用法

composer 安装 predis/predis 依赖&#xff0c;或者安装php_redis.dll的扩展。 我这里选择的是predis/predis 依赖。 composer require predis/predis 进入config/cache.php 配置添加redis缓存支持 示例&#xff1a; <?php// -----------------------------------------…...

SRM系统询价竞价管理:优化采购流程的全面解析

SRM系统的询价竞价管理模块是现代企业采购管理中的重要工具。通过该模块&#xff0c;企业可以实现供应商的询价、竞价和合同管理等关键环节的自动化和优化。 一、概述 SRM系统是一种用于管理和优化供应商关系的软件系统。它通过集成各个环节&#xff0c;包括供应商信息管理、询…...

c++选择题笔记

局部变量能否和全局变量重名&#xff1f;可以&#xff0c;局部变量会屏蔽全局变量。在使用全局变量时需要使用 ":: "。拷贝构造函数&#xff1a;参数为同类型的对象的常量引用的构造函数函数指针&#xff1a;int (*f)(int,int) & max; 虚函数&#xff1a;在基类…...

Android2:构建交互式应用

一。创建项目 项目名Beer Adviser 二。更新布局 activity_main.xml <?xml version"1.0" encoding"utf-8"?><LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"…...

ChatGLM-6B微调记录

目录 GLM-130B和ChatGLM-6BChatGLM-6B直接部署基于PEFT的LoRA微调ChatGLM-6B GLM-130B和ChatGLM-6B 对于三类主要预训练框架&#xff1a; autoregressive&#xff08;无条件生成&#xff09;&#xff0c;GPT的训练目标是从左到右的文本生成。autoencoding&#xff08;语言理解…...

Linux Kernel 4.12 或将新增优化分析工具

到 7 月初&#xff0c;Linux Kernel 4.12 预计将为修复所有安全漏洞而奠定基础&#xff0c;另外新增的是一个分析工具&#xff0c;对于开发者优化启动时间时会有所帮助。 新的「个别任务统一模型」&#xff08;Per-Task Consistency Model&#xff09;为主要核心实时修补&#…...

【30天熟悉Go语言】10 Go异常处理机制

作者&#xff1a;秃秃爱健身&#xff0c;多平台博客专家&#xff0c;某大厂后端开发&#xff0c;个人IP起于源码分析文章 &#x1f60b;。 源码系列专栏&#xff1a;Spring MVC源码系列、Spring Boot源码系列、SpringCloud源码系列&#xff08;含&#xff1a;Ribbon、Feign&…...

飞机打方块(四)游戏结束

一、游戏结束显示 1.新建节点 1.新建gameover节点 2.绑定canvas 3.新建gameover容器 4.新建文本节点 2.游戏结束逻辑 Barrier.ts update(dt: number) {//将自身生命值取整let num Math.floor(this.num);//在Label上显示this.num_lb.string num.toString();//获取GameCo…...

保研之旅1:西北工业大学电子信息学院夏令营

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; 本人持续分享更多关于电子通信专业内容以及嵌入式和单片机的知识&#xff0c;如果大家喜欢&#xff0c;别忘点个赞加个关注哦&#xff0c;让我们一起共同进步~ &#x…...

[WMCTF 2023] crypto

似乎退步不了&#xff0c;这个比赛基本不会了&#xff0c;就作了两个简单题。 SIGNIN 第1个是签到题 from Crypto.Util.number import * from random import randrange from secret import flagdef pr(msg):print(msg)pr(br"""........ …...

图像分割unet系列------TransUnet详解

图像分割unet系列------TransUnet详解 1、TransUnet结构2、我关心的问题3、总结与展望TransUnet发表于2021年,它是对UNet非常重要的改进,专为医学图像分割任务设计,特别用于在医学图像中分割器官或病变等解剖结构。 1、TransUnet结构 TransUNet在U-Net模型的基础上引入了混合…...

ASCII码-shellcode的技巧

网上已经有成熟的工具了&#xff0c;所以就简单记录一下工具怎么用吧 https://github.com/TaQini/alpha3 https://github.com/veritas501/ae64.git https://github.com/rcx/shellcode_encoder 结合题目来看吧&#xff0c;没有开启NX保护&#xff0c;基本这类型题目九成九都…...

spring cloud 之 dubbo nacos整合

整体思路&#xff1a; 搭建本地nacos服务&#xff0c;详见docker安装nacos_xgjj68163的博客-CSDN博客 共三个工程&#xff0c;生产者服务、消费者服务、生产者和消费者共同依赖的接口工程&#xff08;打成jar&#xff0c;供生产者和消费者依赖&#xff09;&#xff1b; …...

MySQL如何进行表之间的关联更新

在实际编程工作或运维实践中&#xff0c;对MySQL数据库表进行关联更新是一种比较常见的应用场景&#xff0c;比如在电商系统中&#xff0c;订单表里保存了商品名称的信息&#xff08;冗余字段设计&#xff09;&#xff0c;但如果商品名称发生变化&#xff0c;则需要通过关联商品…...

Docker创建 LNMP 服务+Wordpress 网站平台

Docker创建 LNMP 服务Wordpress 网站平台 一.环境及准备工作 1.项目环境 公司在实际的生产环境中&#xff0c;需要使用 Docker 技术在一台主机上创建 LNMP 服务并运行 Wordpress 网站平台。然后对此服务进行相关的性能调优和管理工作。 容器 系统 IP地址 软件 nginx centos…...

手机wap购物网站模板/关键词排名优化营销推广

概述 循环创建按钮, 进行按钮单选或者多选的操作.详细 代码下载&#xff1a;http://www.demodashi.com/demo/10712.html 我们经常会有多行多列按钮的页面, 这个时候我们通常会选择循环创建按钮, 然后进行按钮单选或者多选的操作! 一、程序实现 一. 单选逻辑处理 1. 创建按钮控件…...

用javaweb做购物网站/一台电脑赚钱的门路

学习网络渗透技术是一件靠兴趣驱动的事情&#xff0c;只有强烈热爱一件事才能持之以恒的去做&#xff0c;对于那些三分钟热度的人来说还是劝你放弃吧&#xff0c;因为网络渗透技术自学需要很多方面的知识&#xff0c;没耐心是无法学会的&#xff0c;当然除了有想要学习的决心之…...

南山老品牌网站建设/上海seo推广

各种字符串Hash函数比较 https://www.byvoid.com/blog/string-hash-compare 字符串Hash函数对比 http://blog.csdn.net/icefireelf/article/details/5796529 Python 内置hash函数&#xff1a; import hash sha1obj hashlib.sha1() sha1obj.update(title_a) hash sha1obj.h…...

今天新冠病毒最新消息/怎么做seo网站关键词优化

pycharm同时使用python2.7和python3.5设置方法 - CSDN博客https://blog.csdn.net/qwerty200696/article/details/53015922转载于:https://www.cnblogs.com/jyfootprint/p/9417006.html...

打字做任务赚钱的网站/河南网站推广优化

Welcome to My Book Store.please choose your favorite book, clickhere.Enjoy!...

河北住房和城乡建设网站/谷歌浏览器手机版免费官方下载

启动项目java -jar /目录 &例如 nohup java -jar /data/wwwroot/springboot.kingsuper.net/demo.jar & 重新启动项目&#xff0c;要先将之前的端口杀死查询端口netstat -tunlp 杀死端口 kill -9 端口例如 kill -9 18607转载于:https://www.cnblogs.com/SeaWxx/p/109377…...