javacv使用笔记

javacv使用笔记javacv 使用笔记一 前言最近在做一个视频审核的功能 但是运营觉得每个视频都要看一篇太浪费时间了 于是提出了这样一个需求 给每个视频随机截取 5 张图片展示出来 根据这 5 张图片决定是否需要继续观看视频内容 以提高审核效率 既然运营提出了这样的需求 就得尽力去完成 二 准备首先从感性的角度分析该需求肯定可以实现的 毕竟软件开发技术已经是相当成熟了 只是暂时不知道什么技术可以实现该功

javacv使用笔记

一.前言

最近在做一个视频审核的功能,但是运营觉得每个视频都要看一篇太浪费时间了,于是提出了这样一个需求,给每个视频随机截取5张图片展示出来,根据这5张图片决定是否需要继续观看视频内容,以提高审核效率。既然运营提出了这样的需求,就得尽力去完成。

二.准备

首先从感性的角度分析该需求肯定可以实现的,毕竟软件开发技术已经是相当成熟了。只是暂时不知道什么技术可以实现该功能。于是,只能向度娘去请教了。经过一个时间的搜索发现有个叫javacv的开源框架似乎可以满足我的需求,那么就要花更多的时间去学习并动手实践一下。

三.开始

1.首先创建一个maven工程,工程名随意

2. 引入javacv需求的jar包,在pom.xml文件中添加

                  org.bytedeco                javacv-platform                1.3.1             

这里使用的是最新版本1.3.1

3. 从百度上搜索到一段代码

package com.javacv.test; 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 javax.imageio.ImageIO; import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.FrameGrabber.Exception; import org.bytedeco.javacv.Java2DFrameConverter; public abstract class FrameGrabberKit { public static void main(String[] args) throws Exception { // randomGrabberFFmpegImage("e:/ffmpeg/aa.mp4", "./target", "screenshot", 5); randomGrabberFFmpegImage("e:/ffmpeg/ffmpeg.mp4", "./target", "screenshot", 5); } public static void randomGrabberFFmpegImage(String filePath, String targerFilePath, String targetFileName, int randomSize) throws Exception { FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath); ff.start(); int ffLength = ff.getLengthInFrames(); List       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)) { doExecuteFrame(f, targerFilePath, targetFileName, i); } if (i >= maxRandomGrab) { break; } i++; } ff.stop(); } public static void doExecuteFrame(Frame f, String targerFilePath, String targetFileName, int index) { if (null == f || null == f.image) { return; } Java2DFrameConverter converter = new Java2DFrameConverter(); String imageMat = "png"; String FileName = targerFilePath + File.separator + targetFileName + "_" + index + "." + imageMat; BufferedImage bi = converter.getBufferedImage(f); File output = new File(FileName); try { ImageIO.write(bi, imageMat, output); } catch (IOException e) { e.printStackTrace(); } } public static List         random(int baseNum, int length) { List           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; } }            

注:该段代码只需要将main方法中的视频源地址修改成自己的地址即可运行。

 

运气还不错,代码能成功运行且能成功截图。本以为到此可以告一段落了,但经过几次的测试发现一个问题,截取出来的图片被旋转了。这可不是我想要的结果啊,没办法,只能继续去请教度娘。

 

4. 解决图片旋转问题

通过一段时间的搜索了解到,如果拍摄的视频中带有旋转(rotate)信息,那么截取出来的图片就会被旋转。通过查询API发现FFmpegFrameGrabber的getVideoMetadata(“rotate”)方法可以获取到视频的旋转信息。根据获取到的rotate信息对ff.grabImage()得到的Frame进行旋转,但是Frame并没有提供旋转接口。但有一个IpImage对象提供了旋转方法

public static IplImage rotate(IplImage src, int rotate) { IplImage img = IplImage.create(src.height(), src.width(), src.depth(), src.nChannels()); opencv_core.cvTranspose(src, img); opencv_core.cvFlip(img, img, angle); return img; } 

那么现在需要解决的就是把Frame转换成IpImage,旋转后在转回Frame。

再次查看API发现OpenCVFrameConverter.ToIplImage提供了相互转换的接口

OpenCVFrameConverter.ToIplImageconverter =new OpenCVFrameConverter.ToIplImage();

converter有两个重载的方法converter(IplImage img)和converter(Frame frame)可以实现IpImage和Frame的相互转换。

至此,基本满足了所有需求,最终代码如下:

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 javax.imageio.ImageIO;

import org.bytedeco.javacpp.opencv_core;

import org.bytedeco.javacpp.opencv_core.IplImage;

import org.bytedeco.javacv.FFmpegFrameGrabber;

import org.bytedeco.javacv.Frame;

import org.bytedeco.javacv.FrameGrabber.Exception;

import org.bytedeco.javacv.Java2DFrameConverter;

import org.bytedeco.javacv.OpenCVFrameConverter;

 

public abstract class FrameGrabberKit {

 

    public static void main(String[]args)throws Exception {

//        randomGrabberFFmpegImage(“e:/ffmpeg/aa.mp4″, “./target”, “screenshot“, 5);

    randomGrabberFFmpegImage(“e:/ffmpeg/ffmpeg.mp4”,“./target”,screenshot, 5);

    }

 

     

    public static void randomGrabberFFmpegImage(StringfilePath, StringtargerFilePath, StringtargetFileName,int randomSize)

            throws Exception {

        FFmpegFrameGrabberff = FFmpegFrameGrabber.createDefault(filePath);

        ff.start();

        Stringrotate =ff.getVideoMetadata(“rotate”);

        

        int ffLength =ff.getLengthInFrames();

        List
randomGrab =random(ffLength,randomSize);

        int maxRandomGrab =randomGrab.get(randomGrab.size() – 1);

        Framef;

        int i = 0;

        while (i <ffLength) {

            f =ff.grabImage();

            if (randomGrab.contains(i)) {

            if(null !=rotate &&rotate.length() > 1) {

                OpenCVFrameConverter.ToIplImageconverter =new OpenCVFrameConverter.ToIplImage();

                    IplImagesrc =converter.convert(f);

                    f =converter.convert(rotate(src, Integer.valueOf(rotate)));

                }

                doExecuteFrame(f,targerFilePath,targetFileName,i);

            }

            if (i >=maxRandomGrab) {

                break;

            }

            i++;

        }

        ff.stop();

    }

    

    public static IplImage rotate(IplImage src,int angle) {

        IplImageimg = IplImage.create(src.height(),src.width(),src.depth(),src.nChannels());

        opencv_core.cvTranspose(src,img);

        opencv_core.cvFlip(img,img,angle);

        return img;

    }

 

    public static void doExecuteFrame(Framef, StringtargerFilePath, StringtargetFileName,int index) {

        if (null ==f ||null ==f.image) {

            return;

        }

         

        Java2DFrameConverterconverter =new Java2DFrameConverter();

        StringimageMat =“png”;

        StringFileName =targerFilePath + File.separator +targetFileName +“_” +index +“.” +imageMat;

        BufferedImagebi =converter.getBufferedImage(f);

        Fileoutput =new File(FileName);

        try {

            ImageIO.write(bi,imageMat,output);

        }catch (IOExceptione) {

            e.printStackTrace();

        }

    }

 

    public static List

random(
int baseNum,int length) {

 

        List
list =new ArrayList<>(length);

        while (list.size() < length) {

            Integernext = (int) (Math.random() *baseNum);

            if (list.contains(next)) {

                continue;

            }

            list.add(next);

        }

        Collections.sort(list);

        return list;

    }

}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/206910.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午3:13
下一篇 2026年3月19日 下午3:13


相关推荐

  • mongodb启动以及基本命令操作

    mongodb启动以及基本命令操作monggodb 启动以及基本命令操作介绍 MongoDB 是一个基于分布式文件存储 1 的数据库 由 C 语言编写 旨在为 WEB 应用提供可扩展的高性能数据存储解决方案 MongoDB 是一个介于关系数据库和非关系数据库之间的产品 是非关系数据库当中功能最丰富 最像关系数据库的 它支持的数据结构非常松散 是类似 json 的 bson 格式 因此可以存储比较复杂的数据类型 Mongo 最大的特点是它支持的查询语言非常强大 其语法有点类似于面向对象的查询语言 几乎可以实现类似关系数据库单表查询的绝大部分功能

    2026年3月19日
    2
  • java string与stringbuffer的区别_string类和stringbuilder类的区别

    java string与stringbuffer的区别_string类和stringbuilder类的区别简单地说,就是一个变量和常量的关系。StringBuffer对象的内容可以修改;而String对象一旦产生后就不可以被修改,重新赋值其实是两个对象。StringBuffer的内部实现方式和String不同,StringBuffer在进行字符串处理时,不生成新的对象,在内存使用上要优于String类。所以在实际使用时,如果经常需要对一个字符串进行修改,例如插入、删除等操作,使用StringBuff…

    2025年12月8日
    4
  • n8n AI Agent节点完全指南:从入门到精通

    n8n AI Agent节点完全指南:从入门到精通

    2026年3月15日
    2
  • 圆周率3000万亿位_圆周率背诵口诀完整版

    圆周率3000万亿位_圆周率背诵口诀完整版展开全部圆周率3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895…

    2025年11月10日
    6
  • PhpSpreadsheet_中文在线集团简介

    PhpSpreadsheet_中文在线集团简介1、PhpSpreadsheet是什么PhpSpreadsheet是一个用纯PHP编写的库,提供了一组类,使您可以读取和写入不同的电子表格文件格式PhpSpreadsheet提供了丰富的API接口,可以设置诸多单元格以及文档属性,包括样式、图片、日期、函数等等诸多应用,总之你想要什么样的Excel表格,PhpSpreadsheet都能做到使用PhpSpreadsheet开发的PHP要求7.1或更高版本PhpSpreadsheet支持链式操作2、PhpSpreadsheet支持的文件格式

    2025年12月15日
    4
  • C# winform 获取当前路径

    C# winform 获取当前路径

    2021年8月11日
    60

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号