그려진 선의 진 직도를 어떻게 정량화 할 수 있습니까?


37

플레이어가 안드로이드 장치의 화면에서 A 지점 (x1, y1)에서 다른 지점 B (x2, y2)까지 선을 그려야하는 게임을 만들고 있습니다.

그 그림이 직선에 얼마나 잘 맞는지 알고 싶습니다. 예를 들어 90 %의 결과는 그림이 선에 거의 완벽하게 맞는다는 것을 의미합니다. 플레이어가 A에서 B로 곡선을 그리면 점수가 낮아집니다.

종말점은 미리 알려져 있지 않습니다. 어떻게해야합니까?


1
두 가지 엔드 포인트가 무엇인지 미리 알고 있습니까? 또는 사용자가 화면을 더 이상 터치하지 않는 순간에 결정됩니까?
Vaillancourt

내 설명이 명확하지 않으면 죄송합니다. 글쎄, 시작점 A (x, y)는 첫 번째 터치이고 끝점 B (x, y)는 우리가 말한 것처럼 터치 스크린에서 손을 when 때입니다.
user3637362

플레이어가 그린 글자일치 시키는 것과 관련된 질문이 있습니다.
Anko

3
앞으로 소스 코드 이미지를 게시하지 마십시오.
Josh

1
@ user3637362 시작 j=1하기 때문에 귀하 touchList[j]와 비교할 수 touchList[j-1]있지만 언제 touch.phase == TouchPhase.Began또는 touch.phase == TouchPhase.Ended위치가 추가 touchList되지 않고 이후에 포함되지 않는지 이해 sumLength합니다. 이 버그는 모든 경우에 존재하지만 선에 세그먼트가 거의 없을 때 더 분명합니다.
Kelly Thomas

답변:


52

완전 직선은 또한 전체 길이가 가능한 가장 짧은 직선입니다 sqrt((x1-x2)² + (y1-y2)²). 더 깔끔한 회선은 이상적인 연결이 아니므로 필연적으로 더 길어집니다.

사용자가 그린 경로의 모든 개별 점을 취하고 그 사이의 거리를 합하면 총 길이를 이상적인 길이와 비교할 수 있습니다. 전체 길이를 이상적인 길이로 나눈 값이 작을수록 선이 더 좋습니다.

시각화는 다음과 같습니다. 검은 점이 제스처의 끝 점이고 파란색 점이 제스처 중 측정 한 점이면 녹색 선의 길이를 계산하여 합산하여 빨간색 선의 길이로 나눕니다.

여기에 이미지 설명을 입력하십시오

점수 또는 sinuosity 지수 가 1이면 완벽 할 것이고, 높을수록 완벽하지 않을 수 있습니다. 1보다 작은 것은 버그입니다. 점수를 백분율로 표시하려면 100 %를 해당 숫자로 나눕니다.


34
길이가 같은 폴리 라인이 똑바로 '똑 바르지 않다'는 점에서이 방법 에는 작은 문제가 있습니다. 직선에 대해 낮은 편차 (하지만 여러 번)로 흔들리는 선은 동일한 길이의 선보다 '직선'이어서 단일 점으로 이탈 한 후 되돌아옵니다.
Dancrumb

나는 @ Dancrumbs 주석을 충분히 +1 할 수 없다-그것은 사용자가 직선을 그리는 것처럼 약간 흔들 리므로 일반적인 사용 사례처럼 느껴지는 것처럼이 방법의 주요 제한 사항입니다.
T. Kiley

@Dancrumb는 선과의 평균 거리를 고려하거나, 어떤 점이 선과 "최대 거리"를 고려합니다. 그런 다음 편차 진폭이 더 작고 예상 경로에서 멀리 떨어진 선에서 멀어지면서 더 흔들리는 선에 알고리즘의 가중치를 지정할 수 있습니다.
Superdoggy

2
@ Dancrumb 그것은 OP의 유스 케이스에 이익을 줄 수있는 것처럼 들립니다. 물론 손으로 그린 ​​선은 약간의 편차가 있습니다. 이 접근 방식은 실제로 이러한 예상되는 차이의 영향을 완화시키는 데 효과적 일 수 있습니다.

2
@ user3637362 코드에 버그가 있습니다. 가능한 설명은 시작점과 첫 번째 지점 또는 끝점과 마지막 지점 사이의 거리를 고려하지 않았지만 코드를 보지 않으면 실수가 무엇인지 알 수 없습니다.
Philipp

31

이것은 이것을 구현하는 가장 좋은 방법은 아니지만 Dancrumb이 언급 한 경우 거리 방법보다 RMSD (루트 평균 제곱 편차)가 더 좋을 것이라고 제안합니다 (아래 두 줄 참조).

RMSD = sqrt(mean(deviation^2))

노트 :

  • 절대 편차 (정수 유사)의 합은 음수로 양수 오류를 평균화하지 않으므로 더 좋을 수 있습니다. ( =sum(abs(deviation)))
  • 수직선을 떨어 뜨리는 것보다 짧은 거리를 만드는 방법이 있다면 아마도 직선까지의 최단 거리를 검색해야 할 것입니다.

그림

(내 그림의 저품질을 실례합니다)

보시다시피

  1. 귀하의 선에 직교 벡터를 찾으십시오 ( 내적은 0입니다 ).
    선이 (1, 3) 원하는 방향 을 가리키면 (3, -1)(원점을 각각 통과 )
  2. h이상적인 선에서 사용자까지 의 거리 를 벡터와 평행하게 측정하십시오 .
  3. RMSD 또는 절대 차이의 합을 계산 하십시오.

Joel Bosveld의 답변은 흥미로운 사례를 나타냅니다. 시작과 끝에 모서리가 거의 완벽하게 직선입니다. 사용자가 선을 자유롭게 그리면 실제로 문제가됩니다. 그럼에도 불구하고 나는이 방법이 그 시나리오를 다룰 수 있다고 생각합니다. 실제로 RMSD 또는 절대 적분 과 함께 최소값 으로 적합을 수행 할 수 있습니다. 시작 값은 시작 및 끝 지점이 될 수 있습니다. 길이가 중요하지 않기 때문에 최적화가 포인트를 이동시켜 이상적인 선이 더 닿거나 짧아지는 경우 (높이는 해당 니베로 계산되어야 함) 또한 중요하지 않습니다.
gr4nt3d

1
또 다른 경우는 다루지 않는 것 같습니다. 모든 측정 된 점이 x 축에 있지만 선이 방향을 여러 번 뒤집습니다. 0의 오류를 반환합니다.
dave mankoff

23

기존 답변은 종점이 임의적이지 않다는 점을 고려하지 않습니다. 따라서 곡선의 진 직도를 측정 할 때는 끝점을 사용하는 것이 적합하지 않습니다 (예 : 예상 길이, 각도, 위치 계산). 간단한 예는 양쪽 끝이 꼬인 직선입니다. 커브와 끝점 사이의 직선으로부터의 거리를 사용하여 측정하는 경우, 우리가 그린 직선이 끝점 사이의 직선에서 오프셋되므로 상당히 커집니다.

커브가 얼마나 직선인지 어떻게 알 수 있습니까? 곡선이 충분히 매끄럽다 고 가정하면 평균적으로 곡선에 접하는 양이 얼마나 변하는 지 알고 싶습니다. 선의 경우이 값은 0입니다 (접선이 일정하므로).

시간 t에서의 위치를 ​​(x (t), y (t))로한다면, 탄젠트는 (Dx (t), Dy (t))이며, 여기서 Dx (t)는 시간 t에서의 x의 도함수입니다 (이 사이트에는 TeX 지원이없는 것 같습니다). 곡선이 호 길이로 매개 변수화되지 않은 경우 || (Dx (t), Dy (t)) ||로 나누어 정규화합니다. 우리는 시간 t에서 커브에 접하는 단위 벡터 (또는 각도)를가집니다. 따라서 각도는 a (t) = (Dx (t), Dy (t)) / || (Dx (t), Dy (t)) ||

그런 다음 곡선을 따라 적분 된 || Da (t) || ^ 2에 관심이 있습니다.

커브가 아닌 이산 데이터 포인트가있을 가능성이 크므로 유한 차이를 사용하여 미분 값을 근사화해야합니다. 따라서 Da (t)가됩니다 (a(t+h)-a(t))/h. 그리고 a (t)가됩니다 ((x(t+h)-x(t))/h,(y(t+h)-y(t))/h)/||((x(t+h)-x(t))/h,(y(t+h)-y(t))/h)||. 그런 다음 h||Da(t)||^2모든 데이터 포인트 를 합산 하고 곡선 길이로 정규화하여 S를 얻습니다 . 아마도 우리는을 사용 h=1하지만 실제로는 임의의 스케일 요소 일뿐입니다.

다시 말하면, S는 라인에 대해 0이되고 라인에서 벗어날수록 커집니다. 필요한 형식으로 변환하려면을 사용하십시오 1/(1+S). 스케일이 다소 임의적이라고 가정하면 S에 양수를 곱하거나 (또는 ​​다른 방식으로 변환, 예를 들어 S 대신 bS ^ c 사용) 특정 곡선이 얼마나 직선인지 조정할 수 있습니다.


2
이것은 직진성에 대한 가장 현명한 정의입니다.
Marcks Thomas

1
이것은 지금까지 가장 현명한 답변이며 다른 사람들은 매우 실망 스러울 것이라고 확신합니다. 불행히도 솔루션이 제시되는 형식은 다른 형식보다 약간 모호하지만 OP가 지속되는 것이 좋습니다.
Dan Sheppard

일반적으로 나는이 답변이 실제로 최고라고 생각합니다. 문제가 나를 귀찮게하지만 라인이 "충분히 부드럽 지 않은"경우 어떻게됩니까? 예를 들어, 90 °의 각도를 가진 완벽하게 직선 인 두 개의 세그먼트가 있다면. 내가 실수 또는 정말 부드러운 선형 선에 비해 결과가 매우 낮습니까? (나는 흔들리는 줄이있는 Dancrumb의 사용자 사례가 비슷한 문제라고 생각합니다.) ... 로컬로 이것이 가장 좋은 방법입니다.
gr4nt3d

3

이것은 그리드 기반 시스템입니다. 선에 대한 자신의 점을 찾아 선의 기울기를 계산하십시오. 이제이 계산을 사용하여 정확한 값에서 약간의 오차 한계가있는 경우 선이 통과 할 유효한 점을 결정하십시오.

시행 착오 테스트의 짧은 양을 통해 일치하는 포인트의 양과 양이 일치하는지 확인하고 테스트와 동일한 결과에 대한 척도를 사용하여 게임을 설정하십시오.

즉, 거의 수평 기울기가있는 짧은 선에는 7 개의 점이있을 수 있습니다. 직선의 일부로 결정된 7 개 중 6 개 이상을 일관되게 일치시킬 수 있다면, 이것이 가장 높은 점수가됩니다. 길이와 정확도에 대한 채점은 채점의 일부 여야합니다.


3

매우 쉽고 직관적 인 측정은 가장 적합한 직선과 실제 곡선 사이의 영역입니다. 이것을 결정하는 것은 매우 간단합니다.

  1. 모든 점에 최소 자승법을 사용하십시오 (Joel Bosveld가 언급 한 최종 문제를 방지합니다).
  2. 곡선의 모든 점에 대해 선까지의 거리를 결정하십시오. 이것은 또한 표준 문제입니다. (선형 대수, 기본 변환)
  3. 모든 거리를 합산하십시오.

위의 대부분의 답변이 이론적으로 설명되어 있기 때문에 텍스트 코딩 (JS, C #) 또는 의사 코드를 요청하면 어떻게 시작할 수 있습니까?
user3637362

1
@ user3637362 : StackOverflow에는 실용적인 답변이 있습니다 : stackoverflow.com/questions/6195335/… stackoverflow.com/questions/849211/…
MSalters

2

아이디어는 사용자가 터치 한 모든 지점을 유지 한 다음 사용자가 화면을 놓을 때 형성된 선까지 각 지점 사이의 거리를 평가하고 합산하는 것입니다.

다음은 의사 코드로 시작하기위한 것입니다.

bool mIsRecording = false;
point[] mTouchedPoints = new point[];

function onTouch
  mIsRecording = true

functon update
  if mIsRecording
    mTouchedPoints.append(currentlyTouchedLocation)

function onRelease
  mIsRecording = false

  cumulativeDistance = 0

  line = makeLine( mTouchedPoints.first, mTouchedPoints.last )

  for each point in mTouchedPoints:
    cumulativeDistance = distanceOfPointToLine(point, line)

  mTouchedPoints = new point[]

무엇이 cumulativeDistance피팅에 대한 아이디어를 줄 수 있습니까? 거리가 0이면 사용자가 항상 전화를 끊지 않았 음을 의미합니다. 이제 컨텍스트에서 어떻게 동작하는지 확인하기 위해 몇 가지 테스트를 수행해야합니다. 그리고 distanceOfPointToLine거리에서 더 먼 거리에 벌점을두기 위해 반환 된 값을 증폭하여 증폭시킬 수 있습니다 .

나는 화합에 익숙하지 않지만 update여기에 있는 코드 는 onDrag기능을 할 수 있습니다.

그리고 마지막으로 등록 된 포인트와 동일한 포인트를 등록하지 못하도록 코드를 어딘가에 추가 할 수 있습니다. 사용자가 움직이지 않을 때 물건을 등록하고 싶지 않습니다.


5
이상적인 선과 모든 측정 지점의 지점 사이의 거리를 합산 할 때 수행 한 측정 수를 고려해야합니다. 점수가 더 나빠질 것임을 의미합니다.
Philipp

@ 필립 네! 나는 너의 행동이 나의 것보다 낫다는 것을 인정해야한다 : P
Vaillancourt

이 접근 방식은 누적 거리가 아닌 평균 거리 를 취함으로써 향상된다고 생각합니다 .
Dancrumb

@ Dancrumb 실제로, 그것은 요구에 달려 있지만, 그렇습니다.
Vaillancourt

2

사용할 수있는 한 가지 방법은 선을 세그먼트로 세분화하고 세그먼트를 나타내는 각 벡터와 첫 번째 점과 마지막 점 사이의 직선을 나타내는 벡터 사이에 벡터 내적을 수행하는 것입니다. 이는 매우 "뾰족한"세그먼트를 쉽게 찾을 수 있다는 이점이 있습니다.

편집하다:

또한 내적 이외에도 세그먼트의 길이를 사용하는 것이 좋습니다. 매우 짧지 만 직교 벡터는 편차가 적은 긴 벡터보다 작게 계산해야합니다.


1

가장 쉽고 빠른 방법은 단순히 사용자가 그린 선의 모든 점을 덮는 선의 두께를 찾는 것입니다.

선이 두꺼울수록 사용자가 선을 그리는 데 더 나빴습니다.


0

어떻게 든 MSalters Answer를 언급하면 ​​여기에 더 구체적인 정보가 있습니다.

최소 제곱 법을 사용하여 포인트에 맞는 선을 만듭니다. 기본적으로 가장 적합한 y = f (x) 함수를 찾고 있습니다. 일단 그것을 얻으면 실제 y 값을 사용하여 차이의 제곱을 합할 수 있습니다.

s = 합계 ((yf (x)) ^ 2)

합계가 작을수록 선이 똑 바르게됩니다.

최고의 근사값을 얻는 방법은 여기에 설명되어 있습니다 : http://math.mit.edu/~gs/linearalgebra/ila0403.pdf

그냥 "직선 맞추기"에서 읽습니다. x 대신 t가 사용되고 y 대신 b가 사용됩니다. C와 D는 근사치로 결정되며 f (x) = C + Dx입니다.

추가 사항 : 분명히, 줄의 길이도 고려해야합니다. 2 포인트로 구성된 모든 라인이 완벽합니다. 나는 정확한 맥락을 알지 못하지만 제곱의 합을 점수로 나눈 값을 등급으로 사용한다고 생각합니다. 또한 최소 길이, 최소 포인트 수의 요구 사항을 추가합니다. (최대 길이의 약 75 %)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.