Java使用OpenCV3.2实现视频读取与播放
OpenCV从3.x版本开始其JAVA语言的SDK支持视频文件读写,这样就极大的方便了广大Java语言开发者学习与使用OpenCV,通过摄像头或者视频文件读取帧的内容与播放,完成视频内容分析与对象跟踪等各种应用开发任务。可以说OpenCV C++ SDK可以做到绝大多数事情,在OpenCV3.x版本上用Java都可以完成,这样就为很多Java开发者学习OpenCV打开了方便之门。
实现思路
首先用OpenCV相关API读取视频流或者视频文件的每一帧,然后通过Swing JComponent组件实现视频每一帧的更新显示,我模仿了C++的HIGHGUI里面创建窗口与显示图像接口,基于Swing实现了一个视频播放窗口类,把读取到的每一帧都传给它就可以实现连续显示即播放。每帧之间相隔100毫秒,我是通过Java线程Sleep方法实现。
运行效果 - USB摄像头读取每帧
运行效果 - 视频文件读取每帧
代码实现
视频文件读取
package com.gloomyfish.video.demo;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.videoio.VideoCapture;
public class VideoDemo {
public static void main(String[] args) {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
// 打开摄像头或者视频文件
VideoCapture capture = new VideoCapture();
//capture.open(0);
capture.open("D:/vcprojects/images/768x576.avi");
if(!capture.isOpened()) {
System.out.println("could not load video data...");
return;
}
int frame_width = (int)capture.get(3);
int frame_height = (int)capture.get(4);
ImageGUI gui = new ImageGUI();
gui.createWin("OpenCV + Java视频读与播放演示", new Dimension(frame_width, frame_height));
Mat frame = new Mat();
while(true) {
boolean have = capture.read(frame);
Core.flip(frame, frame, 1);// Win上摄像头
if(!have) break;
if(!frame.empty()) {
gui.imshow(conver2Image(frame));
gui.repaint();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static BufferedImage conver2Image(Mat mat) {
int width = mat.cols();
int height = mat.rows();
int dims = mat.channels();
int[] pixels = new int[width*height];
byte[] rgbdata = new byte[width*height*dims];
mat.get(0, 0, rgbdata);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
int index = 0;
int r=0, g=0, b=0;
for(int row=0; row<height; row++) {
for(int col=0; col<width; col++) {
if(dims == 3) {
index = row*width*dims + col*dims;
b = rgbdata[index]&0xff;
g = rgbdata[index+1]&0xff;
r = rgbdata[index+2]&0xff;
pixels[row*width+col] = ((255&0xff)<<24) | ((r&0xff)<<16) | ((g&0xff)<<8) | b&0xff;
}
if(dims == 1) {
index = row*width + col;
b = rgbdata[index]&0xff;
pixels[row*width+col] = ((255&0xff)<<24) | ((b&0xff)<<16) | ((b&0xff)<<8) | b&0xff;
}
}
}
setRGB( image, 0, 0, width, height, pixels);
return image;
}
/**
* A convenience method for setting ARGB pixels in an image. This tries to avoid the performance
* penalty of BufferedImage.setRGB unmanaging the image.
*/
public static void setRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) {
int type = image.getType();
if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB )
image.getRaster().setDataElements( x, y, width, height, pixels );
else
image.setRGB( x, y, width, height, pixels, 0, width );
}
}
视频与图像显示窗口类
package com.gloomyfish.video.demo;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JDialog;
public class ImageGUI extends JComponent {
/**
*
*/
private static final long serialVersionUID = 1L;
private BufferedImage image;
public ImageGUI() {
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
if(image == null) {
g2d.setPaint(Color.BLACK);
g2d.fillRect(0, 0, this.getWidth(), this.getHeight());
} else {
g2d.drawImage(image, 0, 0, this.getWidth(), this.getHeight(), null);
System.out.println("show frame...");
}
}
public void createWin(String title) {
JDialog ui = new JDialog();
ui.setTitle(title);
ui.getContentPane().setLayout(new BorderLayout());
ui.getContentPane().add(this, BorderLayout.CENTER);
ui.setSize(new Dimension(330, 240));
ui.setVisible(true);
}
public void createWin(String title, Dimension size) {
JDialog ui = new JDialog();
ui.setTitle(title);
ui.getContentPane().setLayout(new BorderLayout());
ui.getContentPane().add(this, BorderLayout.CENTER);
ui.setSize(size);
ui.setVisible(true);
}
public void imshow(BufferedImage image) {
this.image = image;
this.repaint();
}
}