2012-01-30 36 views
7

如果我有例如20分,我如何檢查這些點是否能彌補一個圈?它不一定是一個完美的圓圈。是否有多個點組成一個圓圈?

例如,如果我每隔200毫秒存儲一次鼠標的座標(當用戶移動鼠標時),我想查看用戶是否做出圓圈手勢。我不希望用戶做出完美的圈子。

+0

請問您能更具體地說明您正在努力完成什麼? – Alexandros 2012-01-30 12:28:55

+0

什麼是不完美的圈子? – 2012-01-30 12:29:33

+0

現在呢? – Afra 2012-01-30 12:34:34

回答

9

我做了以下內容:

  • 計算best fit circle through the points
  • 計算剩餘的每一個點(從中心到該點減最佳擬合圓半徑的連接距離)
  • 接受的結果,如果殘差足夠大的比例分別爲低於定義爲最佳擬合半徑的一小部分的某個值。這些參數將是用戶可定義的驗收標準。
+0

這可能是最正確的方法,但它似乎是在代碼中實現它的承諾。根據點數的不同,它可能仍然足夠快速地進行實時手勢識別。 – 2012-01-30 17:26:38

+1

最好使用L_1擬合,因爲這對單個異常值不太敏感。另一種可能性是L_∞(最小環空)擬合,其中測試可以基於環寬度與平均半徑的比率。這裏有一個很好的[圓形擬合算法]的調查(http://valis.cs.uiuc.edu/~sariel/papers/05/l1_fitting/l1_fit_slides.pdf),帶有代碼和其他資源的鏈接。網絡搜索_L1圈擬合_爲L_1和L_∞算法提供了大量資源。 – 2012-01-30 20:36:47

+0

@Ted,非常感謝您的鏈接,非常有用。我過去曾經遇到過單一的異常問題。 – 2012-01-31 07:32:44

3

更新:從@LastCoder的建議刪除太接近前一個點的連續點(我設置的閾值在10的距離;也許它可以增加),容差水平設置爲0.25(即差異距離中心點的平均距離爲25%是可以接受的),我所做的應用程序在超過一半的情況下識別我的「圈子」,並且不再受廣場欺騙。畢竟,這可能不是一個壞主意。


我會找到centroid對於給定的點的集合,並檢查是否從重心到各點的距離或多或少是相同的(假設你希望全圓的近似,不只是一個弧)。

它在實踐中適用於檢測用鼠標完成圓形手勢的問題;看到an example in C#(VS2010中,只有主要形式,應用程序的其餘部分是自動的樣板;在忽略的ideone錯誤)和在這裏的截圖:

Certainly I am bad at drawing circles with laptop's touch-stick

+0

+1。請記住,徑向偏差必須與半徑成正比,否則最終檢測到一個不移動的圓圈。該算法可以作爲在線算法有效地實施,其中當新樣本到達時重新計算圓形度分數。 – cyborg 2012-01-30 14:25:57

+3

如果點不是均勻地分佈在整個圓周上,則將該圓心拉離圓心。 – 2012-01-30 14:29:57

+1

@RafałDowgird及其他人:我同意,但對於鼠標手勢檢測問題,人們可以期望點分配非常均勻;並通過實驗進行了確認(請參閱更新後的答案):) – 2012-01-30 16:32:37

2

這裏有一個簡單的方法,我把一個工作實現放在一起。

http://jsfiddle.net/kBsdW/29/

  • 循環遍歷點
  • 查找與第一
  • 記錄的距離
  • 的最大距離第二點一旦你把所有的最大距離取它們的平均值,計算容錯度
  • 檢查所有記錄的距離與您的容錯度

這對於鼠標或觸摸傳感器等用戶輸入非常適用。該算法是O(n^2),並使用delta最大距離而不是找到質心和檢查半徑距離。

它似乎比最佳擬合圓方法更有效率,它必須計算每個3點的組合。

這個hack_algo利用了一個事實,即圓上兩點之間的最大距離是圓的直徑。

function isCircle(points, error) { 
    if(points.length <= 2) return true; 
    var weights = []; 
    var maxDistance = 0; 
    var sumDistance = 0; 
    var avgDistance = 0; 
    var errorConstraint = 0; 
    for(var i=0; i<points.length; i++) { 
     var distance = 0; 
     for(var j=0; j<points.length; j++) { 
      var d = getDistance(points[i], points[j]); 
      if(d > distance) { 
       distance = d; 
      } 
     } 
     if(distance > 0) { 
      if(distance > maxDistance) maxDistance = distance; 
      sumDistance += distance; 
      weights.push(distance); 
     } 
    } 
    avgDistance = sumDistance/weights.length; 
    errorConstraint = error * avgDistance; 
    for(var i=0; i<weights.length; i++) { 
     if(Math.abs(avgDistance - weights[i]) > errorConstraint) { 
      return false; 
     } 
    } 
    return true; 
} 
+0

+1。但'Math.abs(avgDistance - 權重[i])> errorConstraint'太簡單了。想想那些從圈子中間開始的人。您需要大部分驗證這一點。所以2個參數。 – UmNyobe 2012-01-30 17:41:58

+0

@UmNyobe - 這就是爲什麼它在這些情況下返回false,並且只有在「全部」長度在容差範圍內時才返回true。你也可以對權重數組做一些額外的處理並刪除異常值,但是我沒有在簡單的例子jsfiddle中這樣做。 – 2012-01-30 18:35:54

+0

我對你的實現起了一點作用。即使公差水平設置爲0.15,它也可以將一個正方形甚至三角形(如果接近正方形)視爲一個圓圈:) – 2012-01-30 18:41:53