)类 新建javafx程序时_第三章 第一个OpenCV的JavaFX应用程序.md

# 第三章 第一个OpenCV的JavaFX应用程序

---

***注意***:我们假设您现在已经阅读了之前的教程。如果没有,请在[http://opencv-java-tutorials.readthedocs.org/en/latest/index.html](http://opencv-java-tutorials.readthedocs.org/en/latest/index.html)查看。您还可以在

[https://github.com/opencv-java/](https://github.com/opencv-java/)找到源代码和资源。

---

## 3.1 OpenCV的JavaFX应用程序

  本教程将指导你使用Eclipse中的OpenCV库来创建一个简单的JavaFX GUI应用程序。

## 3.2 在本教程中要做什么

  在本教程中,我们将:

    •安装**e(fx)clipse**插件和 _Scene Builder_ (*Scene Builder*安装不做硬性要求);

    •使用 _Scene Builder_ ;

    •编写并运行应用程序。

## 3.3 JavaFX中的第一个应用程序

  本教程编写出来的应用程序将捕获来自网络摄像机的视频流并将其显示在图形用户界面(GUI)上。

  我们是使用Scene Builder来创建GUI的。创建完毕后,GUI将具有一个按钮和一个简单的图像视图框,前者用于播放/关闭视频流,后者用于放置视频流帧。

## 3.4 安装e(fx)clipse插件和Scene Builder

  请按照本教程的指导在Eclipse中安装**e(fx)clipse**插件,本教程内容详见[http://www.eclipse.org/efxclipse/install.html#fortheambitious](http://www.eclipse.org/efxclipse/install.html#fortheambitious)。

  如果不想安装此类插件,只需创建一个惯用的**Java项目**——*JavaFX Scene Builder 2.0*即可。请从[http://www.oracle.com/technetwork/java/javafxscenebuilder-1x-archive-2199384.html](http://www.oracle.com/technetwork/java/javafxscenebuilder-1x-archive-2199384.html)下载安装*JavaFX Scene Builder 2.0*。

  现在可以来新建一个JavaFX项目了,具体操作为:

    •转到“File > New > Project...”,选择“JavaFX project....”;

![U8Puid.png](https://images.gitee.com/uploads/images/2020/0716/170447_07d86fe4_1464254.png)

    •输入项目名称(名称自选),单击“Next”;

![U8P7wD.png](https://images.gitee.com/uploads/images/2020/0716/170455_2965d862_1464254.png)

    •添加OpenCV用户库到刚刚创建的项目,单击“Next”;

![U8iv4J.png](https://images.gitee.com/uploads/images/2020/0716/170447_73b87349_1464254.png)

    •分别选定Package名称、*FXML文件*名称以及*控制器类*名称。关于你创建的GUI的描述将以FXML语言的形式包含在FXML文件中。而GUI组件与用户交互时所必须调用、管理的方法和事件都将由*控制器类*处理。

## 3.5 使用Scene Builder

  如果之前已经安装过*Scene Builder*,就可以直接在Eclipse中右键单击FXML文件然后选择“Open with SceneBuilder”。

   _Scene Builder_ 是通过与图形界面交互来帮助构建你的GUI的。这样一来,你就可以实时预览你的窗口效果。此外,只需编辑图形预览即可实现GUI组件内容的修改以及位置的调整。

  不妨来具体地看一看我到底在讲些什么。

  *FXML文件*最开始只有一个*AnchorPane*。AnchorPane中,允许存在一个偏离距离,位于AnchorPane子节点边缘锚定的位置与AnchorPane自身边缘所在的位置之间。如果AnchorPane设置了border和(或)padding,则偏离距离要从它们的内边缘开始算起。对于受到AnchorPane管理的子节点,无论它们是否可见,都将被AnchorPane一一展开。而非托管子节点则不会被AnchorPane展开。

  当然,你也可以删除AnchorPane并添加BorderPane。BorderPane在TOP、LEFT、RIGHT、BOTTOM以及CENTER这5个固定位置展开子节点。

![U8k6w8.png](https://images.gitee.com/uploads/images/2020/0716/170450_ecd69550_1464254.png)

  从“Container”菜单中拖拽一个BorderPane并将其放到“Hierarchy”菜单中,即可添加一个BorderPane。BorderPane添加完毕后,我们再来添加一个Button,它之后可以用来播放/关闭视频流。从“Contols”菜单中拖拽一个Button并将其放到我们刚刚添加的BP(即BorderPane)的**BOTTOM**区域,Button就添加完成了。

  我们现在可以看到,界面的右方区域有3个菜单(“Properties”、“Layout”、“Code”),用于自定义被选中组件。例如,我们可以在“Properties”菜单下的“Text”区域修改之前添加的Button内容为“StartCamera”,还可以在“Code”菜单下的“fx:id”区域修改Button的id(比如改成“start_btn”)。接下来在从**控制器**方法编辑button属性时,我们就需要用到button的id。

  在界面中还可以看到,button现在离窗口的距离特别近。因此要为button设置一定的下边距。我们可以在“Layout”菜单中进行相应操作。

![U8kzOx.png](https://images.gitee.com/uploads/images/2020/0716/170449_80184d49_1464254.png)

![U8AEpd.png](https://images.gitee.com/uploads/images/2020/0716/170448_d93bfe99_1464254.png)

  为了能让button正常运行,我们必须在“Code”菜单下的“OnAction”这一栏设定好方法名称(比如“startCamera”),此处设定的方法将执行我们预想的功能。

![U8EPuq.png](https://images.gitee.com/uploads/images/2020/0716/170449_b1f17c57_1464254.png)

  然后从“Controls”菜单中拖拽一个*ImageView*添加到BP的**CENTER**区域中。同样地,为ImageView设置一定的边距并对其id加以修改(比如改成“currentFrame”)。

![U8EzdK.png](https://images.gitee.com/uploads/images/2020/0716/170450_2dc463fe_1464254.png)

  最后,必须指定一个控制器类去管理我们的GUI。为此,需添加我们之前选定的控制器类名称到位于窗口左下方的“Controller”菜单下的“Controller class”这一栏。

  我们刚刚使用Scene Builder创建了我们第一个GUI。如果你现在保存文件回到Eclipse,你会看到Eclipse已经自动生成了某些FXML代码。

## 3.6 JavaFX中的一些重要概念

  **Stage**:应用程序显示的地方(比如Windows窗口);

  **Scene**:即节点容器,此容器中的节点构成了你的应用程序的某个“页面”;

  **Node**:Scene中的一个元素,具有可视化、可交互的特点。节点可能是以分层嵌套的形式存在于Scene中。

  在*Main类*中,我们需要将自身的*primary stage*传递给*start*函数:

```

public void start(Stage primaryStage)

```

  也是在*Main类*中,我们还要载入FXML文件,该文件将会填充我们的Stage、Scene的*root element*以及控制器类:

```

FXMLLoader loader = new FXMLLoader(getClass().getResource("FXHelloCV.fxml"));

BorderPane root = (BorderPane) loader.load();

FXController controller = loader.getController();

```

## 3.7 使用控制器类管理GUI交互

  关于我们的JavaFX应用程序,我们需要做两件最基本的事:一是控制按下Button;二是控制刷新ImageView。为了实现上述操作,我们需要在GUI组件和控制器类变量间创建一个引用:

```

@FXML

private Button button;

@FXML

private ImageView currentFrame;

```

  **@FXML**标签用于链接变量到FXML文件中的某个元素,并且该变量值应等于相链接的元素的id。

  **@FXML**标签用于某个元素设定的方法时,功能同上。例如:

    对于:

```

```

    我们设置:

```

@FXML

protected void startCamera(ActionEvent event) { ...

```

## 3.8 视频捕获

  VideoCapture类基本上已经整合了视频处理所需要的一切函数。这是建立在FFmpeg开源库的基础上的。

```

private VideoCapture capture = new VideoCapture();

```

  一段视频由若干连续的图像组成,其中的这些图像我们称之为帧。视频文件中,用帧率来明确两帧之间的间隔时长。而对于摄像机来说,每秒可数字化的帧数通常是有限制的。在这里,我们设置帧率为30帧/秒。为此我们需要初始化一个计时器(即`ScheduledExecutorService`),该计时器每33毫秒将会启动一次后台任务。

```

Runnable frameGrabber = new Runnable() { ... }

this.timer = Executors.newSingleThreadScheduledExecutor();

this.timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.

˓→ MILLISECONDS);

```

  要检查VideoCapture类是否成功绑定了视频源的话,我们需要使用**isOpened**函数:

```

if (this.capture.isOpened()) { ... }

```

  视频在其析构函数被调用时就会自动关闭。可是如果你想在此之前就关闭视频的话,就需要调用其释放函数了:

```

this.capture.release();

```

  鉴于视频帧纯粹就是图像而已,所以我们只需要将它们从VideoCapture对象中提取出来再放入Mat 1即可。

```

Mat frame = new Mat();

```

  从“read”或“overloaded >> operator”读取帧时,由于视频流都是连续的,所以帧可能是顺次而出。

```

this.capture.read(frame);

```

  我们还需要将我们的图像从*BGR*格式转换成*灰度*图。OpenCV中有一个非常好的函数可以完成此类转换:

```

Imgproc.cvtColor(frame, frame, Imgproc.COLOR_BGR2GRAY);

```

  **从上面这行代码可以看到,cvtColor用到以下参数:**

      •**源图像(frame);**

      •**目标图像(frame),用来保存转换后的灰度图;**

      •**附加参数,用于指示将要执行何种转换。在这里使用的附加参数是COLOR_BGR2GRAY (不使用imread是因为对于彩色图像imread默认使用BGR通道顺序)。**

  为了能将捕获的帧放入ImageView中,我们需要将矩阵转换成图像。具体操作如下:

    •首先,我们创建一个缓冲区,用于存储矩阵。

```

MatOfByte buffer = new MatOfByte();

```

    •然后,使用**imencode**函数,将捕获的帧放入缓冲区,下列这行代码便会将图像编码到内存缓冲区中:

```

Imgcodecs.imencode(".png", frame, buffer);

```

    **imencode**函数压缩图像并存储到内存缓冲区中,内存缓冲区会自适应压缩后图像的大小。

---

**注意:** **imencode**函数返回**CV_8UC1**型的单行矩阵,被编码成字节数组的图像就包含在返回的矩阵中。

---

    **imencode函数用到3个参数:**

      •**“.png”,即文件扩展名,用于定义输出格式;**

      **•frame,即待写入图像;**

      **•buffer,即输出缓存区,可以自适应压缩后图像的大小。**

  将捕获的帧放入缓存区后,我们就要用到**ByteArrayInputStream**来流式传输缓存区中被压缩的图像:

```

new Image(new ByteArrayInputStream(buffer.toArray()));

```

  通过流式传输得到新的图像后,我们就可以将其放到ImageView中。不过使用Java 1.8版本时,我们是无法在与主线程不同的线程中更新GUI的元素的。因此我们需要先从其他的线程中获取新帧,然后在主线程中刷新我们的ImageView:

```

Image imageToShow = grabFrame();

Platform.runLater(new Runnable() {

@Override public void run() { currentFrame.setImage(imageToShow); }

});

```

![U8u2zF.png](https://images.gitee.com/uploads/images/2020/0716/170452_e1829e8e_1464254.png)

一键复制

编辑

Web IDE

原始数据

按行查看

历史

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

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

相关文章

公式和图片转LaTeX网址

在线LaTeX公式编辑器-编辑器

沃丰报告:物联网的未来

物联网的未来激动人心,但物联网并不只为那些极具创新精神的创业企业而生。大多数物联网项目都不是为了创造头条新闻,而是为了做出切实的成果。我相信我们已经越过了临界点,物联网已经成为主流。来源 | 沃达丰物联网近日,沃达丰(vo…

推销员(codevs 5126)

题目描述 Description阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有N家住户,第i家住户到入口的距离为Si米。由于同一栋房…

python管理系统web版_Python学生管理系统(web网页版)-Go语言中文社区

前言:本项目是使用Python的Django的web框架搭建的,是一个完整的学生管理系统,功能包括基本的增删改查 项目演示图: 首页展示数据的页面(index.html)添加学生的页面(add.html)搜索学生…

hog函数的用法 python_Python常见内置函数用法(三)

本文作者:孙雪丽文字编辑:周聪聪技术总编:张学人重大通知!!!2019年6月22日至24日在河南郑州举行Stata编程技术特别训练营,招生工作已经圆满结束。另外爬虫俱乐部将于2019年7月5日至7月8日在武汉…

pytorch打印模型每层的结构

可以用torchsummary下的summary方法,或者torchinfo下的summary方法,两者功能是一样的 以torchsummary下的summary方法为例说明 首先通过pip install torchsummary 之后在代码中: from torchsummary import summarysummary(model, (1, 28,…

学会动态丨中国人工智能学会成功召开重大科学问题《智能生成机理》研讨会...

来源:中国人工智能学会为配合国家科技发展的重大需求,推进重大科学问题的研究,形成相应的政策建议,中国人工智能学会于9月29日上午9时在北邮科技大厦召开了“重大科学问题《智能生成机理》研讨会”。现场专家们通过深入交流&#…

Linux文件(区域)锁函数 -- open()、fcntl()

一、什么是文件锁定 对于锁这个字,大家一定不会陌生,因为我们生活中就存在着大量的锁,它们各个方面发挥着它的作用,现在世界中的锁的功能都可归结为一句话,就是阻止某些人做某些事,例如,门锁就是…

**Java有哪些悲观锁的实现_「Java并发编程」何谓悲观锁与乐观锁,Java编程你会吗...

何谓悲观锁与乐观锁悲观锁乐观锁两种锁的使用场景乐观锁常见的两种实现方式1. 版本号机制2. CAS算法乐观锁的缺点1 ABA 问题2 循环时间长开销大3 只能保证一个共享变量的原子操作CAS与synchronized的使用情景何谓悲观锁与乐观锁乐观锁对应于生活中乐观的人总是想着事情往好的方…

python分配内存_CPython内存分配

其中大部分内容在C API文档的Memory Management章节中得到回答.一些文档比您要求的更容易.有关详细信息,您必须转到源代码.没有人会愿意这样做,除非你选择一个特定的版本. (至少2.7.5,2.7.6,3.3.2之前,3.3.3之前和3.4之前对于不同的人来说将是有趣的.)obmalloc.c文件的来源是您…

现代版的大案牍术:数字孪生在城市的应用

来源:阿里研究院最近大火的电视剧《长安十二时辰》中,靖安司大规模启用秘密核武器——大案牍术,书吏们从各个部门汇总来的人员往来、钱粮货物流水中寻找到蛛丝马迹甚至未卜先知,再结合长安版的5G通讯——望楼通信与大沙盘&#xf…

关于样式表setStyleSheet

在Qt中设置widget背景颜色或者图片方法很多种:重写paintEvent() , 调色板QPalette , 样式表setStyleSheet等等。 但是各种方法都有其注意事项,如果不注意则很容易陷入麻烦中。 1:setStyleSheet() 这个函数我一直很喜欢使用,因为只…

react打包后图片丢失_使用 webpack 搭建 React 项目

简评:相信很多开发者在入门 react 的时候都是使用 create-react-app 或 react-slingshot 这些脚手架来快速创建应用,当有特殊需求,需要修改 eject 出来的 webpack 配置文件时,面对各种配置项不知如何下手,本文会介绍如…

揭秘5G+AI时代的机器人世界!七大核心技术改变人类生活【附下载】| 智东西内参...

来源: 智东西AI 和 5G 与机器人技术结合,正在不断催生新的消费电子品类。AI 解决机器理解世界,以及人机交互的问题。5G 拓展机器人的活动边界,并为机器人提供更大的算力和存储空间(云协作机器人) 。根据 IF…

TSQL编程

1.索引添加索引,设计界面,在任何一列前右键--索引/键--点击进入添加某一列为索引 2.视图 视图就是我们查询出来的虚拟表创建视图:create view 视图名 as SQL查询语句,分组,排序,in 等都不能写视图的用法: s…

python方向键控制角色_用python和pygame游戏编程入门-控制角色移动

在上一节中我们知道了事件,以及如何捕捉键盘事件进行响应,本届我们结合第一节何上一节的内容,做一个用键盘控制角色移动的功能,代码如下: #!/usr/bin/env python #指定图像文件名称 background_image_filename ./img/…

arcgis fishnet 单位_ArcGIS中使用Create Fishnet生成格网

ArcGIS中使用Create Fishnet生成格网1.如果单元格的宽和高定义为0,那么必须指定行与列的数目以及格网对角的坐标2.格网的范围可以手动输入,也可以引用已有数据为模板。如果输入一个模版,格网的起始坐标和Y轴的坐标就被自动填充了,…

让人工智能有情感的秘诀!清华权威报告看透情感计算【附下载】

来源: 智东西40 多年前,诺贝尔奖得主 Herbert Simon 在认知心理学方面强调,解决问题论要结合情感的影响。情感的识别和表达对于信息的交流和理解是必需的,也是人类最大的心理需求之一。人类的认知、行为等几乎都要受到情感的驱动&…

端口扫描的目的

端口扫描的目的是扫描大范围的主机连接一系列的 TCP 端口,判断主机开放了哪些服务,这些开放的端口往往与一定的服务相对应,通过这些开放的端口,就能了解主机运行的服务,然后就可以进一步整理和分析这些服务可能存在的漏…