笔者之前遇到一个抓取视频图片,然后视频图片倒置的问题,之后查了些博文找到解决办法。不过这不是主要的,主要的是javacv的代码笔者当时没有读懂,现在发一篇有详细注释的文档,分享一下使用心得。

目录

  • 一、先上源码,每一行都有注释
  • 二、使用注意事项
    • 1、使用javacv之前记得倒入依赖
    • 2、注意视屏中的Rotate属性
    • 3、最容易忽视的一点:取帧(Frame)

一、先上源码,每一行都有注释

package com.muyichen.demo.javacv;import org.bytedeco.javacv.*;
import org.bytedeco.opencv.opencv_core.IplImage;
import org.springframework.util.StringUtils;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;import static org.bytedeco.opencv.global.opencv_core.cvFlip;
import static org.bytedeco.opencv.global.opencv_core.cvTranspose;/*** 抓取视频图片工具类* @author muyichen* @version 1.0*/
public class FrameGrabberUtil {/*** 抓取视频图片工具* @param filePath          视频文件路径(加上文件名)* @param targetFilePath    取出图片的存放路径* @param targetFileName    取出图片的名称(全名:当前参数+帧数)* @param randomSize        取出多少张图片(数量)* @throws FrameGrabber.Exception*/public static void randomGrabberFFmpegImage(String filePath, String targetFilePath, String targetFileName, int randomSize) throws FrameGrabber.Exception {//根据路径读取视频文件FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);//启动FFmpegFrameGrabber(抓帧器)ff.start();//获取rotate属性String rotate =ff.getVideoMetadata("rotate");//获取视频中包含有多少帧int ffLength = ff.getLengthInFrames();//随机选出五个取帧位置List<Integer> randomGrab = random(ffLength, randomSize);//标记最后读取的位置(在这个位置跳出循环)int maxRandomGrab =randomGrab.get(randomGrab.size() - 1);//遍历随机选出来的帧位置Frame f;int i = 0;while (i <ffLength) {//取出对应位置的帧f = ff.grabImage();//当前帧是想要获取的帧则将其读取出来if (randomGrab.contains(i)) {//是否存在rotate属性,存在则需要对图片进行修正处理if (!StringUtils.isEmpty(rotate)) {//创建一个CVF帧-图片转换器OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();//使用转换器将获取出的帧(Frame)对象转换为图片对象IplImage src = converter.convert(f);//将图片对象修正处理完成后,再转换为帧(Frame)对象f = converter.convert(rotate(src, Integer.parseInt(rotate)));}//将帧对象输出为具体的图片文件doExecuteFrame(f, targetFilePath, targetFileName, i);}//如果到需要的帧取完了则跳出循环if (i >= maxRandomGrab) {break;}i++;};ff.stop();}/*** 将图片根据rotate属性还原为它原来的状态* @param src       原始图片对象* @param rotate    旋转角度* @return*/public static IplImage rotate(IplImage src, int rotate) {//创建一个和原图片宽高互换的图片框架IplImage img = IplImage.create(src.height(), src.width(), src.depth(), src.nChannels());//将原图片中元素的位置进行矩阵转置后放入新创建的图片框架中cvTranspose(src, img);//将转置好后的图片根据rotate属性的值旋转对应的度数(根据纵轴旋转rotate度数)cvFlip(img, null, rotate);//返回最终生成的图片return img;}/*** 将帧对象输出为具体的图片文件* @param f                 帧对象* @param targetFilePath    输出图片文件存放路径* @param targetFileName    输出图片文件名* @param index             帧位置(视频的第几帧)*/public static void doExecuteFrame(Frame f, String targetFilePath, String targetFileName, int index) {if (null == f || null == f.image) {return;}//创建一个2D帧转换器Java2DFrameConverter converter = new Java2DFrameConverter();//设定图片的输出格式String imageMat = "png";//设定图片的全路径+图片名String FileName = targetFilePath + File.separator + targetFileName + "_" + index + "." + imageMat;//使用2D帧转换器将视频中的帧转换为图片缓冲对象BufferedImage bi = converter.getBufferedImage(f);//根据图片的全路径名创建一个图片文件File output = new File(FileName);try {//使用图片IO将图片缓冲对象写入新创建的图片文件中ImageIO.write(bi, imageMat, output);} catch (IOException e) {e.printStackTrace();}}/*** 随机选出指定长度范围类的几个数字* @param baseNum   随机选出的数字个数* @param length    指定长度范围* @return*/public static List<Integer> random(int baseNum, int length) {//创建指定长度的接收数字集合对象List<Integer> list = new ArrayList<>(length);//当集合对象未满时,循环选出while (list.size() < length) {//获取指定范围类的随机数Integer next = (int) (Math.random() * baseNum);//判断集合中是否存在当前随机出来的数,有的话则跳出当前循环进入下一循环if (list.contains(next)) {continue;}//将指定范围随机数放入集合中list.add(next);}//对集合进行排序Collections.sort(list);return list;}public static void main(String[] args) throws Exception {randomGrabberFFmpegImage("/Users/muyichen/Downloads/0420上传.mp4", "/Users/muyichen/Downloads", "screenshot", 5);}}

二、使用注意事项

1、使用javacv之前记得倒入依赖

<dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.3</version>
</dependency>

注意各个版本之间的类方法位置可能不同,比如1.3.1版本中的IplImage是一个内部类,但是1.5.3的这个类却独立出来了。

2、注意视屏中的Rotate属性

Roate属性是导致图片由竖屏变横屏的主要原因,上述代码中有着详细的处理方法。

3、最容易忽视的一点:取帧(Frame)

使用FFmpegFrameGrabber的时候,需要将它当成一个流来处理,FFmpegFrameGrabber无法指定从确定位置取帧,只能一帧一帧的读取。grabImage()这个方法相当于流中的read()方法,它每读完一帧后都会从当前读取帧的下一帧位置开始读取。(也就是说如果要读取100帧位置的图片,那么他会先将前面的99帧都先读一遍后才能读到第100帧的图片

javacv使用详解相关推荐

  1. javacv开发详解之19:如何使用批量的多张图片制作apng动态图,再也不用担心不会制作动态图了

    javacv实战专栏目录: JavaCV实战专栏文章目录(JavaCV速查手册) 前言 前面写过视频.桌面屏幕录制apng和gif动态图,虽然已经满足大部分情况,但是没考虑到现在很多动态图都是使用多张 ...

  2. JavaCV开发详解之3:通用拉流器实现,从流媒体服务器拉流rtsp/rtmp录制成视频文件

    JavaCV免费教程目录: JavaCV入门教程(免费JavaCV教程) javacv实战专栏目录(2016年更新至今): JavaCV实战专栏文章目录(2016年更新至今) 2022年最新JavaC ...

  3. javaCV开发详解之8:转封装在rtsp转rtmp流中的应用(无须转码,更低的资源消耗)

    JavaCV免费教程目录: JavaCV入门教程(免费JavaCV教程) javacv实战专栏目录(2016年更新至今): JavaCV实战专栏文章目录(2016年更新至今) 2022年最新JavaC ...

  4. JavaCV开发详解专栏文章目录(JavaCV速查手册)

    本章作为**JavaCV开发详解**专栏的目录. 为了方便大家分类查找,我们把分为两个目录: 第一个分类目录,根据文章技术类型进行分类. 第二个目录,按照博主更新顺序排列. 有些文章既是设备采集又实现 ...

  5. javacv开发详解之11补充篇:使用批量多张图片制作gif动态图,再也不用担心不会制作动态图了

    javacv实战专栏目录: JavaCV实战专栏文章目录(JavaCV速查手册) 前言 前面写过视频.桌面屏幕录制apng和gif动态图,虽然已经满足大部分情况,但是没考虑到现在很多动态图都是使用多张 ...

  6. JavaCV开发详解之32:使用filter滤镜实现中文字符叠加

    javacv实战专栏目录: JavaCV实战专栏文章目录(JavaCV速查手册) 前言 我们在 javaCV开发详解之13:使用FFmpeg Filter过滤器处理音视频中已经简单介绍过如何使用jav ...

  7. JavaCV开发详解之34:使用filter滤镜实现字符滚动和无限循环滚动字符叠加,跑马灯特效制作

    javacv实战专栏目录: JavaCV实战专栏文章目录(JavaCV速查手册) 前言 我们在 javaCV开发详解之13:使用FFmpeg Filter过滤器处理音视频中已经简单介绍过如何使用jav ...

  8. javacv开发详解补充篇:解决转流后视频画面快进慢放,时间跳动过大,监控视频时间戳重新计算pts和dts

    javacv实战专栏目录: JavaCV实战专栏文章目录(JavaCV速查手册) 前言 本篇文章主要用于javacv重新计算pts和dts时间戳. 解决由于没有pts和dts时间戳或者pts和dts时 ...

  9. JavaCV开发详解之29:使用javacv将多个视频拼接合成单个视频,多个音频拼接合成单个音频,以多个mp4视频合成一个mp4为例

    javacv实战专栏目录: JavaCV实战专栏文章目录(JavaCV速查手册) 前言 上一章中我们讲了多张图片合成视频,本章将再此基础上继续拓展,将多个视频/音频拼接合成一个视频/音频文件. 参考资 ...

  10. javaCV开发详解之5:录制音频(录制麦克风)到本地文件或推流到流媒体服务器(基于javax.sound、javaCV-FFMPEG)

    JavaCV免费教程目录: JavaCV入门教程(免费JavaCV教程) javacv实战专栏目录(2016年更新至今): JavaCV实战专栏文章目录(2016年更新至今) 2022年最新JavaC ...

最新文章

  1. 一文读懂微服务架构的重构策略
  2. 如何使用Leangoo管理Sprint Backlog
  3. 孙正义看未来30年:这个趋势,永远不会错(附完整PPT)
  4. [译] 最佳安全实践:在 Java 和 Android 中使用 AES 进行对称加密
  5. 8年javascript总结
  6. 使用golang的http模块构建redis读写查api
  7. Flink 容错机制:Checkpoints、Savepoints
  8. jmeter 循环使用csv数据_如何通过jmeter读取csv文件行数来设置循环控制器的总数...
  9. 设置MongoDB副本集分为4个步骤
  10. 虚拟机下Ubuntu配置IP地址和网段
  11. Python稳基修炼之计算机等级考试易错细节题4(含答案)
  12. vscode中如何拉取git代码_工具 | 手把手教你在VSCode中使用Git
  13. 根据pid查端口_PLC应用,3个PID控制实例讲解,想不会都难!
  14. ToolsOh第7批收录
  15. java与c互通aes加密解密
  16. POJ 1419-Graph Coloring
  17. android 自定义控件之AutoCompleteTextView邮箱后缀自动补全
  18. pada mysql
  19. python爬虫今日头条_python 简单爬取今日头条热点新闻(
  20. docker异常--docker bind: cannot assign requested address.

热门文章

  1. flash cs4 和 flex builder 联合开发
  2. 基于Cocos2d-x学习OpenGL ES 2.0之多纹理
  3. 玩转STM32(4)学会目录分类
  4. 计算机性能测评实验原理,实验一 计算机性能测试.pdf
  5. ubuntu系统计算机_显卡-性能测试软件
  6. 【mysql入门笔记02 2022.10.03】
  7. 打造全功能的NERO
  8. RabbitMQ03高级篇(消息可靠性投递,Consumer ACK,消费端限流,TTL, 通过代码创建队列和交换机以及绑定)
  9. 快压软件的彻底删除方法
  10. 解决Carsim2016找不Liscens问题