给定触摸点列表,如何检测摇晃手势?

Posted

技术标签:

【中文标题】给定触摸点列表,如何检测摇晃手势?【英文标题】:How to detect a shake gesture, given a list of touch points? 【发布时间】:2017-05-10 06:44:46 【问题描述】:

从一组点中检测摇晃手势,基本上是在寻找三个方向变化:

示例:(我们只需要查看 x 坐标,因为我们只查看水平抖动,而不是垂直抖动)

1,2,3,4,5,6,7,8,[9],8,7,[6],[7]

在上面的x坐标序列中,我用[]标记了方向的变化。

问题是,在上述情况下,我们甚至会检测到微小的无意抖动 - 例如,如果您要求某人将手指从屏幕底部直线拖动到顶部,他的手可能会移动不经意间左右晃动,我们会认为这是“摇晃”

例子:

1,2,[3],[2],[3]....(无意晃动)

为了避免这种情况,我们需要某种阈值,只有超过这个阈值,我们才会将运动视为震动。例如,方向变化之间的差距应至少为 3 个点,值的差异应至少为 4 个。

所以我们应该有类似的东西:

1,2,3,4,5,6,7,8,[9],8,7,6,[5],6,7,8,[9]..... 检测到抖动

1,2,3,4,5,6,7,8,[9],8,7,6,6,7,8,9..... 忽略抖动

1,2,3,2,1....忽略抖动...

这似乎很难实现,因为可能必须跟踪三个索引。我没有自己实现这个,而是想知道这是否是一个已知的算法以及我可以查找的解决方案?

【问题讨论】:

小技巧:求序列的一阶和二阶导数。 @HumamHelfawi 我不明白。在这种情况下,y 坐标无关紧要,因为我们只关注 x 的变化。那么在只有 x 坐标的序列中,你如何找到导数? 添加为答案 【参考方案1】:

根据导数描述函数运动变化的事实,您可以使用导数来轻松解决问题。

让我们举第一个例子:

1, 2, 3, 4, 5, 6, 7, 8, [9], 8, 7, [6], [7] 

通过求这个序列的导数:

1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1
+  +  +  +  +  +  +  +   -   -   -  +

现在,很容易知道震动发生在哪里。

另一个例子:

 1, 12, 15, 8, 3, 1, 0, 5, 17, 30

一阶导数:

11, 3, -7, -5, -2, -1, 5, 12, 13
 +  +   -   -   -   -  +   +  +

简单的实现(未经测试、未经优化):

template <typename valueType> // http://***.com/a/67020/4523099
bool same_sign(typename valueType x, typename valueType y)
     return (x >= 0) ^ (y < 0);


template <typename T>
std::vector<T> get_derivative(std::vector<T> vec_x)
    for(size_t i=0;i<vec_x.size()-1;++i)
         vec_x[i]= vec_x[i+1]-vec_x[i];
    
    vec_x.pop_back();
    return vec_x;


int main()
    std::vector<int> x1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 7 ;
    auto first_derivative=get_derivative(x);
    std::vector<size_t> indices_of_shakes;
    for(size_t i=0;i<first_derivative.size()-1;++i)
        if(!same_sign(first_derivative[i],first_derivative[i+1]))
            indices_of_shakes.emplace_back(i);
        

     

【讨论】:

你能解释一下为什么这应该有效吗?我知道你在做什么,但想知道你能否解释一下这个理论。 “使用导数进行边缘检测”、“sobel”、“拉普拉斯算子”中的任何术语都会为您提供大量资源。如果您仍然不确定,您可以询问具体问题。 此外,虽然在示例中我使用了连续整数,但实际上触摸屏仅每 1/60 秒读取一次输入,因此 xCoordinates 可能根本不会靠近。例如,您可以有 3,4,54,13,... 在这种情况下,您会得到 1,50,-41 的一阶导数,然后是 49,91...的二阶导数... 序列上升时导数为正,下降时为负。确切的值并不重要,除了阈值。 @KaizerSozay 你是对的,我走得更远一点,这是错误的。一阶导数就足够了,我正在编辑我的答案

以上是关于给定触摸点列表,如何检测摇晃手势?的主要内容,如果未能解决你的问题,请参考以下文章

iOS开发系列--触摸事件手势识别摇晃事件耳机线控

iOS开发系列--触摸事件手势识别摇晃事件耳机线控

iOS开发系列--触摸事件手势识别摇晃事件耳机线控

如何检测用户是不是在 c# 中摇晃(检测摇晃),

如何在 Cocos2d CCLayer 中添加摇动手势?

如何防止特定视图响应摇晃手势?