使用Java从网络摄像头中捕获图像?

86

如何从网络摄像头持续捕获影像?

我想通过实验使用物体识别(也许使用Java媒体框架)。

我想创建两个线程:

一个线程:

  • 节点1:捕获实时图像
  • 节点2:将图像保存为“1.jpg”
  • 节点3:等待5秒
  • 节点4:重复...

另一个线程:

  • 节点1:等待图像被捕获
  • 节点2:使用“1.jpg”获取每个像素的颜色
  • 节点3:将数据保存在数组中
  • 节点4:重复...

2
这是你的答案 - Java Swing程序捕获网络摄像头图像教程。稍作修改即可完成。 - Aman
16个回答

49

这个 JavaCV 实现很好。

代码:

import org.bytedeco.javacv.*;
import org.bytedeco.opencv.opencv_core.IplImage;

import java.io.File;

import static org.bytedeco.opencv.global.opencv_core.cvFlip;
import static org.bytedeco.opencv.helper.opencv_imgcodecs.cvSaveImage;

public class Test implements Runnable {
    final int INTERVAL = 100;///you may use interval
    CanvasFrame canvas = new CanvasFrame("Web Cam");

    public Test() {
        canvas.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
    }

    public void run() {

        new File("images").mkdir();

        FrameGrabber grabber = new OpenCVFrameGrabber(0); // 1 for next camera
        OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
        IplImage img;
        int i = 0;
        try {
            grabber.start();

            while (true) {
                Frame frame = grabber.grab();

                img = converter.convert(frame);

                //the grabbed frame will be flipped, re-flip to make it right
                cvFlip(img, img, 1);// l-r = 90_degrees_steps_anti_clockwise

                //save
                cvSaveImage("images" + File.separator + (i++) + "-aa.jpg", img);

                canvas.showImage(converter.convert(img));

                Thread.sleep(INTERVAL);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Test gs = new Test();
        Thread th = new Thread(gs);
        th.start();
    }
}

这里还有一篇有关JavaCV配置的文章

你可以修改代码,定期保存图像并进行其他任何你想要的处理。


4
+1 你太棒了!我正在寻找一个好的开源和支持的替代方案来在 Windows 和 Linux 上捕捉摄像头。这个方案非常完美!谢谢 :) - maple_shaft
2
对我来说不起作用,它显示了一个异常信息:“Exception in thread "main" java.lang.UnsatisfiedLinkError: C:\Users\steve\AppData\Local\Temp\javacpp213892357885346\jniopencv_core.dll: Can't find dependent libraries”。 - Stepan Yakovenko
这个可以运行,但视频质量不如应该的好。请查看我的答案以获得更好的视频输出质量。 - syb0rg
谢谢您的建议。我很感兴趣如何在Windows上设置它?我需要3GB的解压缩文件吗?否则,我的程序在Linux上使用JavaCV运行良好。 - Ilian Zapryanov
@StepanYakovenko 你需要安装OpenCV。 - Matthieu

36

我之前创建了一个通用的Java库,可以使用PC摄像头拍照。该API非常简单,不会有过多的功能,可以独立运行,还支持其他网络摄像头驱动程序,如OpenIMAJ、JMF、FMJ、LTI-CIVIL等,以及一些IP摄像头。

项目链接:https://github.com/sarxos/webcam-capture

示例代码(拍照并保存为test.jpg):

Webcam webcam = Webcam.getDefault();
webcam.open();
BufferedImage image = webcam.getImage();
ImageIO.write(image, "JPG", new File("test.jpg"));

它也可以在Maven Central Repository中找到,或者作为单独的ZIP包提供,其中包含所有必需的依赖项和第三方JAR文件。


1
为了方便入门,这个值得一看。代码对我来说很好用,希望你也是 :) - mrswadge
2
@JavaMan,你可以通过设置自定义Painter实例在显示来自相机的视图的面板(WebcamPanel)上绘制,也可以通过使用WebcamImageTransformer功能直接在来自相机的图像上绘制。有关更多详细信息,请在Github上的Webcam Capture项目页面上打开工单,因为我不想在Stack Overflow上详细解释这个问题(需要写太多内容,而且评论中可用的字符太少)。该项目可以在此处找到https://github.com/sarxos/webcam-capture - Bartosz Firyn
1
@Elyas Hadizadeh,在出现问题时,您可以随时在https://github.com/sarxos/webcam-capture上创建新的问题票证,在那里您还可以找到文档和示例。请还记住,这是针对相当熟悉Java的人的框架。如果您是Java新手,也有人愿意帮助,但您必须自己学习基础知识。 - Bartosz Firyn
@BartoszFiryn,我同意你的看法,我必须提高我的知识,感谢你的回复。 :-) - Elyas Hadizadeh
这是一个很棒的库。它涵盖了所有动态网络摄像头图片捕获的需求,甚至还具有运动检测功能。非常不错的选择。 - TaraW
显示剩余5条评论

7

5

这里有一个类似的问题,其中包含一些未被接受的答案。其中一个提到了FMJ作为JMF的Java替代品。


5

这与gt_ebuddy使用JavaCV的答案有关,但我的视频输出质量要高得多。我还添加了其他一些随机的改进(例如在按下 ESC CTRL + C 时关闭程序,并确保正确关闭程序使用的资源)。

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.KeyStroke;

import com.googlecode.javacv.CanvasFrame;
import com.googlecode.javacv.OpenCVFrameGrabber;
import com.googlecode.javacv.cpp.opencv_core.IplImage;

public class HighRes extends JComponent implements Runnable {
    private static final long serialVersionUID = 1L;

    private static CanvasFrame frame = new CanvasFrame("Web Cam");
    private static boolean running = false;
    private static int frameWidth = 800;
    private static int frameHeight = 600;
    private static OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);
    private static BufferedImage bufImg;

    public HighRes()
    {
        // setup key bindings
        ActionMap actionMap = frame.getRootPane().getActionMap();
        InputMap inputMap = frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);

        for (Keys direction : Keys.values())
        {
            actionMap.put(direction.getText(), new KeyBinding(direction.getText()));
            inputMap.put(direction.getKeyStroke(), direction.getText());
        }

        frame.getRootPane().setActionMap(actionMap);
        frame.getRootPane().setInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW, inputMap);

        // setup window listener for close action
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.addWindowListener(new WindowAdapter()
        {
            public void windowClosing(WindowEvent e)
            {
                stop();
            }
        });
    }

    public static void main(String... args)
    {
        HighRes webcam = new HighRes();
        webcam.start();
    }

    @Override
    public void run()
    {
        try
        {

            grabber.setImageWidth(frameWidth);
            grabber.setImageHeight(frameHeight);
            grabber.start();
            while (running)
            {

                final IplImage cvimg = grabber.grab();
                if (cvimg != null)
                {

                    // cvFlip(cvimg, cvimg, 1); // mirror

                    // show image on window
                    bufImg = cvimg.getBufferedImage();
                    frame.showImage(bufImg);
                }
            }
            grabber.stop();
            grabber.release();
            frame.dispose();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public void start()
    {
        new Thread(this).start();
        running = true;
    }

    public void stop()
    {
        running = false;
    }

    private class KeyBinding extends AbstractAction {

        private static final long serialVersionUID = 1L;

        public KeyBinding(String text)
        {
            super(text);
            putValue(ACTION_COMMAND_KEY, text);
        }

        @Override
        public void actionPerformed(ActionEvent e)
        {
            String action = e.getActionCommand();
            if (action.equals(Keys.ESCAPE.toString()) || action.equals(Keys.CTRLC.toString())) stop();
            else System.out.println("Key Binding: " + action);
        }
    }
}

enum Keys
{
    ESCAPE("Escape", KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0)),
    CTRLC("Control-C", KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK)),
    UP("Up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)),
    DOWN("Down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)),
    LEFT("Left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)),
    RIGHT("Right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));

    private String text;
    private KeyStroke keyStroke;

    Keys(String text, KeyStroke keyStroke)
    {
        this.text = text;
        this.keyStroke = keyStroke;
    }

    public String getText()
    {
        return text;
    }

    public KeyStroke getKeyStroke()
    {
        return keyStroke;
    }

    @Override
    public String toString()
    {
        return text;
    }
}

4

3
你可以尝试使用Marvin Framework。它提供了一个与相机交互的接口。此外,它还提供了一组实时视频处理功能,如目标跟踪和过滤。

快来看看吧!

实时视频处理演示:
http://www.youtube.com/watch?v=D5mBt0kRYvk

你可以使用下面的源代码。只需每5秒钟使用MarvinImageIO.saveImage()保存一帧即可。

网络摄像头视频演示:

public class SimpleVideoTest extends JFrame implements Runnable{

    private MarvinVideoInterface    videoAdapter;
    private MarvinImage             image;
    private MarvinImagePanel        videoPanel;

    public SimpleVideoTest(){
        super("Simple Video Test");
        videoAdapter = new MarvinJavaCVAdapter();
        videoAdapter.connect(0);
        videoPanel = new MarvinImagePanel();
        add(videoPanel);
        new Thread(this).start();
        setSize(800,600);
        setVisible(true);
    }
    @Override
    public void run() {
        while(true){
            // Request a video frame and set into the VideoPanel
            image = videoAdapter.getFrame();
            videoPanel.setImage(image);
        }
    }
    public static void main(String[] args) {
        SimpleVideoTest t = new SimpleVideoTest();
        t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

对于那些只想拍一张照片的人:

WebcamPicture.java

public class WebcamPicture {
    public static void main(String[] args) {
        try{
            MarvinVideoInterface videoAdapter = new MarvinJavaCVAdapter();
            videoAdapter.connect(0);
            MarvinImage image = videoAdapter.getFrame();
            MarvinImageIO.saveImage(image, "./res/webcam_picture.jpg");
        } catch(MarvinVideoInterfaceException e){
            e.printStackTrace();
        }
    }
}

3
我使用了Webcam Capture API。你可以从这里下载。
webcam = Webcam.getDefault();
webcam.open();

if (webcam.isOpen()) { //if web cam open 
    BufferedImage image = webcam.getImage();
    JLabel imageLbl = new JLabel();
    imageLbl.setSize(640, 480);             //show captured image
    imageLbl.setIcon(new ImageIcon(image));

    int showConfirmDialog = JOptionPane.showConfirmDialog(null, imageLbl, "Image Viewer", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, new ImageIcon(""));

    if (showConfirmDialog == JOptionPane.YES_OPTION) {
        JFileChooser chooser = new JFileChooser();
        chooser.setDialogTitle("Save Image");
        chooser.setFileFilter(new FileNameExtensionFilter("IMAGES ONLY", "png", "jpeg", "jpg")); //this file extentions are shown
        int showSaveDialog = chooser.showSaveDialog(this);
        if (showSaveDialog == 0) {                  //if pressed 'Save' button
            String filePath = chooser.getCurrentDirectory().toString().replace("\\", "/");
            String fileName = chooser.getSelectedFile().getName(); //get user entered file name to save
            ImageIO.write(image, "PNG", new File(filePath + "/" + fileName + ".png"));

        }
    }
}


你应该在代码旁边提供一些解释。 - fen1x
1
谢谢。这个更轻便,而且相比javacv,这个对我来说更好用。 - Lucke

3

我曾在一个视频会议应用中使用了JMF,它在两台笔记本电脑上表现良好:一台带有集成式摄像头,另一台带有旧的USB摄像头。在使用之前需要安装和配置JMF,但一旦完成,您可以通过Java代码轻松访问硬件。


2

http://grack.com/downloads/school/enel619.10/report/java_media_framework.html

在Swing应用程序中,可以轻松使用Player。以下代码创建了一个基于Swing的电视捕获程序,视频输出显示在整个窗口中:

import javax.media.*;
import javax.swing.*;
import java.awt.*;
import java.net.*;
import java.awt.event.*;
import javax.swing.event.*;

public class JMFTest extends JFrame {
    Player _player;
    JMFTest() {
        addWindowListener( new WindowAdapter() {
            public void windowClosing( WindowEvent e ) {
                _player.stop();
                _player.deallocate();
                _player.close();
                System.exit( 0 );
            }
        });
          setExtent( 0, 0, 320, 260 );
        JPanel panel = (JPanel)getContentPane();
        panel.setLayout( new BorderLayout() );
        String mediaFile = "vfw://1";
        try {
            MediaLocator mlr = new MediaLocator( mediaFile );
            _player = Manager.createRealizedPlayer( mlr );
            if (_player.getVisualComponent() != null)
            panel.add("Center", _player.getVisualComponent());
            if (_player.getControlPanelComponent() != null)
            panel.add("South", _player.getControlPanelComponent());
        }
        catch (Exception e) {
            System.err.println( "Got exception " + e );
        }
    }

    public static void main(String[] args) {
        JMFTest jmfTest = new JMFTest();
        jmfTest.show();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接