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

时间:2014-09-03 09:54:13

标签: java swing opencv javacv

我想在我的java应用程序中为我的网络摄像头流式传输一些图像处理内容。我正在使用随附的OpenCV和Java Library文件。

我有如何捕捉图像,但如何像视频一样连续捕捉和显示帧。

请建议修改以下代码或其他方法。

我正在使用Java Swing Application开发。

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

}

}

2 个答案:

答案 0 :(得分:2)

  

我有如何捕获图像,但如何像视频一样连续捕获和显示帧。

我从未使用过OpenCV 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);
        }
    }
} 

你有两个阻塞Event Dispatch Thread的无限循环导致你的GUI无法响应。 Swing是单线程的,您必须特别注意如何创建/更新Swing组件。

在这种特殊情况下,我认为您可以使用SwingWorker在后台线程中定期读取相机数据,并在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();

答案 1 :(得分:1)

dic19是正确的,您需要封装框架绘制过程并重新绘制SwingWorker中的Swing组件。但是我会避免Thread.sleepImageIO的使用,因为Swing组件上的实际输出会很差。

所以,我建议这些改变:

1:在SwingWorker的构造函数中初始化VideoCapture并在doInBackground()方法的循环中删除sleep:

@Override
protected Void doInBackground() throws Exception {
    Mat webcamImage = new Mat();
    while (!isCancelled()) {
        camera.read(webcamImage);
        if (!webcamImage.empty()) {
            videoPanel.updateImage(webcamImage);
        } else {
            break;
        }
    }

    return null;
}

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()方法:

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

搜索GitHub样本,我相信你会在那里找到有用的东西。