首先要是Maven项目,然后导入JavaCV的相关jar包,即在pom.xml文件加入以下配置:
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>opencv-platform</artifactId>
<version>3.4.1-1.4.1</version>
</dependency>
<dependency>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>ffmpeg-platform</artifactId>
<version>3.4.2-1.4.1</version>
</dependency>
封装好的工具类 (JavacvUtils):
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import org.apache.commons.io.FileUtils;
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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.utils.gif.AnimatedGifEncoder;
public class JavacvUtils {
private static final Logger log = LoggerFactory.getLogger(JavacvUtils.class);
private static final String IMAGEMAT = "jpg";
private static final String ROTATE = "rotate";
private static final Integer GIF_FRAME_NUMBER = 3;
private static final Integer GIF_FRAME_INTERVAL = 50;
public static void main(String[] args) throws Exception {
makePicFromVideo("C:/Users/admin/Desktop/VID_20180605_165453.mp4", "d://test2.jpg");
makeGifFromVideo("C:/Users/admin/Desktop/VID_20180605_165453.mp4", "d://test2.gif");
}
public static void makeGifFromVideo(String filePath, String targetPath) throws Exception {
String picList[] = new String[GIF_FRAME_NUMBER];
int index = targetPath.lastIndexOf(".");
String prefix = targetPath.substring(0, index);
// 生成多个图片
for (int i = 0; i < GIF_FRAME_NUMBER; i++) {
String temTargetPath = prefix + "_" + i + "." + IMAGEMAT;
picList[i] = temTargetPath;
}
FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);
ff.start();
String rotate = ff.getVideoMetadata(ROTATE);
double ffLength = getDivideValue(ff.getLengthInTime(), 1000000);
log.info("视频旋转度:" + rotate + " 视频时长:" + ffLength);
int frameLength = ff.getLengthInFrames();
int j = 0;
for (int i = 0; i < frameLength && j < GIF_FRAME_NUMBER; i++) {
if (i % GIF_FRAME_INTERVAL == 0) {
Frame f = ff.grabImage();
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
IplImage src = converter.convert(f);
if (null != rotate && rotate.length() > 1) {
f = converter.convert(rotate(src, Integer.valueOf(rotate)));
}
makePicFormFrame(f, picList[j]);
j++;
}
}
ff.stop();
// 合并为一个图片
jpgToGif(picList, targetPath);
// 删除之前的图片
for (int i = 0; i < GIF_FRAME_NUMBER; i++) {
FileUtils.deleteQuietly(new File(picList[i]));
}
}
/**
* 将多个jpg图片合并为一个gif图片
*
*/
private static void jpgToGif(String pic[], String newPic) {
AnimatedGifEncoder encoder = new AnimatedGifEncoder();
encoder.setRepeat(0);
encoder.start(newPic);
BufferedImage src[] = new BufferedImage[pic.length];
for (int i = 0; i < src.length; i++) {
encoder.setDelay(200); // 设置播放的延迟时间
try {
src[i] = ImageIO.read(new File(pic[i]));
} catch (IOException e) {
log.error("图片读取异常", e);
} // 读入需要播放的jpg文件
encoder.addFrame(src[i]); // 添加到帧中
}
encoder.finish();
}
public static void makePicFromVideo(String filePath, String targetPath) throws Exception {
FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);
ff.start();
String rotate = ff.getVideoMetadata(ROTATE);
double ffLength = getDivideValue(ff.getLengthInTime(), 1000000);
log.info("视频旋转度:" + rotate + " 视频时长:" + ffLength);
Frame f = ff.grabImage();
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
IplImage src = converter.convert(f);
if (null != rotate && rotate.length() > 1) {
f = converter.convert(rotate(src, Integer.valueOf(rotate)));
}
makePicFormFrame(f, targetPath);
ff.stop();
}
/**
* 旋转图片
*
*/
public static IplImage rotate(IplImage src, int angle) {
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;
}
/**
* 生成缩略图
*
*/
public static void makePicFormFrame(Frame f, String targetPath) {
if (null == f || null == f.image) {
return;
}
Java2DFrameConverter converter = new Java2DFrameConverter();
BufferedImage bi = converter.getBufferedImage(f);
BufferedImage newbi = scaleImage(bi, 800, 800, IMAGEMAT);
File output = new File(targetPath);
try {
ImageIO.write(newbi, IMAGEMAT, output);
} catch (IOException e) {
log.error("生成缩略图失败", e);
}
}
/**
* 根据比例处理图片
*
*/
public static BufferedImage scaleImage(BufferedImage bufferedImage, int width, int height, String format) {
ArrayList<Integer> paramsArrayList = getAutoWidthAndHeight(bufferedImage, width, height);
width = paramsArrayList.get(0);
height = paramsArrayList.get(1);
log.info("自动调整比例,width=" + width + " height=" + height);
Image image = bufferedImage.getScaledInstance(width, height, Image.SCALE_DEFAULT);
BufferedImage outputImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics graphics = outputImage.getGraphics();
graphics.drawImage(image, 0, 0, null);
graphics.dispose();
return outputImage;
}
/***
* @param bufferedImage
* 要缩放的图片对象
* @param widthScale
* 要缩放到的宽度
* @param heightScale
* 要缩放到的高度
* @return 一个集合,第一个元素为宽度,第二个元素为高度
*
*/
private static ArrayList<Integer> getAutoWidthAndHeight(BufferedImage bufferedImage, int widthScale,
int heightScale) {
ArrayList<Integer> arrayList = new ArrayList<Integer>();
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
double scaleW = getDivideValue(widthScale, width);
double scaleH = getDivideValue(heightScale, height);
if (scaleW < scaleH) {
arrayList.add(parseDoubleToInt(scaleW * width));
arrayList.add(parseDoubleToInt(scaleW * height));
} else {
arrayList.add(parseDoubleToInt(scaleH * width));
arrayList.add(parseDoubleToInt(scaleH * height));
}
return arrayList;
}
/**
* 将double类型的数据转换为int
*
*/
private static int parseDoubleToInt(double sourceDouble) {
return (int) sourceDouble;
}
/**
* 获取两数相除的结果,保留两位小数
*
*/
public static double getDivideValue(int num1, int num2) {
BigDecimal bigDecimal1 = new BigDecimal(num1);
BigDecimal bigDecimal2 = new BigDecimal(num2);
BigDecimal result = bigDecimal1.divide(bigDecimal2, 2, BigDecimal.ROUND_HALF_UP);
return result.doubleValue();
}
/**
* 获取两数相除的结果,保留两位小数
*
*/
public static double getDivideValue(long num1, long num2) {
BigDecimal bigDecimal1 = new BigDecimal(num1);
BigDecimal bigDecimal2 = new BigDecimal(num2);
BigDecimal result = bigDecimal1.divide(bigDecimal2, 2, BigDecimal.ROUND_HALF_UP);
return result.doubleValue();
}
}
将多个图片制作为gif图片,需要用的工具类(AnimatedGifEncoder、LZWEncoder、NeuQuant):
package com.utils.gif;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.BufferedOutput