使用Java的opencv中的网络摄像头流
我想在java应用程序中对我的网络摄像头进行流式处理,以获得一些图像处理的内容。我正在使用它附带的OpenCV和Java库文件 我学会了如何捕捉图像,但如何像视频一样连续捕捉和显示帧 请建议在下面的代码中进行修改或以其他方式进行修改 我正在使用JavaSwing应用程序开发使用Java的opencv中的网络摄像头流,java,swing,opencv,javacv,Java,Swing,Opencv,Javacv,我想在java应用程序中对我的网络摄像头进行流式处理,以获得一些图像处理的内容。我正在使用它附带的OpenCV和Java库文件 我学会了如何捕捉图像,但如何像视频一样连续捕捉和显示帧 请建议在下面的代码中进行修改或以其他方式进行修改 我正在使用JavaSwing应用程序开发 package openc; import org.opencv.core.*; public class openc { private JFrame frame; /** * Launch the applica
package openc;
import org.opencv.core.*;
public class openc {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
openc window = new openc();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public openc() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Canvas canvas = new Canvas();
frame.getContentPane().add(canvas, BorderLayout.CENTER);
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
VideoCapture camera = new VideoCapture(0);
if(!camera.isOpened()){
System.out.println("Error");
}
else {
Mat iframe = new Mat();
while(true){
if (camera.read(iframe)){
System.out.println("Frame Obtained");
System.out.println("Captured Frame Width " +
iframe.width() + " Height " + iframe.height());
while(true){
Highgui.imwrite(canvas, iframe);
}
}
}
}
camera.release();
}
}
我学会了如何捕捉图像,但如何像视频一样连续捕捉和显示帧
我从未使用过API,所以我对这个库一无所知。但是,我认为您的问题是由无限循环引起的典型线程阻塞问题:
while(true){ // infinite loop
if (camera.read(iframe)) {
System.out.println("Frame Obtained");
System.out.println("Captured Frame Width " +
iframe.width() + " Height " + iframe.height());
while(true) { // another infinite loop
Highgui.imwrite(canvas, iframe);
}
}
}
您有两个无限循环,它们阻塞了GUI,导致GUI没有响应。Swing是单线程的,您必须特别注意如何创建/更新Swing组件
在这种特殊情况下,我认为您可以使用一个线程在后台线程中定期读取相机数据,并在EDT中更新Canvas
对象。大概是这样的:
SwingWorker<Void, Mat> worker = new SwingWorker<Void, Mat>() {
@Override
protected Void doInBackground() throws Exception {
while(!isCancelled()) {
if (camera.read(iframe)) {
publish(iframe);
}
Thread.sleep(500); // prudential time to avoid block the event queue
}
return null;
}
@Override
protected void process(List<Mat> chunks) {
Mat lastFrame = chuncks.get(chunks.size() - 1);
Highgui.imwrite(canvas, lastFrame);
}
};
worker.execute();
SwingWorker-worker=新的SwingWorker(){
@凌驾
受保护的Void doInBackground()引发异常{
而(!isCancelled()){
if(摄像头读取(iframe)){
发布(iframe);
}
Thread.sleep(500);//避免阻塞事件队列的谨慎时间
}
返回null;
}
@凌驾
受保护的无效进程(列表块){
Mat lastFrame=chuncks.get(chunks.size()-1);
imwrite(canvas,lastFrame);
}
};
worker.execute();
dic19是正确的,您需要在SwingWorker中封装框架绘图和重新绘制Swing组件的过程。但是,我会避免使用Thread.sleep
和ImageIO
,因为Swing组件上的实际输出将执行不佳
因此,我建议进行以下更改:
1.:在SwingWorker的构造函数中初始化VideoCapture,并在doInBackground()方法的循环中移除睡眠:
2.:在渲染图像的Swing组件中,应使用System.arraycopy
。它比ImageIO
更快
public void updateImage(Mat matrix) {
int type = BufferedImage.TYPE_BYTE_GRAY;
if (matrix.channels() > 1) {
type = BufferedImage.TYPE_3BYTE_BGR;
}
byte[] b = new byte[matrix.channels() * matrix.cols() * matrix.rows()];
matrix.get(0, 0, b);
image = new BufferedImage(matrix.cols(), matrix.rows(), type);
final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arraycopy(b, 0, targetPixels, 0, b.length);
repaint();
}
最后,重写paintComponent()方法:
搜索示例,我相信您会在那里找到一些有用的东西。Highgui.imwrite(canvas,iframe);//甚至可能不会编译check JavaCV。也许你会在那里得到指导!嘿,谢谢,我喜欢你的想法,但在处理复杂的图像处理算法时,这会占用处理时间。有没有一种方法可以只使用opencv来实现这一点?正如我所说,我不知道这个API,所以我说不出来,但是如果你的目标是使用Swing显示图像/视频,那么你将不得不在某个时候处理。正如我看到的问题,你基本上需要两件事:1)通过输入流从相机读取数据(我猜OpenCV就是这样做的)。2) 相应地更新您的GUI。这两个任务可以(也应该)在不同的线程中完成,这就是为什么我建议SwingWorker@盖茨
public void updateImage(Mat matrix) {
int type = BufferedImage.TYPE_BYTE_GRAY;
if (matrix.channels() > 1) {
type = BufferedImage.TYPE_3BYTE_BGR;
}
byte[] b = new byte[matrix.channels() * matrix.cols() * matrix.rows()];
matrix.get(0, 0, b);
image = new BufferedImage(matrix.cols(), matrix.rows(), type);
final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arraycopy(b, 0, targetPixels, 0, b.length);
repaint();
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (image == null) {
return;
}
g.drawImage(this.image, 1, 1, this.image.getWidth(), this.image.getHeight(), null);
}