【Java Web开发学习】使用Javacv截取视频图片

转载:https://www.cnblogs.com/yangchongxing/p/9482935.html

github地址:https://github.com/bytedeco/javacv

Java不擅长处理视频和图片。使用场景是上传上来的视屏需要一个封面,所以就用java实现了。

javacv文档很少,参考网上的代码稍作修改而成,仅供参考,有好的方式欢迎留言。

网上有好多没有解决截屏图片被旋转过的问题,使用String rotate = grabber.getVideoMetadata("rotate");获取视频有没有旋转,没有返回null,有返回度数,90,180,270等。把图片做对象旋转,图片就正了。

示例代码:select截取第20帧的图片

  1. public static void main(String[] args) throws IOException {
  2. // 截第20帧
  3. int select = 20;
  4. FFmpegFrameGrabber grabber = new FFmpegFrameGrabber("E:/wx/下.mp4");
  5. grabber.start();
  6. int length = grabber.getLengthInFrames();
  7. int index = 1;
  8. Frame frame = null;
  9. while (index <= length) {
  10. frame = grabber.grab();
  11. if (index >= select) {
  12. break;
  13. }
  14. index++;
  15. }
  16. String rotate = grabber.getVideoMetadata("rotate");
  17. Java2DFrameConverter converter = new Java2DFrameConverter();
  18. BufferedImage bi = converter.getBufferedImage(frame);
  19. if (rotate != null) {
  20. //旋转图片
  21. bi = rotate(bi, Integer.parseInt(rotate));
  22. }
  23. ImageIO.write(bi, "jpg", new File("E:/wx/" + System.currentTimeMillis() + ".jpg"));
  24. grabber.stop();
  25. }
  26. public static BufferedImage rotate(BufferedImage src, int angel) {
  27. int src_width = src.getWidth(null);
  28. int src_height = src.getHeight(null);
  29. int type = src.getColorModel().getTransparency();
  30. Rectangle rect_des = calcRotatedSize(new Rectangle(new Dimension(src_width, src_height)), angel);
  31. BufferedImage bi = new BufferedImage(rect_des.width, rect_des.height, type);
  32. Graphics2D g2 = bi.createGraphics();
  33. g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2);
  34. g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);
  35. g2.drawImage(src, 0, 0, null);
  36. g2.dispose();
  37. return bi;
  38. }
  39. public static Rectangle calcRotatedSize(Rectangle src, int angel) {
  40. if (angel >= 90) {
  41. if(angel / 90 % 2 == 1) {
  42. int temp = src.height;
  43. src.height = src.width;
  44. src.width = temp;
  45. }
  46. angel = angel % 90;
  47. }
  48. double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
  49. double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
  50. double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2;
  51. double angel_dalta_width = Math.atan((double) src.height / src.width);
  52. double angel_dalta_height = Math.atan((double) src.width / src.height);
  53. int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_width));
  54. int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_height));
  55. int des_width = src.width + len_dalta_width * 2;
  56. int des_height = src.height + len_dalta_height * 2;
  57. return new java.awt.Rectangle(new Dimension(des_width, des_height));
  58. }

下面是一个上传截取第一帧做图片

  1. import java.awt.Dimension;
  2. import java.awt.Graphics2D;
  3. import java.awt.Rectangle;
  4. import java.awt.image.BufferedImage;
  5. import java.io.File;
  6. import java.io.IOException;
  7. import java.text.SimpleDateFormat;
  8. import java.util.Date;
  9.  
  10. import javax.imageio.ImageIO;
  11. import javax.servlet.http.HttpServletRequest;
  12.  
  13. import org.bytedeco.javacv.FFmpegFrameGrabber;
  14. import org.bytedeco.javacv.Java2DFrameConverter;
  15. import org.springframework.stereotype.Controller;
  16. import org.springframework.web.bind.annotation.RequestMapping;
  17. import org.springframework.web.bind.annotation.RequestMethod;
  18. import org.springframework.web.bind.annotation.RequestParam;
  19. import org.springframework.web.bind.annotation.ResponseBody;
  20. import org.springframework.web.multipart.commons.CommonsMultipartFile;
  21. import org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest;
  22.  
  23. @RequestMapping("/upload")
  24. @Controller
  25. public class UploadController extends BaseController {
  26. // 图片上传
  27. @RequestMapping(value="/image", method=RequestMethod.POST, produces="application/json;charset=UTF-8")
  28. @ResponseBody
  29. public String uploadImage(@RequestParam(value = "imageFile", required = false) CommonsMultipartFile imageFile, HttpServletRequest request) throws IOException {
  30. if (imageFile == null || imageFile.getSize() == 0) {
  31. DefaultMultipartHttpServletRequest multipartRequest = (DefaultMultipartHttpServletRequest)request;
  32. imageFile = (CommonsMultipartFile) multipartRequest.getFile("Filedata");
  33. if (imageFile == null || imageFile.getSize() == 0) {
  34. Result result = new Result();
  35. result.setStatus(Result.STATUS_FAILURE);
  36. result.setMessage(Result.STATUS_FAILURE);
  37. return result.toJson();
  38. }
  39. }
  40. //文件名
  41. String fileName = Utils.fileName() + Utils.suffix(imageFile.getOriginalFilename());
  42. //日期目录
  43. String path = "/uploads/images" + new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
  44. //服务器图片文件存放目录
  45. String serverPath = request.getServletContext().getRealPath(path);
  46.  
  47. File serverPathFile = new File(serverPath);
  48. //目录不存在则创建
  49. if (!serverPathFile.exists()) {
  50. serverPathFile.mkdirs();
  51. }
  52. String imageUrl = path + fileName;
  53. String serverFilePath = serverPath + fileName;
  54. //移动文件
  55. imageFile.transferTo(new File(serverFilePath));return imageUrl;
  56. }
  57. // 视频上传
  58. @SuppressWarnings("resource")
  59. @RequestMapping(value="/video", method=RequestMethod.POST, produces="application/json;charset=UTF-8")
  60. @ResponseBody
  61. public String uploadVideo(@RequestParam(value = "videoFile", required = false) CommonsMultipartFile imageFile, HttpServletRequest request) throws IOException {
  62. if (imageFile == null || imageFile.getSize() == 0) {
  63. Result result = new Result();
  64. result.setStatus(Result.STATUS_FAILURE);
  65. result.setMessage("文件不存在");
  66. return result.toJson();
  67. }
  68. //文件名
  69. String fileName = Utils.fileName() + Utils.suffix(imageFile.getOriginalFilename());
  70. //日期目录
  71. String path = "/uploads/videos" + new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
  72. //服务器图片文件存放目录
  73. String serverPath = request.getServletContext().getRealPath(path);
  74.  
  75. File serverPathFile = new File(serverPath);
  76. //目录不存在则创建
  77. if (!serverPathFile.exists()) {
  78. serverPathFile.mkdirs();
  79. }
  80. String serverFilePath = serverPath + fileName;
  81. //移动文件
  82. imageFile.transferTo(new File(serverFilePath));
  83.  
  84. //视频截屏
  85. FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(serverFilePath);
  86. grabber.start();
  87. Java2DFrameConverter converter = new Java2DFrameConverter();
  88. BufferedImage bi = converter.convert(grabber.grab());
  89. String rotate = grabber.getVideoMetadata("rotate");
  90. if (rotate != null) {
  91. bi = rotate(bi, Integer.parseInt(rotate));
  92. }
  93. fileName += ".v.jpg";
  94. serverFilePath = serverPath + fileName;
  95. String imageUrl = path + fileName;
  96. ImageIO.write(bi, "jpg", new File(serverFilePath));
  97. grabber.stop();
  98. // 返回截取封面
    return imageUrl;
  99. }
  100.  
  101. public static BufferedImage rotate(BufferedImage src, int angel) {
  102. int src_width = src.getWidth(null);
  103. int src_height = src.getHeight(null);
  104. int type = src.getColorModel().getTransparency();
  105. Rectangle rect_des = CalcRotatedSize(new Rectangle(new Dimension(src_width, src_height)), angel);
  106. BufferedImage bi = new BufferedImage(rect_des.width, rect_des.height, type);
  107. Graphics2D g2 = bi.createGraphics();
  108. g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2);
  109. g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);
  110. g2.drawImage(src, 0, 0, null);
  111. g2.dispose();
  112. return bi;
  113. }
  114. public static Rectangle CalcRotatedSize(Rectangle src, int angel) {
  115. if (angel >= 90) {
  116. if(angel / 90 % 2 == 1) {
  117. int temp = src.height;
  118. src.height = src.width;
  119. src.width = temp;
  120. }
  121. angel = angel % 90;
  122. }
  123. double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
  124. double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
  125. double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2;
  126. double angel_dalta_width = Math.atan((double) src.height / src.width);
  127. double angel_dalta_height = Math.atan((double) src.width / src.height);
  128.  
  129. int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_width));
  130. int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_height));
  131. int des_width = src.width + len_dalta_width * 2;
  132. int des_height = src.height + len_dalta_height * 2;
  133. return new java.awt.Rectangle(new Dimension(des_width, des_height));
  134. }
  135. }

【Java SE】使用Javacv截取视频图片的更多相关文章

  1. C#利用开源软件ffMpeg截取视频图片

    #region 从视频画面中截取一帧画面为图片 /// <summary> /// 从视频画面中截取一帧画面为图片 /// </summary> /// <param n ...

  2. 使用javacv 截取视频指定帧节

    个人博客 地址:https://www.wenhaofan.com/article/20190407105818 引入依赖 <dependency> <groupId>org. ...

  3. (转载)[FFmpeg]使用ffmpeg从各种视频文件中直接截取视频图片

    你曾想过从一个视频文件中提取图片吗?在Linux下就可以,在这个教程中我将使用ffmpeg来从视频中获取图片. 什么是ffmpeg?What is ffmpeg? ffmpeg是一个非常有用的命令行程 ...

  4. iOS截取视频缩略图的两种方法

    前言: 看完了使用MPMoviePlayerController播放在线视频,在实际应用中有时候须要获取视频的缩略图,我们来看看怎样截取指定时间内的视频缩略图. 一  使用MPMoviePlayerC ...

  5. FFmpeg-截取视频图片

    FFmpeg-截取视频图片 标签(空格分隔): linux 安装FFmpeg 官网:http://www.ffmpeg.org/ 这里主要是linux环境下的安装 1. wget http://ffm ...

  6. javacv——读取摄像头的图像、截取视频的画面

    javacv开发包是用于支持java多媒体开发的一套开发包,可以适用于本地多媒体(音视频)调用以及音视频,图片等文件后期操作(图片修改,音视频解码剪辑等等功能). 这些需要引入的包.音视频处理使用ff ...

  7. javacpp-opencv图像处理之1:实时视频添加文字水印并截取视频图像保存成图片,实现文字水印的字体、位置、大小、粗度、翻转、平滑等操作

    欢迎大家积极开心的加入讨论群 群号:371249677 (点击这里进群) javaCV图像处理系列: javaCV图像处理之1:实时视频添加文字水印并截取视频图像保存成图片,实现文字水印的字体.位置. ...

  8. Java截取视频文件缩略图

    /** * 截取视频第0帧的图片 */public static void videoImage(String filePath, String fileName,int widthdist, int ...

  9. php ffmpeg截取视频第一帧保存为图片的方法

    php ffmpeg截取视频第一帧保存为图片的方法 <pre> $xiangmupath = $this->getxiangmupath(); $filename = 'chengs ...

随机推荐

  1. C语言|博客作业06

    这个作业属于哪个课程 C语言程序设计II 这个作业的要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-1/homework/9885 我在这个课程的 ...

  2. synchronized:内部锁

    synchronized:内部锁 起源: 并行程序开发涉及多线程.多任务间的协作和数据共享 一).内部锁:synchronized 1).定义在方法上 public synchronized void ...

  3. vim用户手册笔记常用操作整理

    "x"命令可以删除一个字符 "d"命令可以后跟任何一个位移命令,它将删除从当前光标起到位移的终点处的文本内容dw "c",改变命令例如cw ...

  4. node 后台使用增删改查(4)

    无论node还是java增删改查都是一样的原理,变得是配合框架使用时候有简便方法而已. 这里我接着上一篇开始讲,使用同一个数据库(数据库创建)这里必须创建了数据库 优化:为了维护方便这里我们把sql语 ...

  5. [ch03-00] 损失函数

    系列博客,原文在笔者所维护的github上:https://aka.ms/beginnerAI, 点击star加星不要吝啬,星越多笔者越努力. 第3章 损失函数 3.0 损失函数概论 3.0.1 概念 ...

  6. python3 之 内置函数enumerate

    python3 内置函数enumerate一.简介: 该函数在字面上是枚举.列举的意思,用于将一个可遍历的数据对象(如列表.元组或字符串)组合为一个索引序列, 同时列出数据和数据下标,一般用在 for ...

  7. PHP开发各种规范,面试秘籍!

    基本约定 源文件 代码使用<?php开头,忽略闭合标签?> 文件格式必须是无BOM UTF-8格式 一个文件只声明一种类型,如class和interface不能混写在一个源文件中 缩进 使 ...

  8. 【数据结构】之顺序表(C语言描述)

    顺序表是线性表的一种,它将元素存储在一段连续的内存空间中,表中的任意元素都可以通过下标快速的获取到,因此,顺序表适合查询操作频繁的场景,而不适合增删操作频繁的场景. 下面是使用 C语言 编写的顺序表的 ...

  9. js贪吃蛇(构造函数)

    给大家分享一下这几天我研究的一个贪吃蛇,挺简单的,但是实现起来其实有点绕的,我给大家附上完整代码,一起分析学习一下,主要用的是构造函数. 思想: .设计蛇:属性有宽.高.方向.状态(有多少节),方法: ...

  10. 爬取豆瓣top250音乐 时长 出版商 存入Mongo数据库

    import requestsfrom lxml import etreeimport reimport pymongoimport time client = pymongo.MongoClient ...