找回密码
 立即注册
首页 业界区 业界 探索 JavaCV:开启计算机视觉与多媒体处理新世界 ...

探索 JavaCV:开启计算机视觉与多媒体处理新世界

怀陶宁 2025-6-25 15:30:13
目录

  • JavaCV 是什么?
  • 安装指南
  • 有趣的 JavaCV 使用示例

    • 录制 RTMP 直播流
    • 捕获摄像头画面
    • 美颜相机

  • 引用

在当今的技术领域,计算机视觉和多媒体处理的应用愈发广泛。从视频监控到直播录制,再到美颜相机等有趣的功能,都离不开强大的处理库。JavaCV 作为基于 OpenCV 和 FFmpeg 的 Java 接口库,为 Java 开发者打开了一扇通往这些功能的大门。接下来,就让我们一起深入了解 JavaCV 的神奇之处吧!
JavaCV 是什么?

JavaCV 就像是一个超级桥梁,它将 OpenCV 和 FFmpeg 这两个在 C++ 世界中叱咤风云的库,引入到了 Java 的环境里。有了 JavaCV,开发者无需再纠结于 C++ 的复杂语法和编译环境,在 Java 里就能轻松实现视频处理、图像分析、特征提取等高端操作。
它的特性超厉害

  • OpenCV 功能封装:JavaCV 把 OpenCV 的 C++ API 进行了精心封装,提供了和原生 API 很相似的 Java 接口。不管是图像处理、特征检测,还是目标跟踪,都能信手拈来。
  • FFmpeg 集成:集成了 FFmpeg 库,意味着 JavaCV 支持多种音视频格式的编解码、转码以及流媒体处理。以后处理音视频,就像吃蛋糕一样简单。
  • GPU 加速支持:在这个追求速度的时代,JavaCV 支持利用 GPU 进行加速计算。对于那些计算密集型任务,速度提升可不是一星半点。
  • 多平台兼容:无论是 Windows、Linux 还是 macOS,JavaCV 都能完美运行,跨平台性一流。
安装指南

如果你使用 Gradle,安装 JavaCV 就像下面这样简单:
  1. dependencies {
  2.     implementation 'org.springframework.boot:spring-boot-starter-web'
  3.    
  4.     // JavaCV 核心依赖
  5.     implementation group: 'org.bytedeco', name: 'javacv-platform', version: '1.5.7'
  6.    
  7.     // Tesseract JavaCPP Presets
  8.     implementation group: 'org.bytedeco', name: 'tesseract-platform', version:
  9. '5.0.1-1.5.7'
  10.    
  11.     compileOnly 'org.projectlombok:lombok'
  12.     annotationProcessor 'org.projectlombok:lombok'
  13.     // Apache HttpClient 依赖
  14.     implementation 'org.apache.httpcomponents:httpclient:4.5.14'
  15.     // fastjson2 核心依赖
  16.     implementation 'com.alibaba.fastjson2:fastjson2:2.0.36'
  17.     implementation 'cn.hutool:hutool-all:5.8.1'
  18.     implementation 'org.springdoc:springdoc-openapi-ui:1.7.0'
  19. }
复制代码
这里要注意啦,本文使用的 SpringBoot 版本为 2.7.6,JDK 版本为 11。而且在 Intellj IDEA 的“外部库”依赖关系中可以发现,javacv - platform 已经自带了很多依赖包,甚至连 ffmpeg 库都包含在内,所以使用时无需单独安装 ffmpeg 库。
1.png

有趣的 JavaCV 使用示例

录制 RTMP 直播流

想象一下,你正在观看一场精彩的直播,想要把它录制下来慢慢回味。JavaCV 就能帮你轻松实现这个需求。
核心对象揭秘

  • FFmpegFrameGrabber:它就像一个勤劳的小蜜蜂,从直播源中抓取帧数据。
  • FFmpegFrameRecorder:负责把抓取到的帧数据录制下来,保存成 MP4 文件。
下面是封装在 Spring Boot 中的示例代码:
  1. @Slf4j
  2. @RequiredArgsConstructor
  3. @Component
  4. public class RecordComponent {
  5.     /**
  6.      * 录制MP4
  7.      *
  8.      * @param deviceCode 设备编码
  9.      * @param videoUrl  直播url
  10.      * @param dpi 录制的视频质量(720p,1080p,2k)
  11.      * @return
  12.      */
  13.     @Async("customThreadPool")
  14.     public String record(String deviceCode, String videoUrl, DpiEnum dpi) {
  15.         log.debug("video_record_param:deviceCode={},videoUrl={},dpi={}", deviceCode, videoUrl, dpi);
  16.         try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoUrl)) {
  17.             if (videoUrl.startsWith("rtmp")) {
  18.                 //使用 TCP 避免丢包
  19.                 grabber.setOption("rtmp_transport", "tcp");
  20.             }
  21.             if (videoUrl.startsWith("rtsp")) {
  22.                 //使用 TCP 避免丢包
  23.                 grabber.setOption("rtsp_transport", "tcp");
  24.             }
  25.             //禁用数据缓冲区,直接从源读取,适用于实时流(如 RTSP/RTMP),减少从源到帧抓取的延迟
  26.             grabber.setOption("fflags", "nobuffer");
  27.             grabber.start();
  28.             
  29.             String videoSavePath="";
  30.             try (FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(videoSavePath, dpi.getWidth(), dpi.getHeight())) {
  31.                 // 禁用音频,若源中存在音频通道(即grabber.getAudioChannels()>0),此配置无法生效
  32.                 recorder.setAudioChannels(0);
  33.                 //设置编码格式:h264
  34.                 recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
  35.                 recorder.setFormat("mp4");
  36.                 //fps,帧率表示视频中每秒钟显示的静态画面数量
  37.                 recorder.setFrameRate(grabber.getFrameRate());
  38.                 //视频色彩相关配置
  39.                 recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
  40.                 //降低视频编码延迟,适用于对实时性要求极高的场景
  41.                 recorder.setOption("tune", "zerolatency");
  42.                 //预设值影响编码速度和压缩效率的平衡
  43.                 recorder.setOption("preset", "veryfast");
  44.                 recorder.start();
  45.                
  46.                 Frame frame;
  47.                 while ((frame = grabber.grab()) != null) {
  48.                     recorder.record(frame);
  49.                     log.debug("video_record_{}视频帧录制成功", deviceCode);
  50.                 }
  51.             } catch (Exception e) {
  52.                 log.error("video_record_recorder_error,msg={},deviceCode={}", e.getMessage(), deviceCode);
  53.                 log.error("video_record_recorder_error", e);
  54.             }
  55.         } catch (Exception e) {
  56.             log.error("video_record_grabber_error,msg={},deviceCode={}", e.getMessage(), deviceCode);
  57.             log.error("video_record_grabber_error", e);
  58.         }
  59.     }
  60. }
复制代码
这里的 @Component 让这个类成为 Spring IOC 组件,方便在其他地方注入使用。@Async 开启了异步线程,因为录制直播可能需要很长时间,不能让请求方一直等待。
原理:通过 FFmpegFrameGrabber 从指定的直播地址抓取帧数据,然后通过 FFmpegFrameRecorder 将帧数据录制为 mp4 文件。这里面会通过调用自包含的ffmpeg库,实现录制功能。
捕获摄像头画面

想不想用 Java 打开笔记本的摄像头,看看自己帅气或美丽的脸庞?下面的代码就能帮你实现:
  1. public class CameraComponent {
  2.     /**
  3.      * 打开摄像头并显示视频流,不可以以SpringBoot Web方式调用, 可以使用 main 调用。
  4.      */
  5.     public static void openCamera() {
  6.         try (OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0)) {
  7.             grabber.start();
  8.             CanvasFrame frameViewer = new CanvasFrame("摄像头视频");
  9.             frameViewer.setCanvasSize(grabber.getImageWidth(), grabber.getImageHeight());
  10.             Frame frame;
  11.             while ((frame = grabber.grab()) != null && frameViewer.isVisible()) {
  12.                 frameViewer.showImage(frame);
  13.             }
  14.             
  15.             frameViewer.dispose();
  16.         } catch (Exception e) {
  17.             log.error("打开摄像头失败", e);
  18.         }
  19.     }
  20.     public static void main(String[] args) {
  21.         openCamera();
  22.     }
  23. }
复制代码
2.png

OpenCVFrameGrabber 负责捕获摄像头的视频流,CanvasFrame 则用来显示视频流。不过要注意哦,这个方法只能在 main 方法里运行,Spring Boot Web 项目启动会报错。
美颜相机

有了摄像头,怎么能少了美颜功能呢?JavaCV 也能实现简单的美颜效果。
  1. public class CameraComponent {
  2.     /**
  3.      * 美颜相机
  4.      */
  5.     public static void beautyFace() {
  6.         try (OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0)) {
  7.             CanvasFrame frameViewer = new CanvasFrame("美颜相机");
  8.             grabber.start();
  9.             frameViewer.setCanvasSize(grabber.getImageWidth(), grabber.getImageHeight());
  10.             String cascadePath = "D:\\temp\\haarcascade_frontalface_default.xml";
  11.             System.out.println("人脸检测器路径: " + cascadePath);
  12.             CascadeClassifier faceDetector = new CascadeClassifier(cascadePath);
  13.             OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat();
  14.             Frame frame;
  15.             while ((frame = grabber.grab()) != null && frameViewer.isVisible()) {
  16.                 Mat mat = converter.convert(frame);
  17.                 if (mat == null) continue;
  18.                 Mat gray = new Mat();
  19.                 cvtColor(mat, gray, COLOR_BGR2GRAY);
  20.                 equalizeHist(gray, gray);
  21.                 RectVector faceDetections = new RectVector();
  22.                 faceDetector.detectMultiScale(gray, faceDetections);
  23.                 gray.release();
  24.                 for (int i = 0; i < faceDetections.size(); i++) {
  25.                     Rect rect = faceDetections.get(i);
  26.                     applyBeautyFilter(mat, rect);
  27.                 }
  28.                 frameViewer.showImage(converter.convert(mat));
  29.             }
  30.         } catch (Exception e) {
  31.             e.printStackTrace();
  32.         }
  33.     }
  34.     /**
  35.      * 简化版美颜滤镜实现
  36.      * @param frame
  37.      * @param face
  38.      */
  39.     private static void applyBeautyFilter(Mat frame, Rect face) {
  40.         int expand = face.width() / 4;
  41.         Rect expandedFace = new Rect(
  42.                 Math.max(0, face.x() - expand),
  43.                 Math.max(0, face.y() - expand),
  44.                 Math.min(frame.cols() - face.x() - 1, face.width() + 2 * expand),
  45.                 Math.min(frame.rows() - face.y() - 1, face.height() + 2 * expand)
  46.         );
  47.         Mat faceROI = new Mat(frame, expandedFace);
  48.         Mat smoothed = new Mat();
  49.         bilateralFilter(faceROI, smoothed, 15, 80, 80);
  50.         smoothed.copyTo(new Mat(frame, expandedFace));
  51.         smoothed.release();
  52.         faceROI.release();
  53.     }
  54. }
复制代码
这个美颜功能主要是磨皮和虚化,让你的皮肤看起来更加光滑。不过它只对正脸有效哦,如果侧着脸或者没有检测到人脸,就不会有效果啦。
大致思路为,先捕捉摄像头的视频流,解析出帧数据,然后将帧数据转成图片给OpenCV库处理,处理完毕就是美颜之后的图片,再渲染到播放窗口上。
bilateralFilter:调用OpenCV的这个方法,实现磨皮效果。具体这个方法的作用可以参考:https://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html
haarcascade_frontalface_default.xml: 这是 OpenCV 提供的一个预训练模型文件,用于人脸检测。它基于 Haar 级联分类器(Haar Cascade Classifier) 算法,包含了训练好的人脸特征数据,用于识别图像中的正面人脸区域。
faceDetections:这个对象的size 大于0 ,说明检测到了人脸。
JavaCV 的功能远不止这些,它就像一个宝藏库,等待着开发者们去挖掘更多有趣又实用的功能。赶紧动手试试吧!
引用

https://github.com/bytedeco/javacv
https://bytedeco.org/
https://gitee.com/naylor_personal/ramble-spring-boot/tree/master/java-cv
技术交流QQ群:1158377441 欢迎关注我的微信公众号【TechnologyRamble】,后续博文将在公众号首发:
3.png

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册