前言
查看了相關文章然後一筆一筆打代碼再調試成功出結果,
eguid的博客
不保證代碼能夠原封不動就能運行,
這裏做一下記錄。
ps:代碼內容有改動,原版的可以看原作者的。
代碼內容
package net.w2p.JCVStudio.zhiboStudy;
/**
* 前言:
* 鑑於很多同學反饋目前javacv採集攝像頭存在幾點問題
*
* 1、javacv採集攝像頭幀率很低
*
* 2、javacv中的攝像頭採集依賴opencv的capture採集器,獲取的Mat沒有及時釋放,容易內存溢出
*
* 3、javacv封裝的太死,調用攝像頭不靈活,無法遍歷攝像頭設備列表
*
* 4、javacv打開攝像頭太慢,一般要3秒才能打開攝像頭設備
*
* 所以直接使用opencv採集攝像頭設備是一個比較好的方案,並且採集效率上得到了很大的提高,不會像javacv裏面一樣攝像頭掉幀比較嚴重。
* ————————————————
* 版權聲明:本文爲CSDN博主「本博客已停止維護!-eguid」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
* 原文鏈接:https://blog.csdn.net/eguid_1/article/details/58027720
* 一、實現的功能
*
*
* (1)opencv原生攝像頭圖像採集
*
* (2)opencv原生攝像頭設備遍歷
*
* (3)Mat轉換爲Frame
*
* (4)計算實時幀率
*
* (5)文字水印(顯示實時幀率)
* **/
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.*;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.Point;
import org.bytedeco.opencv.opencv_core.Scalar;
import org.bytedeco.opencv.opencv_videoio.VideoCapture;
import javax.swing.*;
import java.text.DecimalFormat;
/***
* 第一課,遍歷調用攝像頭並且:
* 01 顯示原始圖像
* 02 將原始頭像添加上水印文字
* 03 將原始圖像加文字以後用推流器保存到本地。
*
* ***/
public class Lesson01 {
private static final Double FRAME_RATE = 25.0;
final Double imageTime = 0.04*1000;
long startTime = System.currentTimeMillis();
/**
* 無水印,無幀率計算實現:
* **/
public void study01(){
VideoCapture vc=null;
//遍歷查找攝像頭
int index=-1;
for(;index<2;index++){
vc=new VideoCapture(index);
if(vc.grab()){
//找到攝像頭設備,退出遍歷
System.err.println("當前攝像頭:"+index);
break;
}
vc.close();//沒找到設備,釋放資源
}
//vc爲null,並且設備沒正常開啓,說明沒找到設備
if(vc!=null&&!vc.isOpened()){
System.err.println("無法找到攝像頭,請檢查是否存在攝像頭設備");
return;
}
//使用java的JFrame顯示圖像
CanvasFrame cFrame = new CanvasFrame("做好自己!--eguid!http://www.eguid.cc/",CanvasFrame.getDefaultGamma()/2.2);
//javacv提供的轉換器,方便mat轉換爲Frame
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
Mat mat=new Mat();
for(;;){
vc.retrieve(mat);//重新獲取mat
if(vc.grab()){//是否採集到攝像頭數據
if(vc.read(mat)){//讀取一幀mat圖像
// opencv_highgui.imshow("eguid", mat);該opencv方法windows下會無響應
cFrame.showImage(converter.convert(mat));
}
mat.release();//釋放mat
}
try {
Thread.sleep(45);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/***
* 調用攝像頭,添加水印文字。
* **/
public void study02(){
//做好自己!--eguid!http://www.eguid.cc
String msg="fps:";//水印文字
// 水印文字位置
Point point = new Point(10, 50);
// 顏色,使用黃色
Scalar scalar = new Scalar(0, 255, 255, 0);
DecimalFormat df=new DecimalFormat(".##");//數字格式化
VideoCapture vc=null;
//遍歷查找攝像頭
int index=-1;
for(;index<2;index++){
vc=new VideoCapture(index);
if(vc.grab()){
//找到攝像頭設備,退出遍歷
System.err.println("做好自己!--eguid溫馨提示,獲取本機當前攝像頭序號:"+index);
break;
}
vc.close();//沒找到設備,釋放資源
}
//vc爲null,並且設備沒正常開啓,說明沒找到設備
if(vc!=null&&!vc.isOpened()){
System.err.println("無法找到攝像頭,請檢查是否存在攝像頭設備");
return;
}
//使用java的JFrame顯示圖像
CanvasFrame cFrame = new CanvasFrame("做好自己!--eguid!http://www.eguid.cc",
CanvasFrame.getDefaultGamma()/2.2);
cFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
cFrame.setAlwaysOnTop(true);
//javacv提供的轉換器,方便mat轉換爲Frame
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
Mat mat=new Mat();
double start=System.currentTimeMillis();
double end;
Frame ftmp=null;
for(int i=0;;i++){
ftmp=null;
vc.retrieve(mat);//重新獲取mat
if(vc.grab()){//是否採集到攝像頭數據
if(vc.read(mat)){//讀取一幀mat圖像
end=System.currentTimeMillis();
if(mat!=null){
opencv_imgproc.putText(mat,msg+df.format((1000.0/(end-start))),
point, opencv_imgproc.CV_FONT_VECTOR0, 1.2, scalar,
1, 20, false);
}
// opencv_highgui.imshow("eguid", mat);該opencv方法windows下會無響應
ftmp=converter.convert(mat);
cFrame.showImage(ftmp);
System.err.println(i);
start=end;
}
mat.release();//釋放mat
}
if(ftmp!=null){
//--導出到視頻中區。
}
if (!cFrame.isDisplayable()||!cFrame.isActive()||i>100) {//窗口是否關閉
System.out.println("窗口關閉啦,請做收尾工作");
// grabber.stop();//停止抓取
if(ftmp!=null){
}
System.exit(-1);//退出
return;
}
}
}
/***
* 添加水印並且導出爲一個MP4文件。
*
* **/
public void study03() throws Exception {
//做好自己!--eguid!http://www.eguid.cc
String msg="fps:";//水印文字
// 水印文字位置
Point point = new Point(10, 50);
// 顏色,使用黃色
Scalar scalar = new Scalar(0, 255, 255, 0);
DecimalFormat df=new DecimalFormat(".##");//數字格式化
VideoCapture vc=null;
//遍歷查找攝像頭
int index=-1;
for(;index<2;index++){
vc=new VideoCapture(index);
if(vc.grab()){
//找到攝像頭設備,退出遍歷
System.err.println("做好自己!--eguid溫馨提示,獲取本機當前攝像頭序號:"+index);
break;
}
vc.close();//沒找到設備,釋放資源
}
//vc爲null,並且設備沒正常開啓,說明沒找到設備
if(vc!=null&&!vc.isOpened()){
System.err.println("無法找到攝像頭,請檢查是否存在攝像頭設備");
return;
}
//使用java的JFrame顯示圖像
CanvasFrame cFrame = new CanvasFrame("做好自己!--eguid!http://www.eguid.cc",
CanvasFrame.getDefaultGamma()/2.2);
cFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
cFrame.setAlwaysOnTop(true);
//javacv提供的轉換器,方便mat轉換爲Frame
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
Mat mat=new Mat();
double start=System.currentTimeMillis();
double end;
Frame ftmp=null;
Java2DFrameConverter converter1 = new Java2DFrameConverter();
OpenCVFrameConverter.ToIplImage converter2 = new OpenCVFrameConverter.ToIplImage();
final String outputFilePath="/home/too-white/temp/001_study03.flv";
FFmpegFrameRecorder recorder = null;
for(int i=0;;i++){
ftmp=null;
vc.retrieve(mat);//重新獲取mat
if(vc.grab()){//是否採集到攝像頭數據
if(vc.read(mat)){//讀取一幀mat圖像
end=System.currentTimeMillis();
if(mat!=null){
opencv_imgproc.putText(mat,msg+df.format((1000.0/(end-start))),
point, opencv_imgproc.CV_FONT_VECTOR0, 1.2, scalar,
1, 20, false);
}
// opencv_highgui.imshow("eguid", mat);該opencv方法windows下會無響應
ftmp=converter.convert(mat);
// Frame rotatedFrame=converter.convert(grabbedImage);//不知道爲什麼這裏不做轉換就不能推到rtmp
if(recorder==null){
recorder=
new FFmpegFrameRecorder(outputFilePath,
ftmp.imageWidth,ftmp.imageHeight);
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // avcodec.AV_CODEC_ID_H264,編碼
// recorder.setFormat("flv");
recorder.setFormat("flv");//封裝格式,如果是推送到rtmp就必須是flv封裝格式
recorder.setPixelFormat(0);
int frameRate=25;
recorder.setFrameRate(frameRate);
try {
recorder.start();
startTime=System.currentTimeMillis();
}
catch (Exception ed){
ed.printStackTrace();
}
}
cFrame.showImage(ftmp);
/***計算幀的時間**/
Double imageFrameSpendTime=(1/recorder.getFrameRate())*1000;
long time = 1000*(System.currentTimeMillis() - startTime
+ imageFrameSpendTime.longValue()*i
);
if (time > recorder.getTimestamp()) {
System.out.println("時間>===record時間。");
recorder.setTimestamp(time);
}
recorder.record(ftmp);
System.err.println(i);
start=end;
}
mat.release();//釋放mat
}
if(ftmp!=null){
//--導出到視頻中區。
}
if (!cFrame.isDisplayable()||!cFrame.isActive()||i>100) {//窗口是否關閉
if(recorder!=null){
recorder.stop();
}
System.out.println("窗口關閉啦,請做收尾工作");
// grabber.stop();//停止抓取
if(ftmp!=null){
}
System.exit(-1);//退出
return;
}
}
}
public static void main(String[] args) throws Exception{
Lesson01 test=new Lesson01();
test.study03();
}
}