探索 JavaCV:开启计算机视觉与多媒体处理新世界
在当今的技术领域,计算机视觉和多媒体处理的应用愈发广泛。从视频监控到直播录制,再到美颜相机等有趣的功能,都离不开强大的处理库。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 就像下面这样简单:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
// JavaCV 核心依赖
implementation group: 'org.bytedeco', name: 'javacv-platform', version: '1.5.7'
// Tesseract JavaCPP Presets
implementation group: 'org.bytedeco', name: 'tesseract-platform', version:
'5.0.1-1.5.7'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
// Apache HttpClient 依赖
implementation 'org.apache.httpcomponents:httpclient:4.5.14'
// fastjson2 核心依赖
implementation 'com.alibaba.fastjson2:fastjson2:2.0.36'
implementation 'cn.hutool:hutool-all:5.8.1'
implementation 'org.springdoc:springdoc-openapi-ui:1.7.0'
}
这里要注意啦,本文使用的 SpringBoot 版本为 2.7.6,JDK 版本为 11。而且在 Intellj IDEA 的“外部库”依赖关系中可以发现,javacv - platform 已经自带了很多依赖包,甚至连 ffmpeg 库都包含在内,所以使用时无需单独安装 ffmpeg 库。
有趣的 JavaCV 使用示例
录制 RTMP 直播流
想象一下,你正在观看一场精彩的直播,想要把它录制下来慢慢回味。JavaCV 就能帮你轻松实现这个需求。
核心对象揭秘
- FFmpegFrameGrabber:它就像一个勤劳的小蜜蜂,从直播源中抓取帧数据。
- FFmpegFrameRecorder:负责把抓取到的帧数据录制下来,保存成 MP4 文件。
下面是封装在 Spring Boot 中的示例代码:
@Slf4j
@RequiredArgsConstructor
@Component
public class RecordComponent {
/**
* 录制MP4
*
* @param deviceCode 设备编码
* @param videoUrl 直播url
* @param dpi 录制的视频质量(720p,1080p,2k)
* @return
*/
@Async("customThreadPool")
public String record(String deviceCode, String videoUrl, DpiEnum dpi) {
log.debug("video_record_param:deviceCode={},videoUrl={},dpi={}", deviceCode, videoUrl, dpi);
try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoUrl)) {
if (videoUrl.startsWith("rtmp")) {
//使用 TCP 避免丢包
grabber.setOption("rtmp_transport", "tcp");
}
if (videoUrl.startsWith("rtsp")) {
//使用 TCP 避免丢包
grabber.setOption("rtsp_transport", "tcp");
}
//禁用数据缓冲区,直接从源读取,适用于实时流(如 RTSP/RTMP),减少从源到帧抓取的延迟
grabber.setOption("fflags", "nobuffer");
grabber.start();
String videoSavePath="";
try (FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(videoSavePath, dpi.getWidth(), dpi.getHeight())) {
// 禁用音频,若源中存在音频通道(即grabber.getAudioChannels()>0),此配置无法生效
recorder.setAudioChannels(0);
//设置编码格式:h264
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
recorder.setFormat("mp4");
//fps,帧率表示视频中每秒钟显示的静态画面数量
recorder.setFrameRate(grabber.getFrameRate());
//视频色彩相关配置
recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
//降低视频编码延迟,适用于对实时性要求极高的场景
recorder.setOption("tune", "zerolatency");
//预设值影响编码速度和压缩效率的平衡
recorder.setOption("preset", "veryfast");
recorder.start();
Frame frame;
while ((frame = grabber.grab()) != null) {
recorder.record(frame);
log.debug("video_record_{}视频帧录制成功", deviceCode);
}
} catch (Exception e) {
log.error("video_record_recorder_error,msg={},deviceCode={}", e.getMessage(), deviceCode);
log.error("video_record_recorder_error", e);
}
} catch (Exception e) {
log.error("video_record_grabber_error,msg={},deviceCode={}", e.getMessage(), deviceCode);
log.error("video_record_grabber_error", e);
}
}
}
这里的 @Component 让这个类成为 Spring IOC 组件,方便在其他地方注入使用。@Async 开启了异步线程,因为录制直播可能需要很长时间,不能让请求方一直等待。
原理:通过 FFmpegFrameGrabber 从指定的直播地址抓取帧数据,然后通过 FFmpegFrameRecorder 将帧数据录制为 mp4 文件。这里面会通过调用自包含的ffmpeg库,实现录制功能。
捕获摄像头画面
想不想用 Java 打开笔记本的摄像头,看看自己帅气或美丽的脸庞?下面的代码就能帮你实现:
public class CameraComponent {
/**
* 打开摄像头并显示视频流,不可以以SpringBoot Web方式调用, 可以使用 main 调用。
*/
public static void openCamera() {
try (OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0)) {
grabber.start();
CanvasFrame frameViewer = new CanvasFrame("摄像头视频");
frameViewer.setCanvasSize(grabber.getImageWidth(), grabber.getImageHeight());
Frame frame;
while ((frame = grabber.grab()) != null && frameViewer.isVisible()) {
frameViewer.showImage(frame);
}
frameViewer.dispose();
} catch (Exception e) {
log.error("打开摄像头失败", e);
}
}
public static void main(String[] args) {
openCamera();
}
}
OpenCVFrameGrabber 负责捕获摄像头的视频流,CanvasFrame 则用来显示视频流。不过要注意哦,这个方法只能在 main 方法里运行,Spring Boot Web 项目启动会报错。
美颜相机
有了摄像头,怎么能少了美颜功能呢?JavaCV 也能实现简单的美颜效果。
public class CameraComponent {
/**
* 美颜相机
*/
public static void beautyFace() {
try (OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0)) {
CanvasFrame frameViewer = new CanvasFrame("美颜相机");
grabber.start();
frameViewer.setCanvasSize(grabber.getImageWidth(), grabber.getImageHeight());
String cascadePath = "D:\\temp\\haarcascade_frontalface_default.xml";
System.out.println("人脸检测器路径: " + cascadePath);
CascadeClassifier faceDetector = new CascadeClassifier(cascadePath);
OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat();
Frame frame;
while ((frame = grabber.grab()) != null && frameViewer.isVisible()) {
Mat mat = converter.convert(frame);
if (mat == null) continue;
Mat gray = new Mat();
cvtColor(mat, gray, COLOR_BGR2GRAY);
equalizeHist(gray, gray);
RectVector faceDetections = new RectVector();
faceDetector.detectMultiScale(gray, faceDetections);
gray.release();
for (int i = 0; i < faceDetections.size(); i++) {
Rect rect = faceDetections.get(i);
applyBeautyFilter(mat, rect);
}
frameViewer.showImage(converter.convert(mat));
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 简化版美颜滤镜实现
* @param frame
* @param face
*/
private static void applyBeautyFilter(Mat frame, Rect face) {
int expand = face.width() / 4;
Rect expandedFace = new Rect(
Math.max(0, face.x() - expand),
Math.max(0, face.y() - expand),
Math.min(frame.cols() - face.x() - 1, face.width() + 2 * expand),
Math.min(frame.rows() - face.y() - 1, face.height() + 2 * expand)
);
Mat faceROI = new Mat(frame, expandedFace);
Mat smoothed = new Mat();
bilateralFilter(faceROI, smoothed, 15, 80, 80);
smoothed.copyTo(new Mat(frame, expandedFace));
smoothed.release();
faceROI.release();
}
}
这个美颜功能主要是磨皮和虚化,让你的皮肤看起来更加光滑。不过它只对正脸有效哦,如果侧着脸或者没有检测到人脸,就不会有效果啦。
大致思路为,先捕捉摄像头的视频流,解析出帧数据,然后将帧数据转成图片给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://gitee.com/naylor_personal/ramble-spring-boot/tree/master/java-cv
探索 JavaCV:开启计算机视觉与多媒体处理新世界的更多相关文章
- StartDT_AI_Lab | 开启“数据+算法”定义的新世界
继「数据中台技术汇」栏目推出以来,获得了不少技术极客的喜爱.作为AI驱动的数据中台创导者,深度关注核心算法技术的自研创新.融合探索,故推出全新AI算法栏目「StartDT_AI_Lab」,主要介绍算法 ...
- javaCV入门指南:调用FFmpeg原生API和JavaCV是如何封装了FFmpeg的音视频操作?
通过"javaCV入门指南:序章 "大家知道了处理音视频流媒体的前置基本知识,基本知识包含了像素格式.编解码格式.封装格式.网络协议以及一些音视频专业名词,专业名词不会赘述,自行搜 ...
- iOS多媒体总结&进入后台播放音乐
1. 播放mp3需要导入框架,AVFoundation支持音频文件(.caf..aif..wav..wmv和.mp3)的播放. #import <AVFoundation/AVFoundatio ...
- A simple test
博士生课程报告 视觉信息检索技术 博 士 生:施 智 平 指导老师:史忠植 研究员 中国科学院计算技术研究所 2005年1月 目 ...
- CCF虚拟现实与可视化技术专委会丨面向增强现实的可视计算技术研究进展概述
https://mp.weixin.qq.com/s/I-rNwgXHEtwgdpkWzKtVXw 摘要 新一代增强现实技术需要依赖可视计算理论与方法解决大尺度复杂环境下的场景建模.内容生成.感知交互 ...
- 2020中国.NET开发者峰会近50场热点技术专题揭秘
简介 / Summary 2014年微软组织并成立.NET基金会,微软在成为主要的开源参与者的道路上又前进了一步.2014年以来已经有众多知名公司加入.NET基金会,微软,Google,AWS三大云厂 ...
- 一个项目覆盖CS所有课程的可行性探究
我们先看计算机科学有哪些子领域. 学术领域有: 计算理论 信息和编码理论 算法和数据结构 形式化方法 程序设计语言 实践领域有: 计算机体系结构 并行计算和分布式系统 实时系统和嵌入式系统 操作系统 ...
- C/C++ 开源库及示例代码
C/C++ 开源库及示例代码 Table of Contents 说明 1 综合性的库 2 数据结构 & 算法 2.1 容器 2.1.1 标准容器 2.1.2 Lockfree 的容器 2.1 ...
- Deep learning for visual understanding: A review 视觉理解中的深度学习:回顾 之一
Deep learning for visual understanding: A review 视觉理解中的深度学习:回顾 ABSTRACT: Deep learning algorithms ar ...
- 使用Data Lake Analytics + OSS分析CSV格式的TPC-H数据集
0. Data Lake Analytics(DLA)简介 关于Data Lake的概念,更多阅读可以参考:https://en.wikipedia.org/wiki/Data_lake 以及AWS和 ...
随机推荐
- Nginx 301永久性转移
我有个域名www.taadis.com, 想永久性转移到taadis.com. 前言 看到很多网友的做法是把taadis.com & www.taadis.com等多个域名放到一个server ...
- 『Plotly实战指南』--箱线图绘制与应用
在数据可视化领域,箱线图(Box Plot)是一种强大的工具,用于展示数据的分布特征.集中趋势以及异常值. 它不仅能够快速揭示数据的偏态.离散程度,还能帮助我们识别潜在的数据问题. 本文将从基础绘制到 ...
- 让 LLM 来评判 | 技巧与提示
这是 让 LLM 来评判 系列文章的第六篇,敬请关注系列文章: 基础概念 选择 LLM 评估模型 设计你自己的评估 prompt 评估你的评估结果 奖励模型相关内容 技巧与提示 LLM 评估模型已知偏 ...
- Web前端入门第 32 问:CSS background 元素渐变背景用法全解
渐变背景在 CSS 里面就是一个颜色到另一个颜色渐渐变化的样子. 本文示例中,盒子基础样式: .box { margin: 20px; padding: 20px; border: 10px dash ...
- 树状数组(Fenwick Tree)原理和优化全面解析
你正在开发一个交易系统,需要实时完成两种操作: 更新某个时间点的价格(单点修改) 快速计算某段时间段内的交易总量(区间查询) 当数据量较小时,我们可能会这样实现: vector<int> ...
- Redis的淘汰机制
第一种情况:设置了过期时间的数据 a:挑选使用最少的数据淘汰 b:随机淘汰 c:选择时间快过期数据淘汰 第二种:没有设置过期时间的数据 a:挑选使用最少的数据淘汰 b:随机淘汰 第三种: a:禁止驱逐 ...
- Tryhackme部分翻译学习
Tryhackme部分翻译学习 1.Weaponization WSH 上传txt到桌面 Set shell = WScript.CreateObject("Wscript.Shell&qu ...
- Rust实战系列-生命周期、所有权和借用
本文是<Rust in action>学习总结系列的第四部分,更多内容请看已发布文章: 一.Rust实战系列-Rust介绍 二.Rust实战系列-基本语法 三.Rust实战系列-复合数据类 ...
- Windows查看端口占用、相应进程、杀死进程等[netstat]
Windows 通过cmd或powerShell查看端口占用.相应进程.杀死进程等的命令 由于一般开发环境是在windows上,相应的一些测试必然涉及到一些端口的监听与使用.当开发使用的端口被占用后, ...
- 小白也能行【手撕ResNet代码篇(附代码)】:详解可复现
目录 前言 model BasicBlock 和Bottleneck ResNet ResNet18\34\50\101\152 data train test 代码运行以及测试结果 前言 之前已经给 ...