(五)Qt 动态手势识别“左右滑动”以及实现翻页效果

news2024/12/28 4:59:55

系列文章目录

通过Qt实现手势识别控制软件操作相关系列技术方案

(一)Qt 将某控件、图案绘制在最前面的方法,通过QGraphicsScene模块实现
(二)Qt QGraphicsScene模块实现圆点绘制在所有窗体的最前方,实现圆点的“彩色拖尾”效果以及“选中方框”效果
(三)Qt 动态手势识别“握拳”
(四)Qt 动态手势识别“手掌随动”+“握拳选择”
(五)Qt 动态手势识别“左右滑动”以及实现翻页效果

文章目录

  • 系列文章目录
  • 1、前言
    • 1.1 目标
  • 2、效果
  • 2、代码实现
    • 2.1 动态手势识别“左右滑动”
    • 2.2 屏幕滑动效果的实现
  • 总结


1、前言

  本系列博客为Qt实现动态手势识别以及实现一些特定效果的工程性记录博客。

1.1 目标

  本篇博客主要记录了动态手势识别实现“左右滑动翻页”的效果的过程。


2、效果

  为了实现对“左右滑动手势”现象的监测,首先设计好UI相关内容,即在Widget背景内实现“变色”的效果,且每当监测到“右移”或是“左移”的动作时,背景内的数字产生变化,每次“右移”发生时,背景的数字将会+1,每次“左移”发生时,背景的数字将会-1。
  数字右侧的窗口是摄像头的实时画面情况,用于验证效果。

  先看演示效果视频:

动态手势识别_左移页面_视角1

动态手势识别_右移页面_视角1

动态手势识别_右移页面_视角2

  效果演示动态图如下图所示:
在这里插入图片描述

图1 “右移”效果gif图

在这里插入图片描述

图2 “左移”效果gif图

2、代码实现

2.1 动态手势识别“左右滑动”

  判断动态手势的“左右滑动”,与本系列里第(三)篇文章里所说的“检测握拳动作”类似,均为实现判断某一特定系列内各帧静态手势的具体类别、相对位置、运动速度等具体参数内容。
  能判断手势是否存在“左右滑动”现象的手法很多,这里只介绍一种简单的方法步骤:
  (1)判定动作初始帧的位置,如果想右移,那么初始帧的位置必然位于监测画面的左半边,如果想左移,那么初始帧的位置必然位于监测画面的右半边(当然了,这里没什么必然,看个人对动态手势的具体定义吧);
  (2)检测该动作序列中,后一帧对前一帧在横坐标方向上的偏移量,若是右移,那么偏移量均应该为正值,若为左移,偏移量均应该为负值;
  (3)该序列每帧数据的纵坐标方向上的偏差应该小于某一特定的阈值,用于判断该动作是水平方向上的运动;
  (4)手势的速度问题,在上述第(2)点的偏移量,需要检测每个偏移量的数值大小,其绝对值应该大于某一特定的数值(这个自行确定);
  (5)最后一帧的位置问题,判断最后一帧的具体位置是否出现在其应该出现的位置,对于左移而言,其最后一帧的位置应该在监测画面的右半边。
  下面是识别“左右滑动”的算法的C++/Qt代码实现。

QString HandPostureDetect::dynamic_gesture_recognize_leftSlide(const QQueue<QPointF>* historyPoints)
{
    int countLeftMove = 0; 
    int countTotalPoints = historyPoints->size(); 

    const QPointF& startPoint = (*historyPoints).front();
    const QPointF& endPoint = (*historyPoints).back();

    double distance = qSqrt(qPow(endPoint.x() - startPoint.x(), 2) + qPow(endPoint.y() - startPoint.y(), 2));

    if (distance < 0.3 || startPoint.x() < 0.5)
    {
        pre_left_slide_condition = 0;
        return ""; 
    }

    for (int i = 1; i < countTotalPoints; ++i)
    {
        const QPointF& currentPoint = (*historyPoints)[i];
        const QPointF& previousPoint = (*historyPoints)[i - 1];

        double deltaX = currentPoint.x() - previousPoint.x();
        double deltaY = currentPoint.y() - previousPoint.y();

        if (deltaX < 0 && qAbs(deltaY) < 0.1) 
        {
            countLeftMove++;
        }
    }

    double ratioLeftMove = static_cast<double>(countLeftMove) / countTotalPoints;
    if (ratioLeftMove >= 0.3) 
    {
        if (pre_left_slide_condition == 0)
        {
            qDebug() << "Left Slide_" << left_slide_count;
            left_slide_count++;
            emit send_result(3);
        }
        pre_left_slide_condition = 1;
        return "Left Slide";
    }
    else
    {
        pre_left_slide_condition = 0;
        return "";
    }
}

2.2 屏幕滑动效果的实现

  通过QStackWidget模块实现容纳多个不同的QWidget对象,可进行按索引选择所展现的具体页面。
  这里“左右切换屏幕”的效果用Qt的动画模块QPropertyAnimation进行的实现。
  当每次有动态手势被检测到的时候,同时调用Interface_Switching_Animation函数,该函数包含两个参数,第一个参数int m_currentIndex用来表示QStackWidget的索引数,第二个参数int left_right_type用来表示是“左移”还是“右移”。

void Widget::Interface_Switching_Animation(int m_currentIndex, int left_right_type)
void Widget::Interface_Switching_Animation(int m_currentIndex, int left_right_type)
{
    int flag = 0;

    QLabel *m_label = new QLabel(ui->stackedWidget);
    m_label->resize(QSize(ui->stackedWidget->width(),ui->stackedWidget->height()));
    m_label->setPixmap(ui->stackedWidget->grab());
    m_label->setAttribute(Qt::WA_DeleteOnClose);
    m_label->show();

    QPropertyAnimation *animation1 = new QPropertyAnimation(m_label, "geometry");
    animation1->setDuration(1000);

    if(left_right_type == 1)
    {
        //向左拉出前一页
        animation1->setStartValue(QRect(0,0,ui->stackedWidget->width(),ui->stackedWidget->height()));
        animation1->setEndValue(QRect(ui->stackedWidget->width()*2,0,ui->stackedWidget->width(),ui->stackedWidget->height()));
        flag = 0;
    }

    else if(left_right_type == 0)
    {
        //向右拉出前一页
        animation1->setStartValue(QRect(0,0,ui->stackedWidget->width(),ui->stackedWidget->height()));
        animation1->setEndValue(QRect(-ui->stackedWidget->width()*2,0,ui->stackedWidget->width(),ui->stackedWidget->height()));
        flag = 1;
    }


    animation1->setEasingCurve(QEasingCurve::InCubic);

    QParallelAnimationGroup *group = new QParallelAnimationGroup;
    group->addAnimation(animation1);
    group->start(QAbstractAnimation::DeleteWhenStopped);

    ui->stackedWidget->setCurrentIndex(m_currentIndex);
    m_label->raise();
    connect(group, &QParallelAnimationGroup::finished, this, [=](){m_label->close();}); //关闭动画完成后关闭label

    if(flag == 0)
    {
        count_times++;
    }
    else if (flag == 1)
    {
        count_times--;
    }

    QString text = QString::number(count_times);
    QString styleSheet = "background-color: #";
    styleSheet += QString::number(qrand() % 256, 16).rightJustified(2, '0'); // 随机生成颜色
    styleSheet += QString::number(qrand() % 256, 16).rightJustified(2, '0');
    styleSheet += QString::number(qrand() % 256, 16).rightJustified(2, '0');

    QWidget* currentwidget = ui->stackedWidget->currentWidget();
    currentwidget->setStyleSheet(styleSheet);

    QLabel *label = new QLabel(currentwidget);
    label->setFont(QFont("Arial", 360));
    label->setText(text);
    label->setAlignment(Qt::AlignCenter);
    label->setGeometry(currentwidget->rect());
//        label->setStyleSheet("color: white;");
    label->show();
}

总结

  本系列文章,通过动、静态手势识别技术方式操控Qt界面软件实现相关操作功能:
(一)Qt 将某控件、图案绘制在最前面的方法,通过QGraphicsScene模块实现
(二)Qt QGraphicsScene模块实现圆点绘制在所有窗体的最前方,实现圆点的“彩色拖尾”效果以及“选中方框”效果
(三)Qt 动态手势识别“握拳”
(四)Qt 动态手势识别“手掌随动”+“握拳选择”
(五)Qt 动态手势识别“左右滑动”以及实现翻页效果

  本项目所有代码的获取,请私信与本人联系。

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

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

相关文章

Spring Boot 中的 SockJS

Spring Boot 中的 SockJS 在 Spring Boot 中&#xff0c;SockJS 是一个用于实现 WebSocket 的兼容性解决方案。本文将介绍 SockJS 的原理、使用方法和示例代码。 什么是 SockJS SockJS 是一种浏览器与服务器之间的通信协议&#xff0c;它可以在浏览器和服务器之间建立一个基于…

python--tornado服务

一、前言 Tornado是一个基于非阻塞I/O的Web框架&#xff0c;具有可以处理大量并发连接&#xff0c;适用于高并发的场景的高性能&#xff0c;轻量级和异步支持的优点。 本篇主要展示了使用 tornado http post 和 get 服务 二、代码 tornado http post 和 get 服务 # -*- codin…

视频拼接融合产品的产品与架构设计(一)

1视频拼接产品概述 将多达8个视频拼接在一起&#xff0c;拼成上帝视角的大图&#xff0c;并且可以共享最终生成的画面。 1.1 三维方案 三维方案是我在晚上思考的时候无意想到&#xff0c;这种方案应该是最接近事实的方案&#xff0c;多个画面应该是在三个维度&#xff0c;x&…

智慧产业园区管理系统主要包含哪些

智能设备管理 本文介绍的是智慧产业园区管理系统中的智能设备管理。智能设备管理是智慧产业园区管理系统中的重要组成部分&#xff0c;它可以为企业提供高效、智能化的设备管理服务。通过智能设备管理系统&#xff0c;企业可以对设备进行实时监控和在线运维&#xff0c;及时发…

JS知识点汇总(五)--执行上下文

1. JavaScript中执行上下文和执行栈是什么&#xff1f; 1、执行上下文 执行上下文是一种对Javascript代码执行环境的抽象概念&#xff0c;也就是说只要有Javascript代码运行&#xff0c;那么它就一定是运行在执行上下文中 执行上下文的类型分为三种&#xff1a; 全局执行上…

2023年智慧水利综合解决方案,数字孪生,领导驾驶舱,水文监测

导读&#xff1a;原文《2023年智慧水利综合解决方案》共56页PPT&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 完整版领取方式 完整版领取方式&#xff1a; 如需获取…

C++数据结构笔记(4)企业链表的实现(Linux内核链表)

1.企业链表本质上是一种Linux内核链表。 2.最本质的区别在于&#xff0c;传统的结点类型中直接同时包含了指针域和数据域&#xff0c;用来实现和其他结点之间的串联&#xff1b;而在企业链表中&#xff0c;结点本身只含有指针域&#xff0c;而数据部分的具体实现则在测试文件中…

细数 List 的10个坑,保证你一定遇到过!

List 在实际的业务开发中&#xff0c;使用的非常频繁&#xff0c;但同样也有不少的坑&#xff0c;一旦使用不当&#xff0c;就可能带来一系列的问题&#xff1b;今天我们主要来说一说这些问题&#xff0c;以及面对这些坑的时候我们要怎么解决。 Arrays.asList转换基本类型数组…

深度学习----第J2周:ResNet50V2算法实现

深度学习----第J2周&#xff1a;ResNet50V2算法实现 文章目录 深度学习----第J2周&#xff1a;ResNet50V2算法实现前言一、ResNetV2与ResNet结构对比二、模型复现2.1 Residual Block2.2 堆叠的 Residual Block2.3 ResNet50V22.4 查看模型结构2.5 tf下全部代码 三、Pytorch复现3…

有哪些数据分析的工具?

来了&#xff0c;9款大数据&数据分析工具推荐&#xff0c;分享点和别人不一样的。 一、基于 Apache Hudi 的 Onehouse https://www.onehouse.ai 近日&#xff0c;开源大数据项目 Apache Hudi 创始人 Vinoth Chandar 发文官宣基于 Hudi 构建的商业公司和产品 Onehouse&…

Linux +Docker镜像打包导出,上传至内网服务器

1. docker容器打包成镜像和压缩 &#xff08;1&#xff09;首先查看镜像所在的容器&#xff0c;获取到容器id docker ps -a&#xff08;2&#xff09;将容器保存成镜像 sudo docker commit -a yjw e007d8b7e1b7 my_projectv2:v2sudo&#xff1a;以管理员权限运行命令&#x…

Unity快速上手系列1之:2D物理弹球

大家好。 以“跳一跳”为开端&#xff0c;微信小游戏从前几年起以迅雷不及掩耳盗铃儿响叮当之势席卷了用户的手机。从创意小游戏&#xff0c;到页游遗风的挂机游戏&#xff0c;一时间百花齐放。 当然&#xff0c;前者说是创意&#xff0c;其实绝大部分也就是直接把其他平台上的…

5.8.2 TCP报文段首部格式

5.8.2 TCP报文段首部格式 TCP报文段首部格式在很大程度上体现了TCP协议的功能 一、数据封装过程 如图 应用层报文传送到传输层之后&#xff0c;加上TCP报文段的首部构成了TCP数据传送单位&#xff0c;我们称之为TCP报文段。在发送时TCP报文段是作为IP数据报的数据部分&#…

linux虚拟内存管理

目录 虚拟内存分布 进程虚拟内存空间的管理 内核如何划分用户态和内核态虚拟内存空间 内核如何管理虚拟内存区域 定义虚拟内存区域的访问权限和行为规范 关联内存映射中的映射关系 虚拟内存区域在内核中是如何被组织的 程序编译后的二进制文件如何映射到虚拟内存空间中 …

探索图像处理的利器——OpenCV

目录 引言&#xff1a; 一、OpenCV简介&#xff1a; 二、OpenCV的特点&#xff1a; 三、OpenCV的应用领域&#xff1a; 四、实际案例&#xff1a; 结论&#xff1a; 引言&#xff1a; 在当今信息化的时代&#xff0c;图像处理已经成为了日常生活中不可或缺的一部分。从社…

4742. 电(acw每日一题)

来源&#xff1a;Google Kickstart2022 Round H Problem C 题目描述 某城市有 N个电力节点&#xff0c;编号 1∼N。 这些电力节点形成的电力网络&#xff0c;可以看作一个 N 个节点 N−1 条边的连通图。 每个电力节点都有一个固定的电容&#xff0c;其中第 i 个节点的电容为…

CSS 备忘录-基础内容

目录 1、CSS的基本结构 2、样式表的来源以及优先级 3、选择器的优先级 4、源码顺序 5、px、em、rem单位 6、视口相对单位 7、使用 calc() 来定义属性值 8、一些无单位的属性 9、自定义属性 10、使用 JavaScript 来动态修改自定义属性 11、overflow 属性 12、子元素…

【单片机】STM32单片机的各个定时器的定时中断程序,标准库,STM32F103

文章目录 定时器1_定时中断定时器2_定时中断定时器3_定时中断定时器4_定时中断定时器5_定时中断 高级定时器和普通定时器的区别&#xff08;https://zhuanlan.zhihu.com/p/557896041&#xff09;&#xff1a; 定时器1_定时中断 TIM1是高级定时器&#xff0c;使用的时钟总线是R…

bochs编译安装

编译命令 ./configure --prefix‘/usr/local/bochs2.7’ --enable-debugger --enable-disasm --enable-iodebug --enable-x86-debugger --with-x --with-x11 make sudo make install 配置文件 bochsrc # configuration file generated by Bochs plugin_ctrl: unmapped1, biosde…

让开源项目从易用到好用 | 亚马逊的开源文化

亚马逊的领导力准则是亚马逊文化的核心&#xff0c;它如同亚马逊的 DNA 融入贯穿每一个重要决策&#xff0c;深深影响着每一位亚麻人、影响着每一位亚马逊的客户、合作伙伴以及每一位亚马逊云科技的构建者。同时&#xff0c;亚马逊的领导力准则对亚马逊与开源的互动方式也产生着…