上次課,我們說明了《會跳薩日朗的火柴人》的思路,本小節我們實現第一步。就是讀取視訊檔,獲取每一幀對應的圖片。
學習本篇文章,需要你事先已經掌握Java基礎知識,比如變數、數據型別、方法、異常、IO操作等。
在java中的視訊操作,我們採用第三方的包。javacv是視覺領域常用的庫。在javacv封裝的ffmpeg包中,可以通過FFMpegFrameGrabber捕獲image數據和sample數據,而且捕獲的都是譯碼後的。
FFmpeg是一套可以用來記錄、轉換數位音訊、視訊,並能將其轉化爲流的開源計算機程式。
FFmpeg "這個單詞中的 "FF" 指的是 "Fast Forward ff + mpeg
MPEG(Moving Picture Experts Group,動態影象專家組)
Image是一個抽象類,BufferedImage是其實現類,是一個帶緩衝區影象類,主要作用是將一幅圖片載入到記憶體中(BufferedImage生成的圖片在記憶體裡有一個影象緩衝區,利用這個緩衝區我們可以很方便地操作這個圖片),提供獲得繪圖物件、影象縮放、選擇影象平滑度等功能,通常用來做圖片大小變換、圖片變灰、設定透明不透明等。 圖片只有載入到記憶體中才能 纔能進行進一步的處理。
提供read()和write()靜態方法,讀寫圖片,比以往的InputStream讀寫更方便。
讀取:
public static BufferedImage read(File input)
public static BufferedImage read(InputStream input)
public static BufferedImage read(ImageInputStream stream)
public static BufferedImage read(URL input)
寫出:
RenderedImage介面的子類是BufferedImage,因此在這裏可以直接出傳入BufferedImage的範例化物件,將BufferedImage物件直接寫出指定輸出流
public static boolean write(RenderedImage im,String formatName,File output)
public static boolean write(RenderedImage im, String formatName,OutputStream output)
public static boolean write(RenderedImage im, String formatName,ImageOutputStream output)
比如將圖片縮小比例儲存。
範例程式碼:
package day02.demo01;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Demo09_BufferedImage {
public static void main(String[] args) throws IOException {
/**
* BufferedImage類: Image是一個抽象類,BufferedImage是其實現類,是一個帶緩衝區影象類,
* 主要作用是將一幅圖片載入到記憶體中(BufferedImage生成的圖片在記憶體裡有一個影象緩衝區,
* 利用這個緩衝區我們可以很方便地操作這個圖片),提供獲得繪圖物件、影象縮放、選擇影象平滑度等功能,
* 通常用來做圖片大小變換、圖片變灰、設定透明不透明等。
*
* 圖片只有載入到記憶體中才能 纔能進行進一步的處理。
*
* RGB:R(紅)G(綠)B(藍)色彩模式是工業界的一種顏色標準。在Java中每個RGB畫素所佔的位數爲8.
*/
// 讀取本地一張圖片
File file = new File("C:\\Ruby\\pro\\aa\\kakaxi.jpg");// 本地圖片
System.out.println(file.exists());
BufferedImage image = (BufferedImage) ImageIO.read(file);
// 繼而可以對圖片進行操作,比如,獲得圖片的寬度:image.getWidth()
// 獲取影象的寬度和高度,原始寬度和高度
int width = image.getWidth();
int height = image.getHeight();
// 按照比例縮小
BufferedImage image2 = new BufferedImage(width / 2, height / 2, BufferedImage.TYPE_INT_BGR);// 表示具有8位元RGB顏色分量的影象
/**
* 繪製 縮小 後的圖片,如果想要放大圖片,就乘以 Graphics,圖形
*/
Graphics g = image2.getGraphics();
File file2 = new File("C:\\Ruby\\pro\\aa\\kakaxi2.jpg");
g.drawImage(image, 0, 0, width / 2, height / 2, null);
ImageIO.write(image2, "jpg", file2);
}
}
在本地C:\Ruby\pro\aa目錄下,就會有一張縮小了一倍多kakaxi2.jpg圖片。
首先準備好視訊檔,在本地C:\Ruby\薩日朗目錄下。然後需要建立一個File物件表示這個視訊檔,然後根據視訊檔物件,建立FFmpegFrameGrabber物件,就是按照視訊中每一幀進行抓取圖片的抓取物件。
然後可以獲取該視訊一共有多少幀。通過回圈,抓取每一幀的圖片,通過ImageIO將圖片進行儲存即可。
說明:需要先匯入第三方jar包。如圖:
然後建立一個java專案,並新建一個java檔案,命名爲:D1_VideoUtil.java
範例程式碼:
package demo;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
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;
/**
* 專案的第一步:讀取薩日朗的視訊檔,獲取每一幀的圖片
* @author ruby
*
*/
public class D1_VideoUtil {
public static void main(String[] args) {
//1.要讀取的視訊檔路徑
String videoPath = "C:\\Ruby\\薩日朗\\薩日朗原視訊.wmv";
//2.圖片要儲存的目錄位置
String picPath = "C:\\Ruby\\薩日朗\\視訊幀\\";
File video = new File(videoPath);
getVideoPic(video, picPath);
}
/**
* 根據讀取到的視訊檔,獲取視訊中的每一幀圖片
* @param video 視訊檔
* @param picPath 圖片的儲存路徑
*/
public static void getVideoPic(File video,String picPath){
//1.根據一個視訊檔,建立一個按照視訊中每一幀進行抓取圖片的抓取物件
FFmpegFrameGrabber ff = new FFmpegFrameGrabber(video);
try {
ff.start();
//抓每一幀圖片
//2.先知道這個視訊一共有多少幀
int length = ff.getLengthInFrames();
System.out.println(length);
//3.讀取視訊中每一幀圖片
Frame frame = null;
for(int i=0;i<length;i++){
frame = ff.grabFrame();
// System.out.println(frame);
if(frame.image == null){
System.out.println("空"+i);
continue;
}
//將獲取的幀,儲存爲圖片
Java2DFrameConverter converter = new Java2DFrameConverter();//建立一個幀-->圖片的轉換器
BufferedImage image = converter.getBufferedImage(frame);//轉換
String img = picPath+i+".jpg";
System.out.println(img);
File picFile = new File(img);
//將圖片儲存到目標檔案中
ImageIO.write(image, "jpg", picFile);
}
ff.stop();
} catch (Exception e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
執行結果如下:
因爲上課需要和學生的操作系統,所以我在自己的mac電腦上安裝了windows虛擬機器。只有一個C槽。
在本地硬碟上:建立目錄結構:C:\Ruby\薩日朗\視訊幀
我們可以看到在該目錄下,已經儲存了從視訊中讀取到的這些圖片。