使用JavaCV调用摄像头与录制

news/2025/3/12 9:26:24/文章来源:https://www.cnblogs.com/nan1mono/p/18766708

在这一步,使用JavaCV采集摄像头画面,再通过帧转换将JavaCV采集到的视频帧解析成JavaFX可以处理的Image,并渲染到预先设定好的画面中
使用的JavaCV依赖如下

<dependency>  <groupId>org.bytedeco</groupId>  <artifactId>javacv</artifactId>  <version>1.5.11</version>  
</dependency>  <dependency>  <groupId>org.bytedeco</groupId>  <artifactId>javacv-platform</artifactId>  <version>1.5.11</version>  
</dependency>

本次使用的是Java17进行开发,JavaFX相关依赖如下

<dependency>  <groupId>org.openjfx</groupId>  <artifactId>javafx-controls</artifactId>  <version>17</version>  
</dependency>  <dependency>  <groupId>org.openjfx</groupId>  <artifactId>javafx-swing</artifactId>  <version>17</version>  
</dependency>

最终运行的demo代码如下

import javafx.application.Application  
import javafx.application.Platform  
import javafx.embed.swing.SwingFXUtils  
import javafx.scene.Scene  
import javafx.scene.image.ImageView  
import javafx.scene.layout.StackPane  
import javafx.stage.Stage  
import org.bytedeco.javacv.Java2DFrameConverter  
import org.bytedeco.javacv.OpenCVFrameConverter  
import org.bytedeco.javacv.OpenCVFrameGrabber  
import org.bytedeco.opencv.global.opencv_core  
import kotlin.concurrent.thread  class VideoTest : Application() {  // 新建 OpenCV 视频抓取器  private val grabber = OpenCVFrameGrabber(0)  // 用于显示视频帧  private val imageView = ImageView()  private val frameConverter = OpenCVFrameConverter.ToMat() // 用于 Frame 和 Mat 转换  // 帧转换器  private val converter = Java2DFrameConverter()  // 控制采集线程  private var isRunning = true  override fun start(stage: Stage) {  // 创建 JavaFX 窗口  val root = StackPane(imageView)  val scene = Scene(root, 640.0, 480.0)  // 窗口标题,与原代码一致  stage.title = "摄像头窗口"  stage.scene = scene  stage.show()  // 窗口关闭时停止采集  stage.setOnCloseRequest {  isRunning = false  grabber.release()  Platform.exit()  }  grabber.start()  // 通过独立的线程,是采集和展示互不干扰,避免造成两个线程阻塞  thread {  while (isRunning && stage.isShowing) {  val grab = grabber.grab()  // 现在开始采集过程  if (grab != null) {  // 将 Frame 转为 Mat 并翻转  val mat = frameConverter.convertToMat(grab)  opencv_core.flip(mat, mat, 1) // 水平翻转(1 表示左右翻转)  val flippedFrame = frameConverter.convert(mat) // 转回 Frame                    // 将OpenCV的视频返回帧处理成Java Swing可以处理的BufferedImage  val bufferedImage = converter.convert(flippedFrame)  // 将BufferedImage转换成JavaFX的Image,第二个null为不使用预分配的WritableImage(性能优化选项)  val fxImage = SwingFXUtils.toFXImage(bufferedImage, null)  // 在主线程上更新UI,即视频采集到的画面通过主线渲染到提前设定好的imageView  Platform.runLater {  imageView.image = fxImage  }  }  // 每次循环采集时间,用户控制采集频率以实现不同帧率  val sleepTime = (1000 / grabber.frameRate).toLong()  Thread.sleep(sleepTime)  }  grabber.release()  }  }  }  fun main() {  Application.launch(VideoTest::class.java)  
}

视频调用代码

上述代码已经实现了java配合openCV实现录像采集,接下来更近一步,添加上视频的录制功能,此时需要借助FFmpeg去进行视频编码,具体代码如下 ^c302f7

import javafx.application.Application  
import javafx.application.Platform  
import javafx.embed.swing.SwingFXUtils  
import javafx.scene.Scene  
import javafx.scene.image.ImageView  
import javafx.scene.layout.StackPane  
import javafx.stage.Stage  
import org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_H264  
import org.bytedeco.javacv.FFmpegFrameRecorder  
import org.bytedeco.javacv.Java2DFrameConverter  
import org.bytedeco.javacv.OpenCVFrameConverter  
import org.bytedeco.javacv.OpenCVFrameGrabber  
import org.bytedeco.opencv.global.opencv_core  
import kotlin.concurrent.thread  class VideoTest : Application() {  // 新建 OpenCV 视频抓取器  private val grabber = OpenCVFrameGrabber(0)  // 用于显示视频帧  private val imageView = ImageView()  private val frameConverter = OpenCVFrameConverter.ToMat() // 用于 Frame 和 Mat 转换  // 帧转换器  private val converter = Java2DFrameConverter()  // 控制采集线程  private var isRunning = true  // 视频编码器  private lateinit var recorder: FFmpegFrameRecorder  override fun start(stage: Stage) {  // 设置采集器大小  grabber.imageWidth = 640  grabber.imageHeight = 480  // 启动采集器  grabber.start()  // 初始化FFmpeg视频解码器  recorder = FFmpegFrameRecorder("output.mp4", grabber.imageWidth, grabber.imageHeight)  // 设置视频编码格式为H264  recorder.videoCodec = AV_CODEC_ID_H264  // 设置视频输出格式为H264  recorder.format = "mp4"  // 设置帧率为30帧  recorder.frameRate = 30.0  // 设置画面质量(质量越小越高),默认为23  recorder.videoQuality = 23.0  recorder.start()  // 创建 JavaFX 窗口  val root = StackPane(imageView)  val scene = Scene(root, 640.0, 480.0)  // 窗口标题,与原代码一致  stage.title = "摄像头窗口"  stage.scene = scene  // 显示窗口  stage.show()  // 窗口关闭时停止采集  stage.setOnCloseRequest {  isRunning = false  // 窗口关闭时,释放资源  cleanup()  Platform.exit()  }  // 通过独立的线程,是采集和展示互不干扰,避免造成两个线程阻塞  thread {  while (isRunning && stage.isShowing) {  val startTime = System.currentTimeMillis()  try {  val grab = grabber.grab()  val mat = frameConverter.convert(grab)  val flippedFrame = frameConverter.convert(mat)  opencv_core.flip(mat, mat, 1)  // 现在开始采集过程  // 将OpenCV的视频返回帧处理成Java Swing可以处理的BufferedImage  val bufferedImage = converter.convert(flippedFrame)  // 将BufferedImage转换成JavaFX的Image,第二个null为不使用预分配的WritableImage(性能优化选项)  val fxImage = SwingFXUtils.toFXImage(bufferedImage, null)  // 在主线程上更新UI,即视频采集到的画面通过主线渲染到提前设定好的imageView  Platform.runLater {  imageView.image = fxImage  }  try {// 设置编码并保存  recorder.record(flippedFrame)  } catch (e: Exception) {  e.printStackTrace()  println("Record failed: ${e.message}")  }  // 释放反转帧  flippedFrame.close()  // 释放原始视频帧  grab.close()  } catch (e: Exception) {  e.printStackTrace()  }  // 每次循环采集时间,用户控制采集频率以实现不同帧率  val endTime = System.currentTimeMillis()  val elapsed = endTime - startTime  val sleepTime = (33 - elapsed).coerceAtLeast(0) // 动态调整睡眠时间  Thread.sleep(sleepTime)  }  cleanup()  }  }  /**  * 释放资源  */  private fun cleanup() {  recorder.stop()  recorder.release()  grabber.release()  }  }  fun main() {  Application.launch(VideoTest::class.java)  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/897554.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

qt creator 配置clang-format 代码风格

1 Qt creator配置格式化代码插件clang-format 2 clang-format的配置 qt creator上面的选项卡:帮助>关于插件,在c++的那一栏中勾选Beautifier,然后重启qt creator的软件。上方的选项卡:编辑>Preferences>美化器 选择工具为ClangFormat在Clang Format的那一栏中,选…

利用Xshell进行文件传输

1.利用Xshell连接靶机或服务器 新建会话,(连接这里)输入ip,选择端口,名字随便写 点击用户身份验证,输入管理员用户和密码 点击连接 进入靶机终端(可能还需要确认一次密码)2.提权与修改密码 如果不是root权限,可以通过su root提权 root权限下直接通过passwd修改密码 如果是…

です(desu)的意思

“です”是日语中常用的表达方式,主要有以下几个含义和使用场景: 1. 表达断定:在日语中,“です”相当于汉语的“是”,用于断定句的结尾,表示对前面所述内容的肯定。例如,“これは本です。”(这是书。)2. 表达尊敬:在表达尊敬的场合,使用“です”可以使语气显得更加礼…

2025-03-12 随笔

今天周三,天气不错,记

线上测试木舟物联网平台之如何通过HTTP网络组件接入设备

一、概述 木舟 (Kayak) 是什么?木舟(Kayak)是基于.NET6.0软件环境下的surging微服务引擎进行开发的, 平台包含了微服务和物联网平台。支持异步和响应式编程开发,功能包含了物模型,设备,产品,网络组件的统一管理和微服务平台下的注册中心,服务路由,模块,中间服务等管理。还…

经过 10 亿级性能验证的隐私计算开源利器

在数据驱动的时代,我们每天都在产生大量数据:购物记录、健康信息、社交关系……这些数据蕴含巨大价值,但也伴随着隐私泄露的风险。 试想一下:医院希望联合研究某种疾病,但患者数据无法直接共享。 银行想合作分析反欺诈信息,但客户隐私数据必须严格保护。 AI 公司需要使用…

值得推荐的IT公司名单(国企篇)

大家好,今天我们来盘点一下值得推荐的国企,这些企业在行业内具有举足轻重的地位,不仅主营业务突出,福利待遇优厚,尤其是研发岗位的薪资区间,更是让人眼前一亮。十大顶尖央企国企,待遇优厚如天花板级别!(排名不分先后)1、中国烟草总公司 人家都说能成为烟草总公司的一…

Entity Framework Core 数据库迁移

EF Core 通过两种方式来保持**模型**和**数据库架构**同步。 迁移 Code First 反向工程 Db First 管理迁移 通过EF Core 命令行工具来管理迁移 安装EF Core 命令行工具# 安装 dotnet-ef dotnet tool install --global dotnet-ef# 验证安装 dotnet ef# 更新工具 dotnet tool upd…

Roslyn 分析器已知问题 传递项目属性时将忽略分号之后的内容

本文记录 Roslyn 分析器、源代码生成器的已知问题,通过CompilerVisibleProperty 传递值时,所有在 `;`、`#` 和换行符之后的字符都会被忽略相关问题链接:https://github.com/dotnet/roslyn/issues/43970 https://github.com/dotnet/roslyn/issues/51692此问题由 walterlv 发现…

Avalonia 已知问题 继承滚动条将让里层控件无法获得无穷大空间

本文记录 Avalonia 的一个已知问题,如果有代码里面编写一个类型继承 ScrollViewer 类型,然后这个类型里面啥都不做。那将会导致所有放在此滚动条里面的控件无法获取无穷大的空间,其宽高无法撑开,被限定为上层容器尺寸复现步骤如下:新建一个 FooScrollViewer 类型,让其继承…

读DAMA数据管理知识体系指南17数据存储和操作治理

读DAMA数据管理知识体系指南17数据存储和操作治理1. 管理数据库性能 1.1. 数据库的性能取决于两个相互依赖的因素:可用性和响应速度 1.2. 性能包括确保空间的可用性、查询优化以及其他能使数据库以有效的方式返回数据的因素1.2.1. 如果没有可用性,就无法衡量数据库的性能1.2.…