javacv使用筆記

javacv使用筆記

一.前言

最近在做一個視頻審覈的功能,但是運營覺得每個視頻都要看一篇太浪費時間了,於是提出了這樣一個需求,給每個視頻隨機截取5張圖片展示出來,根據這5張圖片決定是否需要繼續觀看視頻內容,以提高審覈效率。既然運營提出了這樣的需求,就得盡力去完成。

二.準備

首先從感性的角度分析該需求肯定可以實現的,畢竟軟件開發技術已經是相當成熟了。只是暫時不知道什麼技術可以實現該功能。於是,只能向度娘去請教了。經過一個時間的搜索發現有個叫javacv的開源框架似乎可以滿足我的需求,那麼就要花更多的時間去學習並動手實踐一下。

三.開始

1.首先創建一個maven工程,工程名隨意

 

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

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


這裏使用的是最新版本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<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)) {
                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<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;
    }
}


 

注:該段代碼只需要將main方法中的視頻源地址修改成自己的地址即可運行。

 

運氣還不錯,代碼能成功運行且能成功截圖。本以爲到此可以告一段落了,但經過幾次的測試發現一個問題,截取出來的圖片被旋轉了。這可不是我想要的結果啊,沒辦法,只能繼續去請教度娘。

 

4. 解決圖片旋轉問題

通過一段時間的搜索瞭解到,如果拍攝的視頻中帶有旋轉(rotate)信息,那麼截取出來的圖片就會被旋轉。通過查詢API發現FFmpegFrameGrabbergetVideoMetadata("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)可以實現IpImageFrame的相互轉換。

至此,基本滿足了所有需求,最終代碼如下:

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<Integer>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<Integer> random(int baseNum,int length) {

 

        List<Integer>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;

    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章