使用Java的opencv中的网络摄像头流

使用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

我想在java应用程序中对我的网络摄像头进行流式处理,以获得一些图像处理的内容。我正在使用它附带的OpenCV和Java库文件

我学会了如何捕捉图像,但如何像视频一样连续捕捉和显示帧

请建议在下面的代码中进行修改或以其他方式进行修改

我正在使用JavaSwing应用程序开发

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);
}