使用Windows Phone 8.1中的加速度传感器数据在画布上绘制线条

使用Windows Phone 8.1中的加速度传感器数据在画布上绘制线条

问题描述:

我正在基于设备运动在画布上绘画,我想基于移动运动在画布上绘制不同的字符。

I am drawing on canvas based on device movement, I want to draw different characters in canvas based on mobile movement.

当前其工作正常,但是我想找到时差,我想检测暂停,暂停表示当用户不尝试绘制且用​​户不移动手机时,因此Application ca假定现在用户要绘制下一个字符。

Currently its working, but I want to find time difference and i want to detect pause, pause means when user is not trying to draw and user is not moving mobile phone, so that Application ca assume that now user want to draw next character.

如何在加速度计值中查找暂停。有逻辑吗?还告诉我如何使加速度计值平滑,以便用户可以在没有噪声的情况下绘制线条。

How to find pause in accelerometer values. Any logic? Also tell me how i can smooth accelerometer values, so that user can draw lines without noise.

我无法使用加速器部分,但考虑到数据中的噪音,这是使用 加权移动平均值的一种方法a> 。

I cannot help with the accelerator part, but for the noise in the data, here is one approach using Weighted Moving Average.

基础很简单:


  • 查找确定要使用的电流前要平滑多少点

  • 根据长度f.ex计算权重。如果长度为5,则权重= 1 + 2 + 3 + 4 + 5 = 15

  • 从权重的长度开始迭代每个数据点(您可以从1开始并缩短权重) -在下面,我将演示后一种方法)

  • 对于点电流-将5与1/15相乘,对于电流-将4与2/15相乘,依此类推。总和存储为该点的值,重复下一个值点

  • Find out how many points before current you want to use for smoothing
  • Calculate a weight based on length, f.ex. if length is 5 then the weight = 1+2+3+4+5 = 15
  • Iterate each data point starting from length of weight (you can start at 1 and cut the weighting short - below I'll demo the latter approach)
  • For point current - 5 multiply with 1/15, for current - 4 multiply with 2/15 and so forth. The sum is stored as value for this point, repeat for the next value points

下面是一个演示(进入整页查看所有图形)。我用JavaScript编写了它,因此可以在答案中实时显示它。我认为您将它转换成您使用的语言(没有说明)应该没有什么问题。

Below is a demo (enter full page to see all graphics). I wrote it in JavaScript so it could be shown live here in the answer. I think you should have little problem converting it into the language you're using (which is not stated).

移动滑块以增加重量点数。您可以通过多次运行来运行数据,以进一步平滑数据。原始数据是具有噪声抖动的正弦曲线。在许多点上,您可以看到曲线平滑以重复此操作。只需在2次传递中使用9-10点的长度,就可以得到很好的结果,并且几乎没有时间延迟:

Move the slider to increase number of points to weight. You can run the data through several passes to smooth even more. The original data is a sinus curve with noise jitter. With many points you can see the curve smooths to replicate this. Just using 9-10 points length over 2 passes will give a good result with very little time delay:

var ctx = document.querySelector("canvas").getContext("2d"),
    rng = document.querySelector("input"),
    val = document.querySelector("span"),
    data = [], scale = 30;

// generate sinus wave with noise jitters
for(var i = 0; i < ctx.canvas.width; i += 2)
    data.push(Math.sin(i*0.1) * Math.random() + Math.random())

// draw initial smoothed curve (length=1, no smoothing)
drawWMA();

// calculate moving average
function drawWMA() {
    var len = +rng.value,        // get smoothing length (number of previous points)
        dataa = [], datab = [],  // pass A and B arrays
        weight = 0;              // calc weight based on length
  
  val.innerHTML = len;
  
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  ctx.beginPath();
  
  // calc weight
  for(var i = 1; i <= len; i++) weight += i;  // add range together [1, length]
  
  // plot original data at top of canvas
  plot(data, 30);

  // PASS 1: Calc new smoothed array
  dataa = calcWMA(data, len, weight);
  
  // plot smoothed curve
  ctx.fillText("FIRST PASS:", 0, 100);
  plot(dataa, 120);
    
  // PASS 2 (optional)
  datab = calcWMA(dataa, len, weight);
  ctx.fillText("SECOND PASS:", 0, 190);
  plot(datab, 210);
  
  ctx.stroke();  // render plots
}

function calcWMA(data, len, weight) {
  var i, t, datao = [];
  
  // calc new smoothed array 
  for(i = 0; i < data.length; i++) {       // iterate from length to end of data
    var v = 0;                             // calc average value for this position
    for(t = 0; t < len; t++) {             // [1, len]
      if (i-t >= 0)
        v += data[i-t] * ((t+1) / weight); // weight previous values based on -delta
    }
    datao.push(v);                         // store new value
  }
  return datao
}

function plot(data, y) {
  ctx.moveTo(0, y + data[0]*scale);
  for(i = 1; i < data.length; i++) ctx.lineTo(i * 2, y + data[i]*scale);
}

rng.onchange = rng.oninput = drawWMA;

<label>Points to consider: <input type="range" min=1 max=50 value=1></label><span>1</span><br>
<canvas width=600 height=300></canvas>

另一种方法是使用 Savitzky-Golay过滤器产生相似的结果,但不会牺牲末端的任何点(移动平均值将向前或在结束)。

A different approach would be to use a Savitzky–Golay filter which gives a similar result, but not "sacrifice" any points at the end (moving average will push forward or crop at the end).