2012-01-30 29 views
7

Jeśli mam np. 20 punktów, jak mogę sprawdzić, czy te punkty składają się na okrąg? To nie musi być idealne koło.Czy wiele punktów składa się na okrąg?

Na przykład, jeśli przechowuję współrzędne mojej myszy co 200 ms (gdy użytkownik przesuwa mysz), chcę sprawdzić, czy użytkownik wykonuje gest okrężny. I nie mogę oczekiwać, że użytkownik zrobi idealne koło.

+0

Czy możesz podać dokładniejsze informacje na temat tego, co próbujesz osiągnąć? – Alexandros

+0

Co to jest niedoskonały krąg? –

+0

Co powiesz teraz? – Afra

Odpowiedz

9

zrobiłbym następujące;

  • obliczyć best fit circle through the points
  • obliczyć pozostały na każdy punkt (odległość przyłączyć od środka do punktu minus najlepiej promienia okręgu Fit)
  • zaakceptować wyników, jeśli dostatecznie duża część reszt były poniżej pewnej wartości zdefiniowanej jako niewielki procent najlepiej dopasowanego promienia. Te parametry będą definiowanymi przez użytkownika kryteriami akceptacji.
+0

Jest to prawdopodobnie najodpowiedniejsza metoda, ale wydaje się, że byłoby to przedsięwzięcie do wdrożenia w kodzie. Prawdopodobnie będzie on działał wystarczająco szybko, aby w czasie rzeczywistym rozpoznawać gesty w zależności od liczby punktów. –

+1

Najlepiej byłoby użyć dopasowania L_1, ponieważ jest ono mniej wrażliwe na pojedyncze wartości odstające. Inną możliwością jest dopasowanie L_∞ (minimalny pierścień), gdzie test może opierać się na stosunku szerokości pierścienia do średniego promienia. Jest fajna ankieta dotycząca [algorytmów dopasowywania okręgów] (http://valis.cs.uiuc.edu/~sariel/papers/05/l1_fitting/l1_fit_slides.pdf), z linkami do kodu i innych zasobów. Wyszukiwanie w sieci dla _L1 circle fitting_ powoduje wyświetlenie dużej ilości zasobów dla algorytmów L_1 i L_∞. –

+0

@Ted, wielkie dzięki za link, bardzo przydatne. W przeszłości miałem problem z jednym odstającym. –

3

Aktualizacja: z sugestią @LastCoder, aby upuścić kolejne punkty zbyt blisko poprzedniej (ustawiam próg w odległości 10, być może można go zwiększyć) i poziom tolerancji ustawiony na 0.25 (czyli rozbieżność 25% od średniej odległości do punktu środkowego jest dopuszczalne), aplikacja, którą utworzyłem, rozpoznaje moje "okręgi" w ponad połowie przypadków i nie jest już oszukiwana przez kwadraty. Więc może nie jest to zły pomysł.


znajdę centroid dla danego zbioru punktów, i sprawdzić, czy odległość od środka ciężkości do każdego punktu jest mniej więcej taka sama (przy założeniu, że można oczekiwać przybliżenie pełne koło, a nie tylko łuk).

W praktyce sprawdza się w przypadku wykrycia gestu wykonanego za pomocą myszy; zobacz an example in C# (VS2010, tylko główną formą, reszta aplikacji jest automatyczne boilerplate; ignorować błędy w ideone) i zrzut ekranu dla tutaj:

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

+0

+1. Pamiętaj tylko, że odchylenie promieniowe musi być proporcjonalne do promienia, lub kończy się wykrywaniem braku ruchu jako okręgu. Algorytm ten można efektywnie zaimplementować jako algorytm online, w którym wynik kołowości jest ponownie obliczany w miarę nadejścia nowych próbek. – cyborg

+3

Spowoduje to zerwanie, jeśli punkty nie będą równomiernie rozmieszczone wokół całego okręgu, odciągając środek ciężkości od rzeczywistego środka okręgu. –

+1

@ RafałDowgird i inni: Zgadzam się, ale w przypadku problemu z wykrywaniem gestów myszy można oczekiwać dość równomiernego rozłożenia punktów; i jest to potwierdzone eksperymentem (patrz zaktualizowana odpowiedź) :) –

2

Oto prosta metoda, z działającą implementacją, którą zrzuciłem razem.

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

  • Loop przez punkty
  • Znajdź drugi punkt z maksymalną odległością od pierwszego
  • Record od odległości
  • Kiedy masz wszystkie Maxa odległościach uśrednić je i obliczyć tolerancja błędu:
  • Sprawdź wszystkie zarejestrowane dystanse na podstawie tolerancji błędów

Działa to doskonale do wprowadzania danych przez użytkownika, jak z myszy lub czujnika dotykowego. Algorytm ten ma postać O (n^2) i wykorzystuje deltowy dystans maksymalny w przeciwieństwie do znajdowania środka masy i sprawdzania odległości promieni.

"Wydaje się" być bardziej wydajnym niż metoda najlepszego dopasowania, która musi obliczyć przy każdej kombinacji 3 punktów.

Ten hack ~ algo wykorzystuje fakt, że maksymalna odległość między dwoma punktami na okręgu to średnica okręgu.

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. ale 'Math.abs (avgDistance - weight [i])> errorConstraint' jest zbyt uproszczone. Pomyśl o kimś, kto zaczyna od środka kręgu. Potrzebujesz większości punktów, które to sprawdzają. Tak więc 2 parametry. – UmNyobe

+0

@UmNyobe - dlatego zwraca wartość false w tych przypadkach i zwraca wartość true tylko wtedy, gdy "wszystkie" długości są w granicach tolerancji. Możesz również wykonać dodatkowe przetwarzanie do tablicy wag i usunąć wartości odstające, ale nie zrobiłem tego w prostym przykładzie jsfiddle. –

+0

Grałem trochę z twoją implementacją. Nawet z poziomem tolerancji ustawionym na 0,15, może traktować kwadrat, a nawet trójkąt (jeśli zbliża się do równoboczności) jako koło :) –