前言
上一节我们学习了使用OpenCV对图像进行一些基础操作,现在我们学习对视频进行一些基础的操作。
对视频的基本操作
从相机中读取视频
我们从电脑自带的摄像头捕捉一段视频并在屏幕上显示出来,代码如下:
import org.junit.jupiter.api.Test;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;
import org.opencv.videoio.VideoCapture;
import org.springframework.boot.test.context.SpringBootTest;
import java.net.URL;
import static org.opencv.highgui.HighGui.*;
import static org.opencv.highgui.HighGui.destroyAllWindows;
import static org.opencv.imgproc.Imgproc.cvtColor;
@SpringBootTest
class Demo2ApplicationTests {
@Test
public void testCamera() throws Exception{
System.setProperty("java.awt.headless","false");
URL url = ClassLoader.getSystemResource("lib/opencv/opencv_java451.dll");
System.load(url.getPath());
//创建一个 VideoCapture 对象
VideoCapture videoCapture = new VideoCapture(0);
//判断是否成功打开摄像机
if (!videoCapture.isOpened()){
throw new Exception("video open fail");
}
Mat image = new Mat();
int stopFlag;
//循环展示捕捉到的视频帧
while(true){
//捕捉、解码并返回下一个视频帧
videoCapture.read(image);
//将捕捉到的视频帧在屏幕上展现出来
imshow("frame",image);
//在10毫秒内等待用户事件
stopFlag = waitKey(10);
System.out.println(stopFlag);
if (stopFlag==27){
break;
}
}
//完成所有操作后,释放捕获器
videoCapture.release();
destroyAllWindows();
}
}
上面用到的一些新的方法我们来讲解一下他们的使用,如下:
- VideoCapture构造方法
这里我们是从摄像机捕捉视频的,所以这种情况下,我们会给出一个标识符,用于表示我们想要访问的摄像机,及其与操作系统的握手方式。对于摄像机而言,这个标志符就是一个标志数字——如果只有1个摄像机,那么就是0,如果系统中有多个摄像机,那么只要将其向上增加即可,如:1表示第二台摄像机,2表示第三台摄像机…以此类推。
定义如下:
//index为摄像机的标志符
public VideoCapture(int index);
- videoCapture.isOpened()方法
我们一般使用该方法来判断摄像机是否初始化,如果未初始化即返回false。 - videoCapture.read()方法
我们使用它来捕捉、解码并返回下一个视频帧,捕捉成功返回true,失败返回false。
该方法定义如下:
public boolean read(Mat image);
image即为返回的视频帧。
- videoCapture.release()方法
release()方法一般用来关闭视频文件或者摄像头。
该方法的定义如下:
public void release();
小插曲:
一开始我在waitKey()方法这里我跟着教程设置的是1毫秒内捕捉用户事件的,即:stopFlag = waitKey(1);,但是后面我一直在按Esc退出它都毫无反应,当时我的心情…
后面按了好多次才退出程序,想了想才发现原来这波是智商掉线,在1毫秒内触发事件,我得恰好在那1毫秒内按到Esc键,怪不得按了那么久才触发,后来改成10毫秒好了。
从文件播放视频
它与从相机捕获相同,只是用视频文件名更改摄像机索引,代码如下:
import org.junit.jupiter.api.Test;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;
import org.opencv.videoio.VideoCapture;
import org.springframework.boot.test.context.SpringBootTest;
import java.net.URL;
import static org.opencv.highgui.HighGui.*;
import static org.opencv.highgui.HighGui.destroyAllWindows;
@SpringBootTest
class Demo2ApplicationTests {
/**
* 读取本地文件的视频
* @throws Exception
*/
@Test
public void testCamera2() throws Exception{
System.setProperty("java.awt.headless","false");
URL url = ClassLoader.getSystemResource("lib/opencv/opencv_java451.dll");
URL videoUrl = ClassLoader.getSystemResource("video/test2.mp4");
System.load(url.getPath());
VideoCapture videoCapture = new VideoCapture(videoUrl.getPath());
if (!videoCapture.isOpened()){
throw new Exception("video open fail");
}
Mat image = new Mat();
while(videoCapture.isOpened()){
videoCapture.read(image);
if (image.empty()){
break;
}
imshow("frame",image);
waitKey(25);
}
videoCapture.release();
destroyAllWindows();
}
}
我们可以看到在读取本机的视频文件的时候,我们只要往VideoCapture的构造方法里面传视频文件的地址或者文件名就可以了。
注意:
在播放视频的时候waitKey()里面的值一般在25~30,此时是相当于正常倍速的播放,而值增大就相当于降低播放倍率,值减小就相当于增大播放倍率,我们可以灵活地运用它来调整视频的播放倍率。
保存视频
当我们使用摄像机捕捉了一个视频后我们想要将它保存下来怎么办,下面我们就来说说捕捉到视频后怎么将捕捉到的视频保存到计算机中。
import org.junit.jupiter.api.Test;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.videoio.VideoCapture;
import org.opencv.videoio.VideoWriter;
import org.springframework.boot.test.context.SpringBootTest;
import java.net.URL;
import static org.opencv.highgui.HighGui.*;
import static org.opencv.highgui.HighGui.destroyAllWindows;
@SpringBootTest
class Demo2ApplicationTests {
/**
* 将捕捉到的视频保存到本机
* @throws Exception
*/
@Test
public void testCamera3() throws Exception{
System.setProperty("java.awt.headless","false");
URL url = ClassLoader.getSystemResource("lib/opencv/opencv_java451.dll");
System.load(url.getPath());
VideoCapture videoCapture = new VideoCapture(0);
if (!videoCapture.isOpened()){
throw new Exception("video open fail");
}
int code = VideoWriter.fourcc('M','J','P','G');
Size size = new Size(640,480);
VideoWriter videoWriter = new VideoWriter("output.avi",code,20.0,size);
Mat image = new Mat();
int flag = -1;
while(flag!=27){
videoCapture.read(image);
Core.flip(image,image,0);
videoWriter.write(image);
imshow("frame",image);
flag = waitKey(50);
}
videoCapture.release();
videoWriter.release();
destroyAllWindows();
}
}
上面使用到的一些方法的使用:
- VideoWriter构造方法
上面的代码中我使用了VideoWriter的一个构造方法来进行VideoWriter对象的初始化,其定义如下:
public VideoWriter(String filename, int fourcc, double fps, Size frameSize);
其中filename是要输出文件的名字;
fourcc是编码的形式;
fps是输出视频的帧数;
frameSize是视频帧的长宽大小。
- VideoWriter.fourcc()方法
该方法的作用是连接4个字符生成一个fourcc编码,进而对输出的视频进行编码。
定义:
public static int fourcc(char c1, char c2, char c3, char c4);
具体不同编码对应的视频格式可以上网去查询。
- Size的构造方法
用来设置视频帧的长宽。
其定义如下:
public Size(double width, double height);
- Core.flip()方法
该方法的作用是对图像进行翻转,在上面的代码中它将视频帧进行了翻转,使得最终输出的视频是倒立的。
其定义如下:
public static void flip(Mat src, Mat dst, int flipCode);
src是输入的图像;
dst是输出的图像;
filipCode是指定如何翻转图像的标志,0图像向下翻转,正值(例如:1)图像向右翻转,负值(例如:-1)表示图像同时向下向右翻转。
- videoWriter.write()方法
该方法的作用是写入下一个视频帧,将显示图像保存成视频。
其定义如下:
public void write(Mat image);
image为待写入的视频帧。
- videoWriter.release()方法
关闭视频写入。
其定义如下:
public void release();