Если вы знаете соответствие (то есть вы знаете, какие точки одинаковы до и после преобразования) и хотите разрешить масштабирование, то проблема состоит в наборе линейных уравнений. Если у вас есть 2 или более очков, вы можете найти решение наименьших квадратов без особых затруднений.
Для начальных точек (xi, yi) и преобразованных точек (xi ', yi') у вас есть уравнения вида
xi' = a xi + b yi + c
yi' =-b xi + a yi + d
, который вы можете переставить в линейную систему
A x = y
, где
A = | x1 y1 1 0 |
| y1 -x1 0 1 |
| x2 y2 1 0 |
| y2 -x2 0 1 |
| ... |
| xn yn 1 0 |
| yn -xn 0 1 |
x = | a |
| b |
| c |
| d |
y = | x1' |
| y1' |
| x2' |
| y2' |
| ... |
| xn' |
| yn' |
стандартная форма "наименьших квадратов"
A^T A x = A^T y
и имеет решение
x = (A^T A)^-1 A^T y
с A^T
в качестве транспонирования A
и A^-1
в качестве инверсии A
. Обычно вы используете SVD или QR-декомпозицию для вычисления решения, поскольку они должны быть более стабильными и менее вычислительно интенсивными, чем обратные.
Как только вы нашли x
(и, таким образом, четыре элемента преобразования a
, b
, c
и d
), тогда различные элементы преобразования задаются как
scale = sqrt(a*a+b*b)
rotation = atan2(b,a)
translation = (c,d)/scale
Если вы не включите масштабирование, то система будет нелинейной и требует итеративного решения (но не слишком сложного для решения). Если вы не знаете соответствия, тогда проблема существенно сложнее, для небольших преобразований работает что-то вроде итерированная ближайшая точка , для больших преобразований это намного сложнее.
Редактировать: Я забыл включить центр вращения. Вращение theta
вокруг произвольной точки p
является последовательностью
translate(p) rotate(theta) translate(-p)
если вы расширите все это как аффинное преобразование (по сути, то, что мы имеем выше), тогда термины перевода придут к
dx = px - cos(theta)*px + sin(theta)*py
dy = py - sin(theta)*px - cos(theta)*py
мы знаем theta
(rotation
), dx
(c
) и dy
(d
) из приведенных выше уравнений. Приложив немного усилий, мы можем решить для px и py
px = 0.5*(dx - sin(theta)*dy/(1-cos(theta)))
py = 0.5*(dy + sin(theta)*dx/(1-cos(theta)))
Вы заметите, что уравнения не определены, если тета равен нулю, потому что нет центра вращения, когда вращение не выполняется.
Я думаю, что все правильно, но сейчас у меня нет времени перепроверять все.