Kurento模块开发指南之二:开发示例 Pointer Detector Filter

2024-08-21 17:58

本文主要是介绍Kurento模块开发指南之二:开发示例 Pointer Detector Filter,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

17.1.2 模块教程1- Pointer Detector Filter
这个页面应用由一个带有指针跟踪滤镜组件的WebRTC视频通信回看组成。

Java 模块教程 1 - Pointer Detector Filter
这个页面应用由一个带有指针跟踪滤镜组件的WebRTC视频通信回看组成。

首先:  运行这个示例程序
首先,需要安装Kurento Media Server来运行这个示例,可以参看前面的安装指南。
另外,内建模块kms-pointerdetector-6.0 也需要被安装:
$ sudo apt-get install kms-pointerdetector-6.0

为了加载这个应用,需要从GitHub上克隆这个工程并运行,命令如下:
$ git clone https://github.com/Kurento/kurento-tutorial-java.git
$ cd kurento-tutorial-java/kurento-pointerdetector
$ mvn compile exec:java

在本机上用 (Chrome, Firefox)浏览器输入网址http://localhost:8080/即可看到这个示例应用。

Note: 
These instructions work only if Kurento Media Server is up and running in the same machine than the tutorial. However, it is possible to locate the KMS in other machine simple adding the argument kms.ws.uri to the Maven execution command, as follows:
mvn compile exec:java -Dkms.ws.uri=ws://kms_host:kms_port/kurento

理解这个示例应用
这个应用程序使用了计算机视觉和虚拟现实技术,它是基于颜色跟踪的方式检测WebRTC流中的指针。

这个应用程序(一个HTML页面)的接口由两个HTML5视频标签组成:
一个用于显示本地的视频摄像头的流;
一个用于显示远端的镜像的流。
本地视频摄像头的流被发送到KMS, 经过处理后再发回到客户端。我们需要创建的媒体管道由下列媒体组件组成:
 
Figure 17.3: WebRTC with PointerDetector filter in loopback Media Pipeline

这个示例应用的完整代码在GitHub上。
这个示例应用程序,是Magic Mirror教程的改版,它使用了PointerDetector 代替FaceOverlay 滤镜。

为了实现指针检测,它必须有一个校准阶段,即先要把指针处的颜色注册到滤镜中。为了实现这个步骤,指针需要先位于视频框的左上角,如下所示:
 
Figure 17.4: Pointer calibration stage

在这个时刻,服务端将会发送一个校准消息给客户端。
这可以通过点击页面的校准蓝色按钮实现。

在这之后,指针所指处的颜色就会被KMS实时跟踪。
PointerDetectorFilter 同样能定义屏幕上的一个区域,称之为窗口,当某些操作导致指针进入这个区域时会执行一些动作, 当指针进入时是WindowInEvent事件,退出时是WindowOutEvent事件。
服务端的代码逻辑如下:

// Media Logic (Media Pipeline and Elements)
UserSession user = new UserSession();
MediaPipeline pipeline = kurento.createMediaPipeline();
user.setMediaPipeline(pipeline);    
WebRtcEndpoint webRtcEndpoint = new WebRtcEndpoint.Builder(pipeline).build();
user.setWebRtcEndpoint(webRtcEndpoint);
users.put(session.getId(), user);


webRtcEndpoint.addOnIceCandidateListener(new EventListener<OnIceCandidateEvent>() {
@Override
    public void onEvent(OnIceCandidateEvent event) {
        JsonObject response = new JsonObject();
        response.addProperty("id", "iceCandidate");
        response.add("candidate", JsonUtils.toJsonObject(event.getCandidate()));
        try {
            synchronized (session) {
                session.sendMessage(new TextMessage(response.toString()));
            }
        } catch (IOException e) {
            log.debug(e.getMessage());
        }
    }
});


pointerDetectorFilter = new PointerDetectorFilter.Builder(pipeline,new WindowParam(5, 5, 30, 30)).build();
pointerDetectorFilter.addWindow(new PointerDetectorWindowMediaParam("window0",50, 50, 500, 150));
pointerDetectorFilter.addWindow(new PointerDetectorWindowMediaParam("window1",50, 50, 500, 250));
webRtcEndpoint.connect(pointerDetectorFilter);
pointerDetectorFilter.connect(webRtcEndpoint);
pointerDetectorFilter.addWindowInListener(new EventListener<WindowInEvent>() {
    @Override
    public void onEvent(WindowInEvent event) {
        JsonObject response = new JsonObject();
        response.addProperty("id", "windowIn");
        response.addProperty("roiId", event.getWindowId());
        try {
            session.sendMessage(new TextMessage(response.toString()));
        } catch (Throwable t) {
            sendError(session, t.getMessage());
        }
    }
});


pointerDetectorFilter.addWindowOutListener(new EventListener<WindowOutEvent>() {
    @Override
    public void onEvent(WindowOutEvent event) {
        JsonObject response = new JsonObject();
        response.addProperty("id", "windowOut");
        response.addProperty("roiId", event.getWindowId());
        try {
            session.sendMessage(new TextMessage(response.toString()));
        } catch (Throwable t) {
            sendError(session, t.getMessage());
        }
    }
});


// SDP negotiation (offer and answer)
String sdpOffer = jsonMessage.get("sdpOffer").getAsString();
String sdpAnswer = webRtcEndpoint.processOffer(sdpOffer);


// Sending response back to client
JsonObject response = new JsonObject();
response.addProperty("id", "startResponse");
response.addProperty("sdpAnswer", sdpAnswer);
synchronized (session) {
    session.sendMessage(new TextMessage(response.toString()));
}
webRtcEndpoint.gatherCandidates();


下图显示了在一个定义窗口中的指针检测:
 
Figure 17.5: Pointer tracking over a window


为了从客户端发送校准消息到服务端,这个示例程序的JavaScripte使用了下面的函数:
function calibrate() {    
    console.log("Calibrate color");
    var message = {
        id : 'calibrate'
    }
    sendMessage(message);
}


当应用程序服务端收到消息后,下面的代码被执行来进行校准:
private void calibrate(WebSocketSession session, JsonObject jsonMessage) {
    if (pointerDetectorFilter != null) {
        pointerDetectorFilter.trackColorFromCalibrationRegion();
    }
}


依赖项
Java Spring是由Maven实现,另外还需要三个依赖项:
the Kurento Client Java dependency (kurento-client), 
the JavaScript Kurento utility library (kurento-utils) for the client-side,
and the pointer detector module (pointerdetector):    


<parent>
    <groupId>org.kurento</groupId>
    <artifactId>kurento-parent-pom</artifactId>
    <version>|CLIENT_JAVA_VERSION|</version>
</parent>


<dependencies>
    <dependency>
        <groupId>org.kurento</groupId>
        <artifactId>kurento-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.kurento</groupId>
        <artifactId>kurento-utils-js</artifactId>
    </dependency>
    <dependency>
        <groupId>org.kurento.module</groupId>
        <artifactId>pointerdetector</artifactId>
    </dependency>
</dependencies>


Note: 
We are in active development. You can find the latest versions at Maven Central.

这篇关于Kurento模块开发指南之二:开发示例 Pointer Detector Filter的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1093879

相关文章

Python中re模块结合正则表达式的实际应用案例

《Python中re模块结合正则表达式的实际应用案例》Python中的re模块是用于处理正则表达式的强大工具,正则表达式是一种用来匹配字符串的模式,它可以在文本中搜索和匹配特定的字符串模式,这篇文章主... 目录前言re模块常用函数一、查看文本中是否包含 A 或 B 字符串二、替换多个关键词为统一格式三、提

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

Linux中SSH服务配置的全面指南

《Linux中SSH服务配置的全面指南》作为网络安全工程师,SSH(SecureShell)服务的安全配置是我们日常工作中不可忽视的重要环节,本文将从基础配置到高级安全加固,全面解析SSH服务的各项参... 目录概述基础配置详解端口与监听设置主机密钥配置认证机制强化禁用密码认证禁止root直接登录实现双因素

ModelMapper基本使用和常见场景示例详解

《ModelMapper基本使用和常见场景示例详解》ModelMapper是Java对象映射库,支持自动映射、自定义规则、集合转换及高级配置(如匹配策略、转换器),可集成SpringBoot,减少样板... 目录1. 添加依赖2. 基本用法示例:简单对象映射3. 自定义映射规则4. 集合映射5. 高级配置匹

深度解析Spring Boot拦截器Interceptor与过滤器Filter的区别与实战指南

《深度解析SpringBoot拦截器Interceptor与过滤器Filter的区别与实战指南》本文深度解析SpringBoot中拦截器与过滤器的区别,涵盖执行顺序、依赖关系、异常处理等核心差异,并... 目录Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现

C++11作用域枚举(Scoped Enums)的实现示例

《C++11作用域枚举(ScopedEnums)的实现示例》枚举类型是一种非常实用的工具,C++11标准引入了作用域枚举,也称为强类型枚举,本文主要介绍了C++11作用域枚举(ScopedEnums... 目录一、引言二、传统枚举类型的局限性2.1 命名空间污染2.2 整型提升问题2.3 类型转换问题三、C

MySQL追踪数据库表更新操作来源的全面指南

《MySQL追踪数据库表更新操作来源的全面指南》本文将以一个具体问题为例,如何监测哪个IP来源对数据库表statistics_test进行了UPDATE操作,文内探讨了多种方法,并提供了详细的代码... 目录引言1. 为什么需要监控数据库更新操作2. 方法1:启用数据库审计日志(1)mysql/mariad

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

SpringBoot开发中十大常见陷阱深度解析与避坑指南

《SpringBoot开发中十大常见陷阱深度解析与避坑指南》在SpringBoot的开发过程中,即使是经验丰富的开发者也难免会遇到各种棘手的问题,本文将针对SpringBoot开发中十大常见的“坑... 目录引言一、配置总出错?是不是同时用了.properties和.yml?二、换个位置配置就失效?搞清楚加