系列文章目录
通过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
效果演示动态图如下图所示:
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 动态手势识别“左右滑动”以及实现翻页效果
本项目所有代码的获取,请私信与本人联系。