- 环境准备:安装 JDK、Maven 和 OpenCV Java 库。
- 创建 Maven 项目:在 IDE(如 IntelliJ IDEA 或 Eclipse)中创建一个标准的 Maven 项目。
- 编写代码:编写 Java 代码来启动摄像头、捕获视频流并显示在窗口中。
- 运行和测试:运行程序并查看效果。
- 进阶功能:介绍如何拍照、保存图片以及释放资源。
第 1 步:环境准备
在开始之前,请确保你已经安装了以下软件:

- JDK (Java Development Kit):Java 开发工具包,建议使用 JDK 8 或更高版本。
- Maven:项目管理和构建自动化工具,用于管理 OpenCV 的依赖。
- IDE (集成开发环境):推荐使用 IntelliJ IDEA 或 Eclipse。
- OpenCV:我们需要 OpenCV 的 Java 绑定库。
最关键的一步:配置 OpenCV Java 库
OpenCV 官方提供了预编译的 Java 库,你可以从其官网下载。
- 下载 OpenCV:访问 OpenCV 官网 Releases 页面,下载最新的稳定版本(
opencv-4.x.x)。 - 解压:下载后解压到一个你熟悉的目录,
D:\dev\opencv。 - 找到
opencv-java-xxx.jar:在解压目录的opencv\build\java文件夹下,你会找到一个名为opencv-490.jar(版本号可能不同)的文件,这就是我们 Java 项目需要引入的库文件。 - 加载 OpenCV 的本地库(
.dll或.so):OpenCV 的 Java 库本身是依赖底层 C++ 实现的动态链接库(Windows上是.dll,Linux上是.so),你必须告诉 JVM 在哪里找到这个库。- 在
opencv\build\java\x64目录下,你会找到一个名为opencv_java490.dll的文件(同样,版本号可能不同)。 - 你需要确保你的 Java 程序在运行时能加载到这个
.dll文件,最简单的方法是在代码中手动指定其路径。
- 在
第 2 步:创建 Maven 项目
这里以 IntelliJ IDEA 为例:
- 打开 IntelliJ IDEA,选择
File->New->Project。 - 选择
Maven,不要勾选Create from archetype,直接点击Next。 - 填写
GroupId(com.example) 和ArtifactId(opencv-camera-demo),点击Next。 - 选择你的 Maven 设置和 JDK,点击
Finish。
项目创建后,你可以在 pom.xml 文件中手动添加 OpenCV 的依赖,但更推荐的方式是在代码中直接加载 .jar 和 .dll 文件,这样可以避免 Maven 仓库中版本不匹配的问题。

第 3 步:编写核心代码
在 src/main/java 目录下,创建一个 Java 类,CameraDemo.java。
下面是完整的代码,并附有详细的注释。
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.videoio.VideoCapture;
import org.opencv.videoio.Videoio;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
public class CameraDemo {
// OpenCV 的 native 库路径
// !!! 请务必修改成你自己的 OpenCV 解压路径 !!!
private static final String OPENCV_DLL_PATH = "D:\\dev\\opencv\\build\\java\\x64\\opencv_java490.dll";
public static void main(String[] args) {
// 1. 加载 OpenCV native 库
// 这是至关重要的一步,如果找不到 .dll 文件,程序会抛出 UnsatisfiedLinkError
System.load(OPENCV_DLL_PATH);
System.out.println("OpenCV version: " + Core.VERSION);
// 2. 创建 VideoCapture 对象
// 0 表示默认摄像头
VideoCapture camera = new VideoCapture(0);
// 检查摄像头是否成功打开
if (!camera.isOpened()) {
System.err.println("Error: Could not open camera.");
return;
}
// 3. 设置摄像头分辨率 (可选)
camera.set(Videoio.CAP_PROP_FRAME_WIDTH, 640);
camera.set(Videoio.CAP_PROP_FRAME_HEIGHT, 480);
// 4. 创建一个 Swing 窗口来显示视频
JFrame frame = new JFrame("OpenCV Camera");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(640, 480);
// JLabel 用于显示图像
JLabel label = new JLabel();
frame.add(label);
frame.setVisible(true);
// 5. 循环读取摄像头帧
Mat frameMat = new Mat();
try {
while (true) {
// 从摄像头读取一帧
if (camera.read(frameMat)) {
// 将 OpenCV 的 Mat 对象转换为 Java 的 BufferedImage
BufferedImage image = matToBufferedImage(frameMat);
// 在 Swing 的 Event Dispatch Thread 中更新 UI
SwingUtilities.invokeLater(() -> {
label.setIcon(new ImageIcon(image));
});
}
// 添加一个小的延迟,避免 CPU 占用过高
Thread.sleep(30); // 约 33 FPS
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 6. 释放资源
System.out.println("Releasing resources...");
camera.release();
frame.dispose();
}
}
/**
* 将 OpenCV 的 Mat 对象转换为 Java 的 BufferedImage
* @param mat OpenCV Mat 对象
* @return BufferedImage 对象
*/
private static BufferedImage matToBufferedImage(Mat mat) {
int width = mat.cols();
int height = mat.rows();
int channels = mat.channels();
BufferedImage image = null;
byte[] data = new byte[width * height * channels];
mat.get(0, 0, data); // 将 Mat 中的像素数据复制到 byte 数组
// 根据通道数创建不同类型的 BufferedImage
if (channels == 1) { // 灰度图
image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
} else if (channels == 3) { // BGR 彩色图
image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
// OpenCV 使用 BGR 格式,而 Java 使用 RGB,所以需要转换
// byteBufferByte 会自动处理,但需要注意颜色通道顺序
}
// 将 byte 数组的数据写入 BufferedImage
byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arraycopy(data, 0, targetPixels, 0, data.length);
return image;
}
}
第 4 步:运行和测试
- 修改路径:最重要的一步!将代码中的
OPENCV_DLL_PATH修改为你自己电脑上opencv_javaXXX.dll文件的绝对路径。 - 运行:在 IntelliJ IDEA 中右键点击
CameraDemo.java,选择Run 'CameraDemo.main()'。
如果一切顺利,你应该会弹出一个标题为 "OpenCV Camera" 的窗口,其中实时显示你摄像头的画面,在控制台,你还会看到打印出的 OpenCV 版本信息。
当你关闭窗口时,程序会自动进入 finally 块,释放摄像头资源并退出。

第 5 步:进阶功能示例
拍照功能
我们可以在窗口上添加一个按钮,点击时捕获当前帧并保存为图片。
修改 CameraDemo.java:
// ... 在 main 方法中,创建 frame 之后添加 ...
JButton captureButton = new JButton("拍照");
frame.add(captureButton, BorderLayout.SOUTH); // 将按钮添加到窗口底部
// ... 在 while 循环之前,定义一个变量来存储当前帧 ...
Mat lastFrame = null;
// ... 修改 while 循环内部 ...
if (camera.read(frameMat)) {
lastFrame = frameMat.clone(); // 保存当前帧的副本
BufferedImage image = matToBufferedImage(frameMat);
// ... 更新 UI ...
}
// ... 在 frame.setVisible(true) 之后添加按钮事件监听 ...
captureButton.addActionListener(e -> {
if (lastFrame != null && !lastFrame.empty()) {
// 保存图片
String fileName = "capture_" + System.currentTimeMillis() + ".png";
System.out.println("Saving image to: " + fileName);
Imgcodecs.imwrite(fileName, lastFrame);
} else {
System.out.println("No frame to capture.");
}
});
注意:你需要在文件顶部添加 import org.opencv.imgcodecs.Imgcodecs;。
正确的资源释放(try-with-resources)
上面的 finally 块是手动释放资源,Java 7+ 提供了 try-with-resources 语法,可以更优雅地管理实现了 AutoCloseable 接口的资源(如 VideoCapture)。
// 替换掉原来的 try-catch-finally 结构
try (VideoCapture camera = new VideoCapture(0)) {
if (!camera.isOpened()) {
System.err.println("Error: Could not open camera.");
return;
}
camera.set(Videoio.CAP_PROP_FRAME_WIDTH, 640);
camera.set(Videoio.CAP_PROP_FRAME_HEIGHT, 480);
JFrame frame = new JFrame("OpenCV Camera");
// ... 设置 frame ...
JLabel label = new JLabel();
frame.add(label);
frame.setVisible(true);
Mat frameMat = new Mat();
while (true) {
if (camera.read(frameMat)) {
BufferedImage image = matToBufferedImage(frameMat);
SwingUtilities.invokeLater(() -> label.setIcon(new ImageIcon(image)));
}
Thread.sleep(30);
}
} catch (Exception e) {
e.printStackTrace();
} // 当 try 块执行完毕后,camera 会自动调用 release()
这种方式更简洁,且能确保资源在异常发生时也能被正确释放。
常见问题与解决
-
java.lang.UnsatisfiedLinkError: no opencv_javaXXX in java.library.path- 原因:JVM 找不到 OpenCV 的 native 库(
.dll或.so文件)。 - 解决:检查
System.load()中的路径是否正确,确保路径指向opencv_javaXXX.dll文件本身,而不是它所在的文件夹。
- 原因:JVM 找不到 OpenCV 的 native 库(
-
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException- 原因:可能是摄像头没有正确打开,导致
camera.read()返回false,但代码继续尝试处理一个空的Mat对象。 - 解决:在
camera.read(frameMat)之后增加判断if (!frameMat.empty())。
- 原因:可能是摄像头没有正确打开,导致
-
画面卡顿或延迟严重
- 原因:
Thread.sleep()的时间太短,或者电脑性能不足。 - 解决:适当增加
sleep的时间,50ms(20 FPS),或者在SwingUtilities.invokeLater()中使用repaint()而不是不断更换Icon。
- 原因:
希望这份详细的指南能帮助你成功地在 Java 中使用 OpenCV 调用摄像头!
