JavaCV实战之调用摄像头基础详解

JavaCV实战之调用摄像头基础详解

简介

JavaCV是一个基于OpenCV的Java Wrapper,它允许Java开发人员快速简单地实现计算机视觉和图形处理任务。其中,JavaCV可以通过调用摄像头来实现很多有趣的功能。

基础流程

JavaCV实战之调用摄像头基础详解的流程大致如下:

  1. 配置JavaCV环境:下载并安装JavaCV(包括OpenCV的动态库),配置IDE环境。
  2. 初始化摄像头:选定要使用的摄像头,打开并进行初始化。
  3. 捕获帧数据:从摄像头中逐帧获取像素信息。
  4. 处理帧数据:对获取到的帧进行各种处理、操作或算法。
  5. 显示处理后的结果:显示最终处理后的图像或视频。

下面将详细讲解JavaCV调用摄像头的基础流程。

配置JavaCV环境

  • 下载并安装JavaCV库:可以在官方网站(https://github.com/bytedeco/javacv/releases)或Maven中获取最新版本。下载并解压缩后将解压缩后的文件夹中bin文件夹下的所有文件添加到环境变量path中。
  • 配置IDE:在项目配置中添加JavaCV的库文件。

初始化摄像头

  • 获取摄像头列表

在JavaCV中,可以使用org.bytedeco.opencv.global.videoInputLib.videoInput调用摄像头。通过videoInput.getDevices()方法获取所有可用的摄像头列表,具体示例如下:

import org.bytedeco.opencv.global.videoInputLib.videoInput;

public class CameraUtil {
    public static void main(String[] args) {
        videoInput.getDevices();
    }
}
  • 初始化摄像头

选取要使用的摄像头后,通过org.bytedeco.javacpp.opencv_videoio.VideoCapture.open()方法打开摄像头。如果打开失败,可以使用org.bytedeco.javacpp.opencv_videoio.VideoCapture.isOpened()方法判断是否已经打开成功。具体实现如下:

import org.bytedeco.opencv.global.videoInputLib.videoInput;
import org.bytedeco.javacpp.opencv_videoio.VideoCapture;

public class CameraUtil {
    static { 
        System.setProperty("java.library.path", "lib"); //设置动态库文件路径
    }

    public static void main(String[] args) {
        VideoCapture camera = null;
        try {
            camera = new VideoCapture(0, VideoIOAPIs.V4L);
            if (camera.isOpened()) {
                System.out.println("Camera is opened.");
            } else{
                System.out.println("Can not open camera.");
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            camera.release();
        }
    }
}

捕获帧数据

在成功打开摄像头后,使用org.bytedeco.javacpp.opencv_core.Mat对象将摄像头捕获到的每一帧图片存储下来。这需要使用org.bytedeco.javacpp.opencv_videoio.VideoCapture.read()方法,可以参考如下的代码示例:

import org.bytedeco.javacpp.opencv_core.Mat;
import org.bytedeco.javacpp.opencv_videoio.VideoCapture;

public class CameraUtil {
    public static void main(String[] args) {
        VideoCapture camera = null;
        try {
            camera = new VideoCapture(0, VideoIOAPIs.V4L);
            if (camera.isOpened()) {
                System.out.println("Camera is opened.");
            } else{
                System.out.println("Can not open camera.");
            }
            Mat mat = new Mat();
            while (true) {
                boolean isCaptured = camera.read(mat);
                if (!isCaptured) {
                    break;
                }
                // process the captured mat frame ...
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            camera.release();
        }
    }
}

处理帧数据

获取到摄像头的每一帧数据后,可以对每一帧进行诸如滤波、变形、裁剪、二值化等多种操作,具体实现根据需要进行。

显示处理后的结果

处理完成后,可以使用OpenCV或ImageView控件显示结果。具体示例如下:

import org.bytedeco.javacpp.opencv_core.Mat;
import org.bytedeco.javacpp.opencv_imgcodecs;
import org.bytedeco.javacpp.opencv_videoio.VideoCapture;
import org.opencv.highgui.*;

import javax.swing.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class CameraUtil {
    public static void main(String[] args) {
        VideoCapture camera = null;
        try {
            camera = new VideoCapture(0, VideoIOAPIs.V4L);
            if (camera.isOpened()) {
                System.out.println("Camera is opened.");
            } else{
                System.out.println("Can not open camera.");
            }
            Mat mat = new Mat();
            JFrame jFrame = new JFrame();
            jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            jFrame.setSize(640, 480);
            JLabel jLabel = new JLabel();
            jFrame.setContentPane(jLabel);
            jFrame.setVisible(true);
            ScheduledExecutorService timerExec = Executors.newSingleThreadScheduledExecutor();
            timerExec.scheduleAtFixedRate(() -> {
                BufferedImage bi = toBufferedImage(mat); //Mat to BufferedImage
                jLabel.setIcon(new ImageIcon(bi));
                jFrame.pack();
            }, 0, 1000/30, TimeUnit.MILLISECONDS);
            while (true) {
                boolean isCaptured = camera.read(mat);
                if (!isCaptured) {
                    break;
                }
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            camera.release();
        }
    }

    private static BufferedImage toBufferedImage(Mat mat) {
        if (mat != null && !mat.empty()) {
            int type = BufferedImage.TYPE_BYTE_GRAY;
            if (mat.channels() > 1) {
                type = BufferedImage.TYPE_3BYTE_BGR;
            }
            int bufferSize = mat.channels() * mat.cols() * mat.rows();
            byte[] bytes = new byte[bufferSize];
            mat.data().get(bytes);
            BufferedImage image = new BufferedImage(mat.cols(), mat.rows(), type);
            final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
            System.arraycopy(bytes, 0, targetPixels, 0, bytes.length);
            return image;
        }
        return null;
    }
}

示例

示例1:简单的调用摄像头

import org.bytedeco.opencv.global.videoInputLib.videoInput;
import org.bytedeco.javacpp.opencv_videoio.VideoCapture;

public class CameraUtil {
    public static void main(String[] args) {
        VideoCapture camera = null;
        try {
            camera = new VideoCapture(0, VideoIOAPIs.V4L);
            if (camera.isOpened()) {
                System.out.println("Camera is opened.");
            } else{
                System.out.println("Can not open camera.");
            }
            Mat mat = new Mat();
            while (true) {
                boolean isCaptured = camera.read(mat);
                if (!isCaptured) {
                    break;
                }
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            camera.release();
        }
    }
}

示例2:在JavaFX应用程序中调用摄像头

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import org.bytedeco.javacpp.opencv_core.Mat;
import org.bytedeco.javacpp.opencv_videoio.VideoCapture;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;

public class CameraFX extends Application {
    private final static int WIDTH = 640;
    private final static int HEIGHT = 480;

    @Override
    public void start(Stage primaryStage) throws Exception {
        VideoCapture camera = null;
        try {
            camera = new VideoCapture(0, VideoIOAPIs.V4L);
            if (camera.isOpened()) {
                System.out.println("Camera is opened.");
            } else{
                System.out.println("Can not open camera.");
            }
            Mat mat = new Mat();
            ImageView imageView = new ImageView();
            BorderPane borderPane = new BorderPane(imageView);
            primaryStage.setScene(new Scene(borderPane));
            primaryStage.show();
            while (!primaryStage.isShowing()) {
                Thread.sleep(1000);
            }
            while (true) {
                boolean isCaptured = camera.read(mat);
                if (!isCaptured) {
                    break;
                }
                imageView.setImage(mat2Image(mat));
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            camera.release();
        }
    }

    private static BufferedImage matToImage(Mat mat) {
        BufferedImage image = null;
        int width = mat.cols();
        int height = mat.rows();
        int channels = mat.channels();
        byte[] sourcePixels = new byte[width * height * channels];
        mat.data().get(sourcePixels);
        if (channels > 1) {
            image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
        } else {
            image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
        }
        byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
        System.arraycopy(sourcePixels, 0, targetPixels, 0, sourcePixels.length);
        return image;
    }

    private static javafx.scene.image.Image mat2Image(Mat frame) {
        //create a temporary buffer
        byte[] b = new byte[frame.width() * frame.height() * frame.channels()];
        //encode the frame in the buffer, according to the BMP format.
        //Yes, OpenCV does support BMP(without telling you), although you probably would not want to use it
        frame.data().get(b);
        BufferedImage bi = new BufferedImage(frame.width(), frame.height(), BufferedImage.TYPE_3BYTE_BGR);
        bi.getRaster().setDataElements(0, 0, frame.width(), frame.height(), b);
        //convert the BufferedImage into an Image
        return SwingFXUtils.toFXImage(bi, null);
    }

    public static void main(String[] args) {
        launch(args);
    }
}

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaCV实战之调用摄像头基础详解 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Java中Lambda表达式的使用详细教程

    Java中Lambda表达式的使用详细教程 什么是Lambda表达式 Lambda表达式是Java8中新增加的一个特性,它提供了一种简洁但功能强大的方式来处理函数式编程。函数式编程是一种基于函数计算的编程方式,它将运算过程封装到函数中,并将函数当作一等公民进行传递。在传统的面向对象编程中,我们通常将操作封装到对象中,然后由对象来进行调用,而函数式编程则是直接…

    Java 2023年5月26日
    00
  • Tomcat部署Bolo动态博客

    下面是详细讲解如何在Tomcat上部署Bolo动态博客的完整攻略: 准备工作 下载Bolo动态博客的源代码,可以从官方GitHub仓库或其他源中获取:https://github.com/bolo/bolo 安装Java和Tomcat,可以从官方网站下载安装包并按照提示完成安装,建议使用JDK 8版本和Tomcat 8.5版本及以上。 在Tomcat的/co…

    Java 2023年5月19日
    00
  • 一文快速掌握Java中的搜索算法和排序算法

    一文快速掌握Java中的搜索算法和排序算法 前置知识 在学习搜索算法和排序算法之前,需要了解以下概念: 数据结构:由数据元素和各元素之间的关系组成的数据整体。 线性结构:数据元素之间存在一对一的前驱后继关系。 非线性结构:数据元素之间存在一对多或多对多的关系。 算法:解决特定问题的一系列步骤。 搜索算法 搜索算法是一种用于在数据结构中查找特定值的算法。常见的…

    Java 2023年5月26日
    00
  • 使用Java实现大小写转换实例代码

    使用Java实现大小写转换可以通过常用的String类提供的方法来实现,下面是实现的完整攻略: 1. 使用toUpperCase和toLowerCase方法 Java中String类提供了两个方法来实现大小写转换,分别是toUpperCase方法和toLowerCase方法。 toUpperCase方法:将字符串中的所有字符转换为大写字母; toLowerC…

    Java 2023年5月23日
    00
  • Mybatis中注入执行sql查询、更新、新增及建表语句案例代码

    让我来为你讲解Mybatis中注入执行SQL查询、更新、新增及建表语句的完整攻略。 什么是Mybatis? Mybatis是一个Java持久化框架,它可以帮助我们将Java对象与关系型数据库之间建立映射关系,同时提供了大量的查询、更新、新增和删除数据的API。 Mybatis支持多种ORM(对象关系映射)方式,其中比较常用的是注解和XML配置文件。本文将主要…

    Java 2023年5月20日
    00
  • 一文带你轻松应对Springboot面试小结

    一、简介 该攻略主要介绍了如何应对Spring Boot面试中常见的问题,并详细解答了每一个问题。通过学习该攻略,可以更好地了解和掌握Spring Boot的相关知识,增加面试成功的概率。 二、Spring Boot常见问题 什么是Spring Boot? Spring Boot是一个基于Spring框架的开发的Web框架,它通过自动化配置提供了一种快速构建…

    Java 2023年5月15日
    00
  • Java IO流对文件File操作

    下面是详细讲解Java IO流对文件操作的完整攻略: 概述 Java中的IO流是指Input/Output流,用于读写数据。Java IO流可以操作不同类型的数据源,其中文件作为一种重要的数据源,Java IO流提供了众多的类和方法,方便对文件进行读写和其他操作。Java IO流对于文件的操作可以分为两类:输入流(InputStream)和输出流(Outpu…

    Java 2023年5月19日
    00
  • Java Tomcat 启动闪退问题解决集

    让我来详细讲解“Java Tomcat 启动闪退问题解决集”。 Java Tomcat 启动闪退问题解决集 问题描述 在启动 Java Tomcat 时,可能会遇到闪退的问题。这种情况可能由多种原因导致,比如 Tomcat 配置文件出错、JVM 虚拟机内存溢出等。本文将提供一些解决 Tomcat 启动闪退的方法。 检查 Tomcat 配置文件 启动 Tomc…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部